23 #include "Curve25519.h"
26 #include "utility/LimbUtil.h"
46 #define CURVE25519_ASM_AVR 1
54 #if defined(CURVE25519_STRICT_CLEAN)
55 #define strict_clean(x) clean(x)
57 #define strict_clean(x) do { ; } while (0)
81 limb_t x_1[NUM_LIMBS_256BIT];
82 limb_t x_2[NUM_LIMBS_256BIT];
83 limb_t x_3[NUM_LIMBS_256BIT];
84 limb_t z_2[NUM_LIMBS_256BIT];
85 limb_t z_3[NUM_LIMBS_256BIT];
86 limb_t A[NUM_LIMBS_256BIT];
87 limb_t B[NUM_LIMBS_256BIT];
88 limb_t C[NUM_LIMBS_256BIT];
89 limb_t D[NUM_LIMBS_256BIT];
90 limb_t E[NUM_LIMBS_256BIT];
91 limb_t AA[NUM_LIMBS_256BIT];
92 limb_t BB[NUM_LIMBS_256BIT];
93 limb_t DA[NUM_LIMBS_256BIT];
94 limb_t CB[NUM_LIMBS_256BIT];
106 x_1[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
108 memset(x_1, 0,
sizeof(x_1));
119 retval = (bool)(reduceQuick(x_1) & 0x01);
122 memset(x_2, 0,
sizeof(x_2));
124 memset(z_2, 0,
sizeof(z_2));
125 memcpy(x_3, x_1,
sizeof(x_1));
126 memcpy(z_3, x_2,
sizeof(x_2));
133 for (uint8_t t = 255; t > 0; --t) {
136 select = s[sposn] & mask;
138 cswap(swap, x_2, x_3);
139 cswap(swap, z_2, z_3);
173 cswap(swap, x_2, x_3);
174 cswap(swap, z_2, z_3);
253 f[31] = (f[31] & 0x7F) | 0x40;
264 }
while (isWeakPoint(k));
292 weak = isWeakPoint(k);
293 weak |= ((
eval(k, f, k) ^ 0x01) & 0x01);
294 weak |= isWeakPoint(k);
296 return (
bool)((weak ^ 0x01) & 0x01);
306 uint8_t Curve25519::isWeakPoint(
const uint8_t k[32])
312 static const uint8_t points[5][32] PROGMEM = {
313 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
317 {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
321 {0xE0, 0xEB, 0x7A, 0x7C, 0x3B, 0x41, 0xB8, 0xAE,
322 0x16, 0x56, 0xE3, 0xFA, 0xF1, 0x9F, 0xC4, 0x6A,
323 0xDA, 0x09, 0x8D, 0xEB, 0x9C, 0x32, 0xB1, 0xFD,
324 0x86, 0x62, 0x05, 0x16, 0x5F, 0x49, 0xB8, 0x00},
325 {0x5F, 0x9C, 0x95, 0xBC, 0xA3, 0x50, 0x8C, 0x24,
326 0xB1, 0xD0, 0xB1, 0x55, 0x9C, 0x83, 0xEF, 0x5B,
327 0x04, 0x44, 0x5C, 0xC4, 0x58, 0x1C, 0x8E, 0x86,
328 0xD8, 0x22, 0x4E, 0xDD, 0xD0, 0x9F, 0x11, 0x57},
329 {0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
330 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
331 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
332 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}
341 for (uint8_t posn = 0; posn < 5; ++posn) {
342 const uint8_t *point = points[posn];
343 uint8_t check = (pgm_read_byte(point + 31) ^ k[31]) & 0x7F;
344 for (uint8_t index = 31; index > 0; --index)
345 check |= (pgm_read_byte(point + index - 1) ^ k[index - 1]);
346 result |= (uint8_t)((((uint16_t)0x0100) - check) >> 8);
365 void Curve25519::reduce(limb_t *result, limb_t *x, uint8_t size)
408 #if !defined(CURVE25519_ASM_AVR)
415 carry = ((dlimb_t)(x[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1))) * 19U;
416 x[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
417 for (posn = 0; posn < size; ++posn) {
418 carry += ((dlimb_t)(x[posn + NUM_LIMBS_256BIT])) * 38U;
420 x[posn] = (limb_t)carry;
423 if (size < NUM_LIMBS_256BIT) {
426 for (posn = size; posn < NUM_LIMBS_256BIT; ++posn) {
428 x[posn] = (limb_t)carry;
438 carry += ((dlimb_t)(x[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1))) * 19U;
439 x[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
440 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
442 x[posn] = (limb_t)carry;
452 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
454 x[posn + NUM_LIMBS_256BIT] = (limb_t)carry;
464 limb_t mask = (limb_t)(((slimb_t)(x[NUM_LIMBS_512BIT - 1])) >> (LIMB_BITS - 1));
465 limb_t nmask = ~mask;
466 x[NUM_LIMBS_512BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
467 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
468 result[posn] = (x[posn] & nmask) | (x[posn + NUM_LIMBS_256BIT] & mask);
471 __asm__ __volatile__ (
480 "mov r24,__zero_reg__\n"
481 "sbc r24,__zero_reg__\n"
486 "mov r22,__zero_reg__\n"
506 "add __tmp_reg__,r24\n"
507 "st Z+,__tmp_reg__\n"
511 "adc __tmp_reg__,r22\n"
512 "st Z+,__tmp_reg__\n"
554 "mov __zero_reg__,r22\n"
569 "adc r17,__zero_reg__\n"
570 "adc r18,__zero_reg__\n"
571 "adc r19,__zero_reg__\n"
572 "mov r25,__zero_reg__\n"
588 "mov r25,__zero_reg__\n"
589 "sbc r25,__zero_reg__\n"
625 : :
"z"(x),
"r"((uint8_t)(size *
sizeof(limb_t))),
"x"(result)
626 :
"r16",
"r17",
"r18",
"r19",
"r20",
"r21",
"r22",
"r23",
645 limb_t Curve25519::reduceQuick(limb_t *x)
647 #if !defined(CURVE25519_ASM_AVR)
648 limb_t temp[NUM_LIMBS_256BIT];
660 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
662 *tt++ = (limb_t)carry;
671 limb_t mask = (limb_t)(((slimb_t)(temp[NUM_LIMBS_256BIT - 1])) >> (LIMB_BITS - 1));
672 limb_t nmask = ~mask;
673 temp[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
676 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
677 *xx = ((*xx) & nmask) | ((*tt++) & mask);
686 #else // CURVE25519_ASM_AVR
687 limb_t temp[NUM_LIMBS_256BIT];
689 __asm__ __volatile__ (
700 "adc r17,__zero_reg__\n"
701 "adc r18,__zero_reg__\n"
702 "adc r19,__zero_reg__\n"
703 "mov r25,__zero_reg__\n"
719 "mov r25,__zero_reg__\n"
720 "sbc r25,__zero_reg__\n"
758 :
"r16",
"r17",
"r18",
"r19",
"r20",
"r21",
"r22",
"r23",
763 #endif // CURVE25519_ASM_AVR
778 void Curve25519::mulNoReduce(limb_t *result,
const limb_t *x,
const limb_t *y)
780 #if !defined(CURVE25519_ASM_AVR)
792 for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
793 carry += ((dlimb_t)(*yy++)) * word;
794 *rr++ = (limb_t)carry;
800 for (i = 1; i < NUM_LIMBS_256BIT; ++i) {
805 for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
806 carry += ((dlimb_t)(*yy++)) * word;
808 *rr++ = (limb_t)carry;
814 __asm__ __volatile__ (
913 : :
"x"(x),
"z"(y),
"r"(result)
914 :
"r8",
"r9",
"r10",
"r11",
"r16",
"r20",
"r21",
"r22",
930 void Curve25519::mul(limb_t *result,
const limb_t *x,
const limb_t *y)
932 limb_t temp[NUM_LIMBS_512BIT];
933 mulNoReduce(temp, x, y);
934 reduce(result, temp, NUM_LIMBS_256BIT);
957 void Curve25519::mulA24(limb_t *result,
const limb_t *x)
959 #if !defined(CURVE25519_ASM_AVR)
961 #if BIGNUMBER_LIMB_8BIT
962 static limb_t
const a24[3] PROGMEM = {0x41, 0xDB, 0x01};
963 #elif BIGNUMBER_LIMB_16BIT
964 static limb_t
const a24[2] PROGMEM = {0xDB41, 0x0001};
965 #elif BIGNUMBER_LIMB_32BIT || BIGNUMBER_LIMB_64BIT
966 static limb_t
const a24[1] PROGMEM = {0x0001DB41};
968 #error "limb_t must be 8, 16, 32, or 64 bits in size"
970 #define NUM_A24_LIMBS (sizeof(a24) / sizeof(limb_t))
973 limb_t temp[NUM_LIMBS_512BIT];
976 limb_t word = pgm_read_limb(&(a24[0]));
977 const limb_t *xx = x;
979 for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
980 carry += ((dlimb_t)(*xx++)) * word;
981 *tt++ = (limb_t)carry;
987 for (i = 1; i < NUM_A24_LIMBS; ++i) {
988 word = pgm_read_limb(&(a24[i]));
992 for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
993 carry += ((dlimb_t)(*xx++)) * word;
995 *tt++ = (limb_t)carry;
1001 limb_t temp[NUM_LIMBS_512BIT];
1002 #define NUM_A24_LIMBS ((3 + sizeof(limb_t) - 1) / sizeof(limb_t))
1003 __asm__ __volatile__ (
1037 #
if BIGNUMBER_LIMB_16BIT || BIGNUMBER_LIMB_32BIT
1042 "clr __zero_reg__\n"
1044 : :
"x"(x),
"z"(temp)
1045 :
"r8",
"r9",
"r10",
"r11",
"r16",
"r17",
"r18",
"r19",
1046 "r20",
"r21",
"r22",
"r25"
1051 reduce(result, temp, NUM_A24_LIMBS);
1066 void Curve25519::mul_P(limb_t *result,
const limb_t *x,
const limb_t *y)
1068 limb_t temp[NUM_LIMBS_512BIT];
1077 word = pgm_read_limb(&(y[0]));
1080 for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
1081 carry += ((dlimb_t)(*xx++)) * word;
1082 *tt++ = (limb_t)carry;
1083 carry >>= LIMB_BITS;
1085 *tt = (limb_t)carry;
1088 for (i = 1; i < NUM_LIMBS_256BIT; ++i) {
1089 word = pgm_read_limb(&(y[i]));
1093 for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
1094 carry += ((dlimb_t)(*xx++)) * word;
1096 *tt++ = (limb_t)carry;
1097 carry >>= LIMB_BITS;
1099 *tt = (limb_t)carry;
1103 reduce(result, temp, NUM_LIMBS_256BIT);
1117 void Curve25519::add(limb_t *result,
const limb_t *x,
const limb_t *y)
1119 #if !defined(CURVE25519_ASM_AVR)
1122 limb_t *rr = result;
1125 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
1128 *rr++ = (limb_t)carry;
1129 carry >>= LIMB_BITS;
1131 #else // CURVE25519_ASM_AVR
1132 __asm__ __volatile__ (
1152 "adc r17,__zero_reg__\n"
1153 "adc r18,__zero_reg__\n"
1154 "adc r19,__zero_reg__\n"
1155 "mov r25,__zero_reg__\n"
1161 "adc r25,__zero_reg__\n"
1172 : :
"x"(x),
"z"(y),
"r"(result)
1173 :
"r16",
"r17",
"r18",
"r19",
"r20",
"r21",
"r22",
"r23",
1176 #endif // CURVE25519_ASM_AVR
1179 reduceQuick(result);
1192 void Curve25519::sub(limb_t *result,
const limb_t *x,
const limb_t *y)
1194 #if !defined(CURVE25519_ASM_AVR)
1197 limb_t *rr = result;
1201 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
1202 borrow = ((dlimb_t)(*x++)) - (*y++) - ((borrow >> LIMB_BITS) & 0x01);
1203 *rr++ = (limb_t)borrow;
1212 borrow = (borrow >> LIMB_BITS) & 19U;
1213 borrow = ((dlimb_t)(*rr)) - borrow;
1214 *rr++ = (limb_t)borrow;
1215 for (posn = 1; posn < NUM_LIMBS_256BIT; ++posn) {
1216 borrow = ((dlimb_t)(*rr)) - ((borrow >> LIMB_BITS) & 0x01);
1217 *rr++ = (limb_t)borrow;
1219 *(--rr) &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
1220 #else // CURVE25519_ASM_AVR
1221 __asm__ __volatile__ (
1241 "sbc r17,__zero_reg__\n"
1242 "sbc r18,__zero_reg__\n"
1243 "sbc r19,__zero_reg__\n"
1244 "mov r25,__zero_reg__\n"
1245 "sbc r25,__zero_reg__\n"
1250 "sbc r25,__zero_reg__\n"
1271 "sbc r17,__zero_reg__\n"
1272 "sbc r18,__zero_reg__\n"
1273 "sbc r19,__zero_reg__\n"
1274 "mov r25,__zero_reg__\n"
1275 "sbc r25,__zero_reg__\n"
1290 : :
"x"(x),
"z"(y),
"r"(result)
1291 :
"r16",
"r17",
"r18",
"r19",
"r20",
"r21",
"r22",
"r23",
1294 #endif // CURVE25519_ASM_AVR
1309 void Curve25519::cswap(limb_t select, limb_t *x, limb_t *y)
1311 #if !defined(CURVE25519_ASM_AVR)
1318 sel = (limb_t)(((((dlimb_t)1) << LIMB_BITS) - select) >> LIMB_BITS);
1323 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
1324 dummy = sel & (x[posn] ^ y[posn]);
1328 #else // CURVE25519_ASM_AVR
1329 __asm__ __volatile__ (
1333 #
if BIGNUMBER_LIMB_8BIT
1335 #elif BIGNUMBER_LIMB_16BIT
1338 #elif BIGNUMBER_LIMB_32BIT
1344 "mov r24,__zero_reg__\n"
1390 : :
"x"(x),
"z"(y),
"r"(select)
1391 :
"r12",
"r13",
"r14",
"r15",
"r16",
"r17",
"r18",
"r19",
1392 "r20",
"r21",
"r22",
"r23",
"r24",
"r25"
1394 #endif // CURVE25519_ASM_AVR
1409 void Curve25519::cmove(limb_t select, limb_t *x,
const limb_t *y)
1411 #if !defined(CURVE25519_ASM_AVR)
1418 sel = (limb_t)(((((dlimb_t)1) << LIMB_BITS) - select) >> LIMB_BITS);
1422 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
1423 dummy = sel & (x[posn] ^ y[posn]);
1426 #else // CURVE25519_ASM_AVR
1427 __asm__ __volatile__ (
1431 #
if BIGNUMBER_LIMB_8BIT
1433 #elif BIGNUMBER_LIMB_16BIT
1436 #elif BIGNUMBER_LIMB_32BIT
1442 "mov r24,__zero_reg__\n"
1476 : :
"x"(x),
"z"(y),
"r"(select)
1477 :
"r16",
"r17",
"r18",
"r19",
"r20",
"r21",
"r22",
"r23",
1480 #endif // CURVE25519_ASM_AVR
1489 void Curve25519::pow250(limb_t *result,
const limb_t *x)
1491 limb_t t1[NUM_LIMBS_256BIT];
1505 #define RECIP_GROUP_SIZE 10
1506 #define RECIP_GROUP_BITS 250 // Must be a multiple of RECIP_GROUP_SIZE.
1508 for (j = 0; j < (RECIP_GROUP_SIZE - 1); ++j)
1511 for (i = 0; i < ((RECIP_GROUP_BITS / RECIP_GROUP_SIZE) - 2); ++i) {
1512 for (j = 0; j < RECIP_GROUP_SIZE; ++j)
1514 mul(result, result, t1);
1520 mul(result, result, t1);
1521 for (j = 0; j < (RECIP_GROUP_SIZE - 2); ++j) {
1523 mul(result, result, t1);
1537 void Curve25519::recip(limb_t *result,
const limb_t *x)
1546 square(result, result);
1547 square(result, result);
1548 mul(result, result, x);
1549 square(result, result);
1550 square(result, result);
1551 mul(result, result, x);
1552 square(result, result);
1553 mul(result, result, x);
1571 bool Curve25519::sqrt(limb_t *result,
const limb_t *x)
1574 static limb_t
const numSqrtM1[NUM_LIMBS_256BIT] PROGMEM = {
1575 LIMB_PAIR(0x4A0EA0B0, 0xC4EE1B27), LIMB_PAIR(0xAD2FE478, 0x2F431806),
1576 LIMB_PAIR(0x3DFBD7A7, 0x2B4D0099), LIMB_PAIR(0x4FC1DF0B, 0x2B832480)
1578 limb_t y[NUM_LIMBS_256BIT];
1586 square(result, result);
1587 mul(result, result, x);
1588 square(result, result);
1592 if (memcmp(x, y,
sizeof(y)) == 0) {
1598 mul_P(result, result, numSqrtM1);
1600 if (memcmp(x, y,
sizeof(y)) == 0) {
void rand(uint8_t *data, size_t len)
Generates random bytes into a caller-supplied buffer.
static bool eval(uint8_t result[32], const uint8_t s[32], const uint8_t x[32])
Evaluates the raw Curve25519 function.
static void unpackLE(limb_t *limbs, size_t count, const uint8_t *bytes, size_t len)
Unpacks the little-endian byte representation of a big number into a limb array.
static void packLE(uint8_t *bytes, size_t len, const limb_t *limbs, size_t count)
Packs the little-endian byte representation of a big number into a byte array.
static void dh1(uint8_t k[32], uint8_t f[32])
Performs phase 1 of a Diffie-Hellman key exchange using Curve25519.
static bool dh2(uint8_t k[32], uint8_t f[32])
Performs phase 2 of a Diffie-Hellman key exchange using Curve25519.