23 #include "Curve25519.h"
26 #include "utility/LimbUtil.h"
49 #if defined(CURVE25519_STRICT_CLEAN)
50 #define strict_clean(x) clean(x)
52 #define strict_clean(x) do { ; } while (0)
76 limb_t x_1[NUM_LIMBS_256BIT];
77 limb_t x_2[NUM_LIMBS_256BIT];
78 limb_t x_3[NUM_LIMBS_256BIT];
79 limb_t z_2[NUM_LIMBS_256BIT];
80 limb_t z_3[NUM_LIMBS_256BIT];
81 limb_t A[NUM_LIMBS_256BIT];
82 limb_t B[NUM_LIMBS_256BIT];
83 limb_t C[NUM_LIMBS_256BIT];
84 limb_t D[NUM_LIMBS_256BIT];
85 limb_t E[NUM_LIMBS_256BIT];
86 limb_t AA[NUM_LIMBS_256BIT];
87 limb_t BB[NUM_LIMBS_256BIT];
88 limb_t DA[NUM_LIMBS_256BIT];
89 limb_t CB[NUM_LIMBS_256BIT];
101 x_1[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
103 memset(x_1, 0,
sizeof(x_1));
114 retval = (bool)(reduceQuick(x_1) & 0x01);
117 memset(x_2, 0,
sizeof(x_2));
119 memset(z_2, 0,
sizeof(z_2));
120 memcpy(x_3, x_1,
sizeof(x_1));
121 memcpy(z_3, x_2,
sizeof(x_2));
128 for (uint8_t t = 255; t > 0; --t) {
131 select = s[sposn] & mask;
133 cswap(swap, x_2, x_3);
134 cswap(swap, z_2, z_3);
168 cswap(swap, x_2, x_3);
169 cswap(swap, z_2, z_3);
248 f[31] = (f[31] & 0x7F) | 0x40;
259 }
while (isWeakPoint(k));
287 weak = isWeakPoint(k);
288 weak |= ((
eval(k, f, k) ^ 0x01) & 0x01);
289 weak |= isWeakPoint(k);
291 return (
bool)((weak ^ 0x01) & 0x01);
301 uint8_t Curve25519::isWeakPoint(
const uint8_t k[32])
307 static const uint8_t points[5][32] PROGMEM = {
308 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
312 {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 {0xE0, 0xEB, 0x7A, 0x7C, 0x3B, 0x41, 0xB8, 0xAE,
317 0x16, 0x56, 0xE3, 0xFA, 0xF1, 0x9F, 0xC4, 0x6A,
318 0xDA, 0x09, 0x8D, 0xEB, 0x9C, 0x32, 0xB1, 0xFD,
319 0x86, 0x62, 0x05, 0x16, 0x5F, 0x49, 0xB8, 0x00},
320 {0x5F, 0x9C, 0x95, 0xBC, 0xA3, 0x50, 0x8C, 0x24,
321 0xB1, 0xD0, 0xB1, 0x55, 0x9C, 0x83, 0xEF, 0x5B,
322 0x04, 0x44, 0x5C, 0xC4, 0x58, 0x1C, 0x8E, 0x86,
323 0xD8, 0x22, 0x4E, 0xDD, 0xD0, 0x9F, 0x11, 0x57},
324 {0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
325 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
326 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
327 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}
336 for (uint8_t posn = 0; posn < 5; ++posn) {
337 const uint8_t *point = points[posn];
338 uint8_t check = (pgm_read_byte(point + 31) ^ k[31]) & 0x7F;
339 for (uint8_t index = 31; index > 0; --index)
340 check |= (pgm_read_byte(point + index - 1) ^ k[index - 1]);
341 result |= (uint8_t)((((uint16_t)0x0100) - check) >> 8);
360 void Curve25519::reduce(limb_t *result, limb_t *x, uint8_t size)
409 carry = ((dlimb_t)(x[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1))) * 19U;
410 x[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
411 for (posn = 0; posn < size; ++posn) {
412 carry += ((dlimb_t)(x[posn + NUM_LIMBS_256BIT])) * 38U;
414 x[posn] = (limb_t)carry;
417 if (size < NUM_LIMBS_256BIT) {
420 for (posn = size; posn < NUM_LIMBS_256BIT; ++posn) {
422 x[posn] = (limb_t)carry;
432 carry += ((dlimb_t)(x[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1))) * 19U;
433 x[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
434 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
436 x[posn] = (limb_t)carry;
446 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
448 x[posn + NUM_LIMBS_256BIT] = (limb_t)carry;
458 limb_t mask = (limb_t)(((slimb_t)(x[NUM_LIMBS_512BIT - 1])) >> (LIMB_BITS - 1));
459 limb_t nmask = ~mask;
460 x[NUM_LIMBS_512BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
461 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
462 result[posn] = (x[posn] & nmask) | (x[posn + NUM_LIMBS_256BIT] & mask);
479 limb_t Curve25519::reduceQuick(limb_t *x)
481 limb_t temp[NUM_LIMBS_256BIT];
493 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
495 *tt++ = (limb_t)carry;
504 limb_t mask = (limb_t)(((slimb_t)(temp[NUM_LIMBS_256BIT - 1])) >> (LIMB_BITS - 1));
505 limb_t nmask = ~mask;
506 temp[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
509 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
510 *xx = ((*xx) & nmask) | ((*tt++) & mask);
533 void Curve25519::mulNoReduce(limb_t *result,
const limb_t *x,
const limb_t *y)
546 for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
547 carry += ((dlimb_t)(*yy++)) * word;
548 *rr++ = (limb_t)carry;
554 for (i = 1; i < NUM_LIMBS_256BIT; ++i) {
559 for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
560 carry += ((dlimb_t)(*yy++)) * word;
562 *rr++ = (limb_t)carry;
579 void Curve25519::mul(limb_t *result,
const limb_t *x,
const limb_t *y)
581 limb_t temp[NUM_LIMBS_512BIT];
582 mulNoReduce(temp, x, y);
583 reduce(result, temp, NUM_LIMBS_256BIT);
606 void Curve25519::mulA24(limb_t *result,
const limb_t *x)
609 #if BIGNUMBER_LIMB_8BIT
610 static limb_t
const a24[3] PROGMEM = {0x41, 0xDB, 0x01};
611 #elif BIGNUMBER_LIMB_16BIT
612 static limb_t
const a24[2] PROGMEM = {0xDB41, 0x0001};
613 #elif BIGNUMBER_LIMB_32BIT
614 static limb_t
const a24[1] PROGMEM = {0x0001DB41};
616 #error "limb_t must be 8, 16, or 32 bits in size"
618 #define NUM_A24_LIMBS (sizeof(a24) / sizeof(limb_t))
621 limb_t temp[NUM_LIMBS_512BIT];
624 limb_t word = pgm_read_limb(&(a24[0]));
625 const limb_t *xx = x;
627 for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
628 carry += ((dlimb_t)(*xx++)) * word;
629 *tt++ = (limb_t)carry;
635 for (i = 1; i < NUM_A24_LIMBS; ++i) {
636 word = pgm_read_limb(&(a24[i]));
640 for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
641 carry += ((dlimb_t)(*xx++)) * word;
643 *tt++ = (limb_t)carry;
650 reduce(result, temp, NUM_A24_LIMBS);
665 void Curve25519::mul_P(limb_t *result,
const limb_t *x,
const limb_t *y)
667 limb_t temp[NUM_LIMBS_512BIT];
679 for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
680 carry += ((dlimb_t)(pgm_read_limb(yy))) * word;
681 *tt++ = (limb_t)carry;
688 for (i = 1; i < NUM_LIMBS_256BIT; ++i) {
693 for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
694 carry += ((dlimb_t)(pgm_read_limb(yy))) * word;
696 *tt++ = (limb_t)carry;
704 reduce(result, temp, NUM_LIMBS_256BIT);
718 void Curve25519::add(limb_t *result,
const limb_t *x,
const limb_t *y)
725 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
728 *rr++ = (limb_t)carry;
746 void Curve25519::sub(limb_t *result,
const limb_t *x,
const limb_t *y)
754 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
755 borrow = ((dlimb_t)(*x++)) - (*y++) - ((borrow >> LIMB_BITS) & 0x01);
756 *rr++ = (limb_t)borrow;
765 borrow = (borrow >> LIMB_BITS) & 19U;
766 borrow = ((dlimb_t)(*rr)) - borrow;
767 *rr++ = (limb_t)borrow;
768 for (posn = 1; posn < NUM_LIMBS_256BIT; ++posn) {
769 borrow = ((dlimb_t)(*rr)) - ((borrow >> LIMB_BITS) & 0x01);
770 *rr++ = (limb_t)borrow;
772 *(--rr) &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
787 void Curve25519::cswap(limb_t select, limb_t *x, limb_t *y)
795 sel = (limb_t)(((((dlimb_t)1) << LIMB_BITS) - select) >> LIMB_BITS);
800 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
801 dummy = sel & (x[posn] ^ y[posn]);
819 void Curve25519::cmove(limb_t select, limb_t *x,
const limb_t *y)
827 sel = (limb_t)(((((dlimb_t)1) << LIMB_BITS) - select) >> LIMB_BITS);
831 for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
832 dummy = sel & (x[posn] ^ y[posn]);
843 void Curve25519::pow250(limb_t *result,
const limb_t *x)
845 limb_t t1[NUM_LIMBS_256BIT];
859 #define RECIP_GROUP_SIZE 10
860 #define RECIP_GROUP_BITS 250 // Must be a multiple of RECIP_GROUP_SIZE.
862 for (j = 0; j < (RECIP_GROUP_SIZE - 1); ++j)
865 for (i = 0; i < ((RECIP_GROUP_BITS / RECIP_GROUP_SIZE) - 2); ++i) {
866 for (j = 0; j < RECIP_GROUP_SIZE; ++j)
868 mul(result, result, t1);
874 mul(result, result, t1);
875 for (j = 0; j < (RECIP_GROUP_SIZE - 2); ++j) {
877 mul(result, result, t1);
891 void Curve25519::recip(limb_t *result,
const limb_t *x)
900 square(result, result);
901 square(result, result);
902 mul(result, result, x);
903 square(result, result);
904 square(result, result);
905 mul(result, result, x);
906 square(result, result);
907 mul(result, result, x);
925 bool Curve25519::sqrt(limb_t *result,
const limb_t *x)
928 static limb_t
const numSqrtM1[NUM_LIMBS_256BIT] PROGMEM = {
929 LIMB(0x4A0EA0B0), LIMB(0xC4EE1B27), LIMB(0xAD2FE478), LIMB(0x2F431806),
930 LIMB(0x3DFBD7A7), LIMB(0x2B4D0099), LIMB(0x4FC1DF0B), LIMB(0x2B832480)
932 limb_t y[NUM_LIMBS_256BIT];
941 square(result, result);
942 mul(result, result, x);
943 square(result, result);
947 if (memcmp(x, y,
sizeof(y)) == 0) {
953 mul_P(result, result, numSqrtM1);
955 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.