24 #include "Curve25519.h"
27 #include "utility/LimbUtil.h"
79 static limb_t
const numD[NUM_LIMBS_256BIT] PROGMEM = {
80 LIMB_PAIR(0x135978A3, 0x75EB4DCA), LIMB_PAIR(0x4141D8AB, 0x00700A4D),
81 LIMB_PAIR(0x7779E898, 0x8CC74079), LIMB_PAIR(0x2B6FFE73, 0x52036CEE)
85 static limb_t
const numDx2[NUM_LIMBS_256BIT] PROGMEM = {
86 LIMB_PAIR(0x26B2F159, 0xEBD69B94), LIMB_PAIR(0x8283B156, 0x00E0149A),
87 LIMB_PAIR(0xEEF3D130, 0x198E80F2), LIMB_PAIR(0x56DFFCE7, 0x2406D9DC)
91 static limb_t
const numBx[NUM_LIMBS_256BIT] PROGMEM = {
92 LIMB_PAIR(0x8F25D51A, 0xC9562D60), LIMB_PAIR(0x9525A7B2, 0x692CC760),
93 LIMB_PAIR(0xFDD6DC5C, 0xC0A4E231), LIMB_PAIR(0xCD6E53FE, 0x216936D3)
95 static limb_t
const numBy[NUM_LIMBS_256BIT] PROGMEM = {
96 LIMB_PAIR(0x66666658, 0x66666666), LIMB_PAIR(0x66666666, 0x66666666),
97 LIMB_PAIR(0x66666666, 0x66666666), LIMB_PAIR(0x66666666, 0x66666666)
99 static limb_t
const numBz[NUM_LIMBS_256BIT] PROGMEM = {
100 LIMB_PAIR(0x00000001, 0x00000000), LIMB_PAIR(0x00000000, 0x00000000),
101 LIMB_PAIR(0x00000000, 0x00000000), LIMB_PAIR(0x00000000, 0x00000000)
103 static limb_t
const numBt[NUM_LIMBS_256BIT] PROGMEM = {
104 LIMB_PAIR(0xA5B7DDA3, 0x6DDE8AB3), LIMB_PAIR(0x775152F5, 0x20F09F80),
105 LIMB_PAIR(0x64ABE37D, 0x66EA4E8E), LIMB_PAIR(0xD78B7665, 0x67875F0F)
109 static limb_t
const numQ[NUM_LIMBS_256BIT] PROGMEM = {
110 LIMB_PAIR(0x5CF5D3ED, 0x5812631A), LIMB_PAIR(0xA2F79CD6, 0x14DEF9DE),
111 LIMB_PAIR(0x00000000, 0x00000000), LIMB_PAIR(0x00000000, 0x10000000)
128 const uint8_t publicKey[32],
const void *message,
size_t len)
131 uint8_t *buf = (uint8_t *)(hash.state.w);
132 limb_t a[NUM_LIMBS_256BIT];
133 limb_t r[NUM_LIMBS_256BIT];
134 limb_t k[NUM_LIMBS_256BIT];
135 limb_t t[NUM_LIMBS_512BIT + 1];
139 deriveKeys(&hash, a, privateKey);
143 hash.
update(buf + 32, 32);
144 hash.
update(message, len);
146 reduceQFromBuffer(r, buf, t);
150 encodePoint(signature, rB);
154 hash.
update(signature, 32);
155 hash.
update(publicKey, 32);
156 hash.
update(message, len);
158 reduceQFromBuffer(k, buf, t);
161 Curve25519::mulNoReduce(t, k, a);
162 t[NUM_LIMBS_512BIT] = 0;
190 const void *message,
size_t len)
197 uint8_t *k = (uint8_t *)(hash.state.w);
201 if (decodePoint(A, publicKey) && decodePoint(R, signature)) {
204 hash.
update(signature, 32);
205 hash.
update(publicKey, 32);
206 hash.
update(message, len);
211 mul(sB, kA.t,
false);
215 reduceQFromBuffer(sB.t, k, kA.x);
216 mul(kA, sB.t, A,
false);
220 result = equal(sB, R);
245 RNG.
rand(privateKey, 32);
259 limb_t a[NUM_LIMBS_256BIT];
263 deriveKeys(&hash, a, privateKey);
267 encodePoint(publicKey, ptA);
283 void Ed25519::reduceQFromBuffer(limb_t *result,
const uint8_t buf[64], limb_t *temp)
286 temp[NUM_LIMBS_512BIT] = 0;
287 reduceQ(result, temp);
302 void Ed25519::reduceQ(limb_t *result, limb_t *r)
318 static limb_t
const numM[NUM_LIMBS_256BIT + 1] PROGMEM = {
319 LIMB_PAIR(0x0A2C131B, 0xED9CE5A3), LIMB_PAIR(0x086329A7, 0x2106215D),
320 LIMB_PAIR(0xFFFFFFEB, 0xFFFFFFFF), LIMB_PAIR(0xFFFFFFFF, 0xFFFFFFFF),
323 limb_t temp[NUM_LIMBS_512BIT + NUM_LIMBS_256BIT + 1];
332 numQ, NUM_LIMBS_256BIT);
352 void Ed25519::mul(Point &result,
const limb_t *s, Point &p,
bool constTime)
355 limb_t A[NUM_LIMBS_256BIT];
356 limb_t B[NUM_LIMBS_256BIT];
357 limb_t C[NUM_LIMBS_256BIT];
358 limb_t D[NUM_LIMBS_256BIT];
363 memset(&result, 0,
sizeof(Point));
370 for (t = 255; t > 0; --t) {
374 select = s[sposn] & mask;
375 if (constTime || select) {
376 Curve25519::sub(A, result.y, result.x);
377 Curve25519::sub(C, p.y, p.x);
378 Curve25519::mul(A, A, C);
379 Curve25519::add(B, result.y, result.x);
380 Curve25519::add(C, p.y, p.x);
381 Curve25519::mul(B, B, C);
382 Curve25519::mul(C, result.t, p.t);
383 Curve25519::mul_P(C, C, numDx2);
384 Curve25519::mul(D, result.z, p.z);
385 Curve25519::add(D, D, D);
386 Curve25519::sub(q.t, B, A);
387 Curve25519::sub(q.z, D, C);
388 Curve25519::add(D, D, C);
389 Curve25519::add(B, B, A);
392 Curve25519::mul(q.x, q.t, q.z);
393 Curve25519::mul(q.y, D, B);
394 Curve25519::mul(q.z, q.z, D);
395 Curve25519::mul(q.t, q.t, B);
398 Curve25519::cmove(select, result.x, q.x);
399 Curve25519::cmove(select, result.y, q.y);
400 Curve25519::cmove(select, result.z, q.z);
401 Curve25519::cmove(select, result.t, q.t);
404 Curve25519::mul(result.x, q.t, q.z);
405 Curve25519::mul(result.y, D, B);
406 Curve25519::mul(result.z, q.z, D);
407 Curve25519::mul(result.t, q.t, B);
412 Curve25519::sub(A, p.y, p.x);
413 Curve25519::square(A, A);
414 Curve25519::add(B, p.y, p.x);
415 Curve25519::square(B, B);
416 Curve25519::square(C, p.t);
417 Curve25519::mul_P(C, C, numDx2);
418 Curve25519::square(D, p.z);
419 Curve25519::add(D, D, D);
420 Curve25519::sub(p.t, B, A);
421 Curve25519::sub(p.z, D, C);
422 Curve25519::add(D, D, C);
423 Curve25519::add(B, B, A);
424 Curve25519::mul(p.x, p.t, p.z);
425 Curve25519::mul(p.y, D, B);
426 Curve25519::mul(p.z, p.z, D);
427 Curve25519::mul(p.t, p.t, B);
430 if (mask != (((limb_t)1) << (LIMB_BITS - 1))) {
454 void Ed25519::mul(Point &result,
const limb_t *s,
bool constTime)
457 memcpy_P(P.x, numBx,
sizeof(P.x));
458 memcpy_P(P.y, numBy,
sizeof(P.y));
459 memcpy_P(P.z, numBz,
sizeof(P.z));
460 memcpy_P(P.t, numBt,
sizeof(P.t));
461 mul(result, s, P, constTime);
471 void Ed25519::add(Point &p,
const Point &q)
473 limb_t A[NUM_LIMBS_256BIT];
474 limb_t B[NUM_LIMBS_256BIT];
475 limb_t C[NUM_LIMBS_256BIT];
476 limb_t D[NUM_LIMBS_256BIT];
478 Curve25519::sub(A, p.y, p.x);
479 Curve25519::sub(C, q.y, q.x);
480 Curve25519::mul(A, A, C);
481 Curve25519::add(B, p.y, p.x);
482 Curve25519::add(C, q.y, q.x);
483 Curve25519::mul(B, B, C);
484 Curve25519::mul(C, p.t, q.t);
485 Curve25519::mul_P(C, C, numDx2);
486 Curve25519::mul(D, p.z, q.z);
487 Curve25519::add(D, D, D);
488 Curve25519::sub(p.t, B, A);
489 Curve25519::sub(p.z, D, C);
490 Curve25519::add(D, D, C);
491 Curve25519::add(B, B, A);
492 Curve25519::mul(p.x, p.t, p.z);
493 Curve25519::mul(p.y, D, B);
494 Curve25519::mul(p.z, p.z, D);
495 Curve25519::mul(p.t, p.t, B);
511 bool Ed25519::equal(
const Point &p,
const Point &q)
513 limb_t a[NUM_LIMBS_256BIT];
514 limb_t b[NUM_LIMBS_256BIT];
517 Curve25519::mul(a, p.x, q.z);
518 Curve25519::mul(b, q.x, p.z);
519 result &= secure_compare(a, b,
sizeof(a));
521 Curve25519::mul(a, p.y, q.z);
522 Curve25519::mul(b, q.y, p.z);
523 result &= secure_compare(a, b,
sizeof(a));
539 void Ed25519::encodePoint(uint8_t *buf, Point &point)
546 Curve25519::recip(point.t, point.z);
547 Curve25519::mul(point.x, point.x, point.t);
548 Curve25519::mul(point.y, point.y, point.t);
551 point.y[NUM_LIMBS_256BIT - 1] |= (point.x[0] << (LIMB_BITS - 1));
569 bool Ed25519::decodePoint(Point &point,
const uint8_t *buf)
571 limb_t temp[NUM_LIMBS_256BIT];
577 limb_t
sign = point.y[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1);
578 point.y[NUM_LIMBS_256BIT - 1] &= ~(((limb_t)1) << (LIMB_BITS - 1));
581 memcpy_P(point.z, numBz,
sizeof(point.z));
584 Curve25519::square(point.t, point.y);
585 Curve25519::sub(point.x, point.t, point.z);
586 Curve25519::mul_P(point.t, point.t, numD);
587 Curve25519::add(point.t, point.t, point.z);
588 Curve25519::recip(temp, point.t);
589 Curve25519::mul(point.t, point.x, temp);
593 limb_t check = point.t[0];
594 for (uint8_t posn = 1; posn < NUM_LIMBS_256BIT; ++posn)
595 check |= point.t[posn];
601 memset(point.x, 0,
sizeof(point.x));
606 if (!Curve25519::sqrt(point.x, point.t))
608 if (
sign != (point.x[0] & ((limb_t)1))) {
610 memset(point.t, 0,
sizeof(point.t));
611 Curve25519::sub(point.x, point.t, point.x);
615 Curve25519::mul(point.t, point.x, point.y);
629 void Ed25519::deriveKeys(
SHA512 *hash, limb_t *a,
const uint8_t privateKey[32])
632 uint8_t *buf = (uint8_t *)(hash->state.w);
634 hash->
update(privateKey, 32);
static void reduceQuick_P(limb_t *result, const limb_t *x, const limb_t *y, size_t size)
Reduces x modulo y using subtraction where y is in program memory.
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 limb_t sub(limb_t *result, const limb_t *x, const limb_t *y, size_t size)
Subtracts one big number from another.
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 limb_t add(limb_t *result, const limb_t *x, const limb_t *y, size_t size)
Adds two big numbers.
static void mul_P(limb_t *result, const limb_t *x, size_t xcount, const limb_t *y, size_t ycount)
Multiplies two big numbers where one is in program memory.
static void sign(uint8_t signature[64], const uint8_t privateKey[32], const uint8_t publicKey[32], const void *message, size_t len)
Signs a message using a specific Ed25519 private key.
static void derivePublicKey(uint8_t publicKey[32], const uint8_t privateKey[32])
Derives the public key from a private key.
static void generatePrivateKey(uint8_t privateKey[32])
Generates a private key for Ed25519 signing operations.
static bool verify(const uint8_t signature[64], const uint8_t publicKey[32], const void *message, size_t len)
Verifies a signature using a specific Ed25519 public key.
void rand(uint8_t *data, size_t len)
Generates random bytes into a caller-supplied buffer.
void reset()
Resets the hash ready for a new hashing process.
void update(const void *data, size_t len)
Updates the hash with more data.
void finalize(void *hash, size_t len)
Finalizes the hashing process and returns the hash.