23 #include "Curve25519.h"
26 #include "utility/LimbUtil.h"
55 #if defined(CURVE25519_STRICT_CLEAN)
56 #define strict_clean(x) clean(x)
58 #define strict_clean(x) do { ; } while (0)
82 limb_t x_1[NUM_LIMBS_256BIT];
83 limb_t x_2[NUM_LIMBS_256BIT];
84 limb_t x_3[NUM_LIMBS_256BIT];
85 limb_t z_2[NUM_LIMBS_256BIT];
86 limb_t z_3[NUM_LIMBS_256BIT];
87 limb_t A[NUM_LIMBS_256BIT];
88 limb_t B[NUM_LIMBS_256BIT];
89 limb_t C[NUM_LIMBS_256BIT];
90 limb_t D[NUM_LIMBS_256BIT];
91 limb_t E[NUM_LIMBS_256BIT];
92 limb_t AA[NUM_LIMBS_256BIT];
93 limb_t BB[NUM_LIMBS_256BIT];
94 limb_t DA[NUM_LIMBS_256BIT];
95 limb_t CB[NUM_LIMBS_256BIT];
107 x_1[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
109 memset(x_1, 0,
sizeof(x_1));
120 retval = (bool)(reduceQuick(x_1) & 0x01);
123 memset(x_2, 0,
sizeof(x_2));
125 memset(z_2, 0,
sizeof(z_2));
126 memcpy(x_3, x_1,
sizeof(x_1));
127 memcpy(z_3, x_2,
sizeof(x_2));
134 for (uint8_t t = 255; t > 0; --t) {
137 select = s[sposn] & mask;
139 cswap(swap, x_2, x_3);
140 cswap(swap, z_2, z_3);
174 cswap(swap, x_2, x_3);
175 cswap(swap, z_2, z_3);
254 f[31] = (f[31] & 0x7F) | 0x40;
265 }
while (isWeakPoint(k));
293 weak = isWeakPoint(k);
294 weak |= ((
eval(k, f, k) ^ 0x01) & 0x01);
295 weak |= isWeakPoint(k);
297 return (
bool)((weak ^ 0x01) & 0x01);
307 uint8_t Curve25519::isWeakPoint(
const uint8_t k[32])
313 static const uint8_t points[5][32] PROGMEM = {
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
318 {0x01, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
322 {0xE0, 0xEB, 0x7A, 0x7C, 0x3B, 0x41, 0xB8, 0xAE,
323 0x16, 0x56, 0xE3, 0xFA, 0xF1, 0x9F, 0xC4, 0x6A,
324 0xDA, 0x09, 0x8D, 0xEB, 0x9C, 0x32, 0xB1, 0xFD,
325 0x86, 0x62, 0x05, 0x16, 0x5F, 0x49, 0xB8, 0x00},
326 {0x5F, 0x9C, 0x95, 0xBC, 0xA3, 0x50, 0x8C, 0x24,
327 0xB1, 0xD0, 0xB1, 0x55, 0x9C, 0x83, 0xEF, 0x5B,
328 0x04, 0x44, 0x5C, 0xC4, 0x58, 0x1C, 0x8E, 0x86,
329 0xD8, 0x22, 0x4E, 0xDD, 0xD0, 0x9F, 0x11, 0x57},
330 {0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
331 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
332 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
333 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}
342 for (uint8_t posn = 0; posn < 5; ++posn) {
343 const uint8_t *point = points[posn];
344 uint8_t check = (pgm_read_byte(&(point[31])) ^ k[31]) & 0x7F;
345 for (uint8_t index = 31; index > 0; --index)
346 check |= (pgm_read_byte(&(point[index - 1])) ^ k[index - 1]);
347 result |= (uint8_t)((((uint16_t)0x0100) - check) >> 8);
366 void Curve25519::reduce(limb_t *result, limb_t *x, uint8_t size)
409 #if !defined(CURVE25519_ASM_AVR)
416 carry = ((dlimb_t)(x[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1))) * 19U;
417 x[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
418 for (posn = 0; posn < size; ++posn) {
419 carry += ((dlimb_t)(x[posn + NUM_LIMBS_256BIT])) * 38U;
421 x[posn] = (limb_t)carry;
424 if (size < NUM_LIMBS_256BIT) {
427 for (posn = size; posn < NUM_LIMBS_256BIT; ++posn) {
429 x[posn] = (limb_t)carry;
439 carry += ((dlimb_t)(x[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1))) * 19U;
440 x[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
441 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
443 x[posn] = (limb_t)carry;
453 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
455 x[posn + NUM_LIMBS_256BIT] = (limb_t)carry;
465 limb_t mask = (limb_t)(((slimb_t)(x[NUM_LIMBS_512BIT - 1])) >> (LIMB_BITS - 1));
466 limb_t nmask = ~mask;
467 x[NUM_LIMBS_512BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
468 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
469 result[posn] = (x[posn] & nmask) | (x[posn + NUM_LIMBS_256BIT] & mask);
472 __asm__ __volatile__ (
481 "mov r24,__zero_reg__\n"
482 "sbc r24,__zero_reg__\n"
487 "mov r22,__zero_reg__\n"
507 "add __tmp_reg__,r24\n"
508 "st Z+,__tmp_reg__\n"
512 "adc __tmp_reg__,r22\n"
513 "st Z+,__tmp_reg__\n"
555 "mov __zero_reg__,r22\n"
570 "adc r17,__zero_reg__\n"
571 "adc r18,__zero_reg__\n"
572 "adc r19,__zero_reg__\n"
573 "mov r25,__zero_reg__\n"
589 "mov r25,__zero_reg__\n"
590 "sbc r25,__zero_reg__\n"
626 : :
"z"(x),
"r"((uint8_t)(size *
sizeof(limb_t))),
"x"(result)
627 :
"r16",
"r17",
"r18",
"r19",
"r20",
"r21",
"r22",
"r23",
646 limb_t Curve25519::reduceQuick(limb_t *x)
648 #if !defined(CURVE25519_ASM_AVR)
649 limb_t temp[NUM_LIMBS_256BIT];
661 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
663 *tt++ = (limb_t)carry;
672 limb_t mask = (limb_t)(((slimb_t)(temp[NUM_LIMBS_256BIT - 1])) >> (LIMB_BITS - 1));
673 limb_t nmask = ~mask;
674 temp[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
677 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
678 *xx = ((*xx) & nmask) | ((*tt++) & mask);
688 limb_t temp[NUM_LIMBS_256BIT];
690 __asm__ __volatile__ (
701 "adc r17,__zero_reg__\n"
702 "adc r18,__zero_reg__\n"
703 "adc r19,__zero_reg__\n"
704 "mov r25,__zero_reg__\n"
720 "mov r25,__zero_reg__\n"
721 "sbc r25,__zero_reg__\n"
759 :
"r16",
"r17",
"r18",
"r19",
"r20",
"r21",
"r22",
"r23",
779 void Curve25519::mulNoReduce(limb_t *result,
const limb_t *x,
const limb_t *y)
781 #if !defined(CURVE25519_ASM_AVR)
793 for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
794 carry += ((dlimb_t)(*yy++)) * word;
795 *rr++ = (limb_t)carry;
801 for (i = 1; i < NUM_LIMBS_256BIT; ++i) {
806 for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
807 carry += ((dlimb_t)(*yy++)) * word;
809 *rr++ = (limb_t)carry;
815 __asm__ __volatile__ (
914 : :
"x"(x),
"z"(y),
"r"(result)
915 :
"r8",
"r9",
"r10",
"r11",
"r16",
"r20",
"r21",
"r22",
931 void Curve25519::mul(limb_t *result,
const limb_t *x,
const limb_t *y)
933 limb_t temp[NUM_LIMBS_512BIT];
934 mulNoReduce(temp, x, y);
935 reduce(result, temp, NUM_LIMBS_256BIT);
937 crypto_feed_watchdog();
959 void Curve25519::mulA24(limb_t *result,
const limb_t *x)
961 #if !defined(CURVE25519_ASM_AVR)
963 #if BIGNUMBER_LIMB_8BIT
964 static limb_t
const a24[3] PROGMEM = {0x41, 0xDB, 0x01};
965 #elif BIGNUMBER_LIMB_16BIT
966 static limb_t
const a24[2] PROGMEM = {0xDB41, 0x0001};
967 #elif BIGNUMBER_LIMB_32BIT || BIGNUMBER_LIMB_64BIT
968 static limb_t
const a24[1] PROGMEM = {0x0001DB41};
970 #error "limb_t must be 8, 16, 32, or 64 bits in size"
972 #define NUM_A24_LIMBS (sizeof(a24) / sizeof(limb_t))
975 limb_t temp[NUM_LIMBS_512BIT];
978 limb_t word = pgm_read_limb(&(a24[0]));
979 const limb_t *xx = x;
981 for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
982 carry += ((dlimb_t)(*xx++)) * word;
983 *tt++ = (limb_t)carry;
989 for (i = 1; i < NUM_A24_LIMBS; ++i) {
990 word = pgm_read_limb(&(a24[i]));
994 for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
995 carry += ((dlimb_t)(*xx++)) * word;
997 *tt++ = (limb_t)carry;
1000 *tt = (limb_t)carry;
1003 limb_t temp[NUM_LIMBS_512BIT];
1004 #define NUM_A24_LIMBS ((3 + sizeof(limb_t) - 1) / sizeof(limb_t))
1005 __asm__ __volatile__ (
1039 #
if BIGNUMBER_LIMB_16BIT || BIGNUMBER_LIMB_32BIT
1044 "clr __zero_reg__\n"
1046 : :
"x"(x),
"z"(temp)
1047 :
"r8",
"r9",
"r10",
"r11",
"r16",
"r17",
"r18",
"r19",
1048 "r20",
"r21",
"r22",
"r25"
1053 reduce(result, temp, NUM_A24_LIMBS);
1068 void Curve25519::mul_P(limb_t *result,
const limb_t *x,
const limb_t *y)
1070 limb_t temp[NUM_LIMBS_512BIT];
1079 word = pgm_read_limb(&(y[0]));
1082 for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
1083 carry += ((dlimb_t)(*xx++)) * word;
1084 *tt++ = (limb_t)carry;
1085 carry >>= LIMB_BITS;
1087 *tt = (limb_t)carry;
1090 for (i = 1; i < NUM_LIMBS_256BIT; ++i) {
1091 word = pgm_read_limb(&(y[i]));
1095 for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
1096 carry += ((dlimb_t)(*xx++)) * word;
1098 *tt++ = (limb_t)carry;
1099 carry >>= LIMB_BITS;
1101 *tt = (limb_t)carry;
1105 reduce(result, temp, NUM_LIMBS_256BIT);
1119 void Curve25519::add(limb_t *result,
const limb_t *x,
const limb_t *y)
1121 #if !defined(CURVE25519_ASM_AVR)
1124 limb_t *rr = result;
1127 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
1130 *rr++ = (limb_t)carry;
1131 carry >>= LIMB_BITS;
1134 __asm__ __volatile__ (
1154 "adc r17,__zero_reg__\n"
1155 "adc r18,__zero_reg__\n"
1156 "adc r19,__zero_reg__\n"
1157 "mov r25,__zero_reg__\n"
1163 "adc r25,__zero_reg__\n"
1174 : :
"x"(x),
"z"(y),
"r"(result)
1175 :
"r16",
"r17",
"r18",
"r19",
"r20",
"r21",
"r22",
"r23",
1181 reduceQuick(result);
1194 void Curve25519::sub(limb_t *result,
const limb_t *x,
const limb_t *y)
1196 #if !defined(CURVE25519_ASM_AVR)
1199 limb_t *rr = result;
1203 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
1204 borrow = ((dlimb_t)(*x++)) - (*y++) - ((borrow >> LIMB_BITS) & 0x01);
1205 *rr++ = (limb_t)borrow;
1214 borrow = (borrow >> LIMB_BITS) & 19U;
1215 borrow = ((dlimb_t)(*rr)) - borrow;
1216 *rr++ = (limb_t)borrow;
1217 for (posn = 1; posn < NUM_LIMBS_256BIT; ++posn) {
1218 borrow = ((dlimb_t)(*rr)) - ((borrow >> LIMB_BITS) & 0x01);
1219 *rr++ = (limb_t)borrow;
1221 *(--rr) &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
1223 __asm__ __volatile__ (
1243 "sbc r17,__zero_reg__\n"
1244 "sbc r18,__zero_reg__\n"
1245 "sbc r19,__zero_reg__\n"
1246 "mov r25,__zero_reg__\n"
1247 "sbc r25,__zero_reg__\n"
1252 "sbc r25,__zero_reg__\n"
1273 "sbc r17,__zero_reg__\n"
1274 "sbc r18,__zero_reg__\n"
1275 "sbc r19,__zero_reg__\n"
1276 "mov r25,__zero_reg__\n"
1277 "sbc r25,__zero_reg__\n"
1292 : :
"x"(x),
"z"(y),
"r"(result)
1293 :
"r16",
"r17",
"r18",
"r19",
"r20",
"r21",
"r22",
"r23",
1311 void Curve25519::cswap(limb_t select, limb_t *x, limb_t *y)
1313 #if !defined(CURVE25519_ASM_AVR)
1320 sel = (limb_t)(((((dlimb_t)1) << LIMB_BITS) - select) >> LIMB_BITS);
1325 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
1326 dummy = sel & (x[posn] ^ y[posn]);
1331 __asm__ __volatile__ (
1335 #
if BIGNUMBER_LIMB_8BIT
1337 #elif BIGNUMBER_LIMB_16BIT
1340 #elif BIGNUMBER_LIMB_32BIT
1346 "mov r24,__zero_reg__\n"
1392 : :
"x"(x),
"z"(y),
"r"(select)
1393 :
"r12",
"r13",
"r14",
"r15",
"r16",
"r17",
"r18",
"r19",
1394 "r20",
"r21",
"r22",
"r23",
"r24",
"r25"
1411 void Curve25519::cmove(limb_t select, limb_t *x,
const limb_t *y)
1413 #if !defined(CURVE25519_ASM_AVR)
1420 sel = (limb_t)(((((dlimb_t)1) << LIMB_BITS) - select) >> LIMB_BITS);
1424 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
1425 dummy = sel & (x[posn] ^ y[posn]);
1429 __asm__ __volatile__ (
1433 #
if BIGNUMBER_LIMB_8BIT
1435 #elif BIGNUMBER_LIMB_16BIT
1438 #elif BIGNUMBER_LIMB_32BIT
1444 "mov r24,__zero_reg__\n"
1478 : :
"x"(x),
"z"(y),
"r"(select)
1479 :
"r16",
"r17",
"r18",
"r19",
"r20",
"r21",
"r22",
"r23",
1491 void Curve25519::pow250(limb_t *result,
const limb_t *x)
1493 limb_t t1[NUM_LIMBS_256BIT];
1507 #define RECIP_GROUP_SIZE 10
1508 #define RECIP_GROUP_BITS 250
1510 for (j = 0; j < (RECIP_GROUP_SIZE - 1); ++j)
1513 for (i = 0; i < ((RECIP_GROUP_BITS / RECIP_GROUP_SIZE) - 2); ++i) {
1514 for (j = 0; j < RECIP_GROUP_SIZE; ++j)
1516 mul(result, result, t1);
1522 mul(result, result, t1);
1523 for (j = 0; j < (RECIP_GROUP_SIZE - 2); ++j) {
1525 mul(result, result, t1);
1539 void Curve25519::recip(limb_t *result,
const limb_t *x)
1548 square(result, result);
1549 square(result, result);
1550 mul(result, result, x);
1551 square(result, result);
1552 square(result, result);
1553 mul(result, result, x);
1554 square(result, result);
1555 mul(result, result, x);
1573 bool Curve25519::sqrt(limb_t *result,
const limb_t *x)
1576 static limb_t
const numSqrtM1[NUM_LIMBS_256BIT] PROGMEM = {
1577 LIMB_PAIR(0x4A0EA0B0, 0xC4EE1B27), LIMB_PAIR(0xAD2FE478, 0x2F431806),
1578 LIMB_PAIR(0x3DFBD7A7, 0x2B4D0099), LIMB_PAIR(0x4FC1DF0B, 0x2B832480)
1580 limb_t y[NUM_LIMBS_256BIT];
1588 square(result, result);
1589 mul(result, result, x);
1590 square(result, result);
1594 if (memcmp(x, y,
sizeof(y)) == 0) {
1600 mul_P(result, result, numSqrtM1);
1602 if (memcmp(x, y,
sizeof(y)) == 0) {
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 bool dh2(uint8_t k[32], uint8_t f[32])
Performs phase 2 of a Diffie-Hellman key exchange using Curve25519.
static void dh1(uint8_t k[32], uint8_t f[32])
Performs phase 1 of a Diffie-Hellman key exchange using Curve25519.
static bool eval(uint8_t result[32], const uint8_t s[32], const uint8_t x[32])
Evaluates the raw Curve25519 function.
void rand(uint8_t *data, size_t len)
Generates random bytes into a caller-supplied buffer.