ArduinoLibs
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
Ed25519.cpp
1 /*
2  * Copyright (C) 2015 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "Ed25519.h"
24 #include "Curve25519.h"
25 #include "Crypto.h"
26 #include "RNG.h"
27 #include "utility/LimbUtil.h"
28 #include <string.h>
29 
78 // 37095705934669439343138083508754565189542113879843219016388785533085940283555
79 static limb_t const numD[NUM_LIMBS_256BIT] PROGMEM = {
80  LIMB(0x135978A3), LIMB(0x75EB4DCA), LIMB(0x4141D8AB), LIMB(0x00700A4D),
81  LIMB(0x7779E898), LIMB(0x8CC74079), LIMB(0x2B6FFE73), LIMB(0x52036CEE)
82 };
83 
84 // d * 2
85 static limb_t const numDx2[NUM_LIMBS_256BIT] PROGMEM = {
86  LIMB(0x26B2F159), LIMB(0xEBD69B94), LIMB(0x8283B156), LIMB(0x00E0149A),
87  LIMB(0xEEF3D130), LIMB(0x198E80F2), LIMB(0x56DFFCE7), LIMB(0x2406D9DC)
88 };
89 
90 // Extended homogenous co-ordinates for the base point.
91 static limb_t const numBx[NUM_LIMBS_256BIT] PROGMEM = {
92  LIMB(0x8F25D51A), LIMB(0xC9562D60), LIMB(0x9525A7B2), LIMB(0x692CC760),
93  LIMB(0xFDD6DC5C), LIMB(0xC0A4E231), LIMB(0xCD6E53FE), LIMB(0x216936D3)
94 };
95 static limb_t const numBy[NUM_LIMBS_256BIT] PROGMEM = {
96  LIMB(0x66666658), LIMB(0x66666666), LIMB(0x66666666), LIMB(0x66666666),
97  LIMB(0x66666666), LIMB(0x66666666), LIMB(0x66666666), LIMB(0x66666666)
98 };
99 static limb_t const numBz[NUM_LIMBS_256BIT] PROGMEM = {
100  LIMB(0x00000001), LIMB(0x00000000), LIMB(0x00000000), LIMB(0x00000000),
101  LIMB(0x00000000), LIMB(0x00000000), LIMB(0x00000000), LIMB(0x00000000)
102 };
103 static limb_t const numBt[NUM_LIMBS_256BIT] PROGMEM = {
104  LIMB(0xA5B7DDA3), LIMB(0x6DDE8AB3), LIMB(0x775152F5), LIMB(0x20F09F80),
105  LIMB(0x64ABE37D), LIMB(0x66EA4E8E), LIMB(0xD78B7665), LIMB(0x67875F0F)
106 };
107 
108 // 2^252 + 27742317777372353535851937790883648493
109 static limb_t const numQ[NUM_LIMBS_256BIT] PROGMEM = {
110  LIMB(0x5CF5D3ED), LIMB(0x5812631A), LIMB(0xA2F79CD6), LIMB(0x14DEF9DE),
111  LIMB(0x00000000), LIMB(0x00000000), LIMB(0x00000000), LIMB(0x10000000)
112 };
113 
127 void Ed25519::sign(uint8_t signature[64], const uint8_t privateKey[32],
128  const uint8_t publicKey[32], const void *message, size_t len)
129 {
130  SHA512 hash;
131  uint8_t *buf = (uint8_t *)(hash.state.w); // Reuse hash buffer to save memory.
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];
136  Point rB;
137 
138  // Derive the secret scalar a and the message prefix from the private key.
139  deriveKeys(&hash, a, privateKey);
140 
141  // Hash the prefix and the message to derive r.
142  hash.reset();
143  hash.update(buf + 32, 32);
144  hash.update(message, len);
145  hash.finalize(buf, 0);
146  reduceQFromBuffer(r, buf, t);
147 
148  // Encode rB into the first half of the signature buffer as R.
149  mul(rB, r);
150  encodePoint(signature, rB);
151 
152  // Hash R, A, and the message to get k.
153  hash.reset();
154  hash.update(signature, 32); // R
155  hash.update(publicKey, 32); // A
156  hash.update(message, len);
157  hash.finalize(buf, 0);
158  reduceQFromBuffer(k, buf, t);
159 
160  // Compute s = (r + k * a) mod q.
161  Curve25519::mulNoReduce(t, k, a);
162  t[NUM_LIMBS_512BIT] = 0;
163  reduceQ(t, t);
164  BigNumberUtil::add(t, t, r, NUM_LIMBS_256BIT);
165  BigNumberUtil::reduceQuick_P(t, t, numQ, NUM_LIMBS_256BIT);
166  BigNumberUtil::packLE(signature + 32, 32, t, NUM_LIMBS_256BIT);
167 
168  // Clean up.
169  clean(a);
170  clean(r);
171  clean(k);
172  clean(t);
173  clean(rB);
174 }
175 
189 bool Ed25519::verify(const uint8_t signature[64], const uint8_t publicKey[32],
190  const void *message, size_t len)
191 {
192  SHA512 hash;
193  Point A;
194  Point R;
195  Point sB;
196  Point kA;
197  uint8_t *k = (uint8_t *)(hash.state.w); // Reuse hash buffer to save memory.
198  bool result = false;
199 
200  // Decode the public key and the R component of the signature.
201  if (decodePoint(A, publicKey) && decodePoint(R, signature)) {
202  // Reconstruct the k value from the signing step.
203  hash.reset();
204  hash.update(signature, 32);
205  hash.update(publicKey, 32);
206  hash.update(message, len);
207  hash.finalize(k, 0);
208 
209  // Calculate s * B. The s value is stored temporarily in kA.t.
210  BigNumberUtil::unpackLE(kA.t, NUM_LIMBS_256BIT, signature + 32, 32);
211  mul(sB, kA.t, false);
212 
213  // Calculate R + k * A. We don't need sB.t in equal() below,
214  // so we reuse that as a temporary buffer when reducing k.
215  reduceQFromBuffer(sB.t, k, kA.x);
216  mul(kA, sB.t, A, false);
217  add(R, kA);
218 
219  // Compare s * B and R + k * A for equality.
220  result = equal(sB, R);
221  }
222 
223  // Clean up and exit.
224  clean(A);
225  clean(R);
226  clean(sB);
227  clean(kA);
228  return result;
229 }
230 
243 void Ed25519::generatePrivateKey(uint8_t privateKey[32])
244 {
245  RNG.rand(privateKey, 32);
246 }
247 
256 void Ed25519::derivePublicKey(uint8_t publicKey[32], const uint8_t privateKey[32])
257 {
258  SHA512 hash;
259  uint8_t *buf = (uint8_t *)(hash.state.w);
260  limb_t a[NUM_LIMBS_256BIT];
261  Point ptA;
262 
263  // Derive the secret scalar a from the private key.
264  deriveKeys(&hash, a, privateKey);
265 
266  // Compute the point A = aB and encode it.
267  mul(ptA, a);
268  encodePoint(publicKey, ptA);
269 
270  // Clean up and exit.
271  clean(a);
272  clean(ptA);
273 }
274 
284 void Ed25519::reduceQFromBuffer(limb_t *result, const uint8_t buf[64], limb_t *temp)
285 {
286  BigNumberUtil::unpackLE(temp, NUM_LIMBS_512BIT, buf, 64);
287  temp[NUM_LIMBS_512BIT] = 0;
288  reduceQ(result, temp);
289 }
290 
303 void Ed25519::reduceQ(limb_t *result, limb_t *r)
304 {
305  // Algorithm from: http://en.wikipedia.org/wiki/Barrett_reduction
306  //
307  // We assume that r is less than or equal to (q - 1)^2.
308  //
309  // We want to compute result = r mod q. Find the smallest k such
310  // that 2^k > q. In our case, k = 253. Then set m = floor(4^k / q)
311  // and let r = r - q * floor(m * r / 4^k). This will be the result
312  // or it will be at most one subtraction of q away from the result.
313  //
314  // Note: 4^k = 4^253 = 2^506 = 2^512/2^6. We can more easily compute
315  // the result we want if we set m = floor(4^k * 2^6 / q) instead and
316  // then r = r - q * floor(m * r / 2^512). Because the slight extra
317  // precision in m, r is at most two subtractions of q away from the
318  // final result.
319  static limb_t const numM[NUM_LIMBS_256BIT + 1] PROGMEM = {
320  LIMB(0x0A2C131B), LIMB(0xED9CE5A3), LIMB(0x086329A7), LIMB(0x2106215D),
321  LIMB(0xFFFFFFEB), LIMB(0xFFFFFFFF), LIMB(0xFFFFFFFF), LIMB(0xFFFFFFFF),
322  0x0F
323  };
324  limb_t temp[NUM_LIMBS_512BIT + NUM_LIMBS_256BIT + 1];
325 
326  // Multiply r by m.
327  BigNumberUtil::mul_P(temp, r, NUM_LIMBS_512BIT, numM, NUM_LIMBS_256BIT + 1);
328 
329  // Multiply (m * r) / 2^512 by q and subtract it from r.
330  // We can ignore the high words of the subtraction result
331  // because they will all turn into zero after the subtraction.
332  BigNumberUtil::mul_P(temp, temp + NUM_LIMBS_512BIT, NUM_LIMBS_256BIT + 1,
333  numQ, NUM_LIMBS_256BIT);
334  BigNumberUtil::sub(r, r, temp, NUM_LIMBS_256BIT);
335 
336  // Perform two subtractions of q from the result to reduce it.
337  BigNumberUtil::reduceQuick_P(result, r, numQ, NUM_LIMBS_256BIT);
338  BigNumberUtil::reduceQuick_P(result, result, numQ, NUM_LIMBS_256BIT);
339 
340  // Clean up and exit.
341  clean(temp);
342 }
343 
353 void Ed25519::mul(Point &result, const limb_t *s, Point &p, bool constTime)
354 {
355  Point q;
356  limb_t A[NUM_LIMBS_256BIT];
357  limb_t B[NUM_LIMBS_256BIT];
358  limb_t C[NUM_LIMBS_256BIT];
359  limb_t D[NUM_LIMBS_256BIT];
360  limb_t mask, select;
361  uint8_t sposn, t;
362 
363  // Initialize the result to (0, 1, 1, 0).
364  memset(&result, 0, sizeof(Point));
365  result.y[0] = 1;
366  result.z[0] = 1;
367 
368  // Iterate over the 255 bits of "s" to calculate "s * p".
369  mask = 1;
370  sposn = 0;
371  for (t = 255; t > 0; --t) {
372  // Add p to the result to produce q. The specification refers
373  // to temporary variables A to H. We can dispense with E to H
374  // by using B, D, q.z, and q.t to hold those values temporarily.
375  select = s[sposn] & mask;
376  if (constTime || select) {
377  Curve25519::sub(A, result.y, result.x);
378  Curve25519::sub(C, p.y, p.x);
379  Curve25519::mul(A, A, C);
380  Curve25519::add(B, result.y, result.x);
381  Curve25519::add(C, p.y, p.x);
382  Curve25519::mul(B, B, C);
383  Curve25519::mul(C, result.t, p.t);
384  Curve25519::mul_P(C, C, numDx2);
385  Curve25519::mul(D, result.z, p.z);
386  Curve25519::add(D, D, D);
387  Curve25519::sub(q.t, B, A); // E = B - A
388  Curve25519::sub(q.z, D, C); // F = D - C
389  Curve25519::add(D, D, C); // G = D + C
390  Curve25519::add(B, B, A); // H = B + A
391  if (constTime) {
392  // Put the intermediate value into q.
393  Curve25519::mul(q.x, q.t, q.z); // q.x = E * F
394  Curve25519::mul(q.y, D, B); // q.y = G * H
395  Curve25519::mul(q.z, q.z, D); // q.z = F * G
396  Curve25519::mul(q.t, q.t, B); // q.t = E * H
397 
398  // Copy q into the result if the current bit of s is 1.
399  Curve25519::cmove(select, result.x, q.x);
400  Curve25519::cmove(select, result.y, q.y);
401  Curve25519::cmove(select, result.z, q.z);
402  Curve25519::cmove(select, result.t, q.t);
403  } else {
404  // Put the intermediate value directly into the result.
405  Curve25519::mul(result.x, q.t, q.z); // q.x = E * F
406  Curve25519::mul(result.y, D, B); // q.y = G * H
407  Curve25519::mul(result.z, q.z, D); // q.z = F * G
408  Curve25519::mul(result.t, q.t, B); // q.t = E * H
409  }
410  }
411 
412  // Double p for the next iteration.
413  Curve25519::sub(A, p.y, p.x);
414  Curve25519::square(A, A);
415  Curve25519::add(B, p.y, p.x);
416  Curve25519::square(B, B);
417  Curve25519::square(C, p.t);
418  Curve25519::mul_P(C, C, numDx2);
419  Curve25519::square(D, p.z);
420  Curve25519::add(D, D, D);
421  Curve25519::sub(p.t, B, A); // E = B - A
422  Curve25519::sub(p.z, D, C); // F = D - C
423  Curve25519::add(D, D, C); // G = D + C
424  Curve25519::add(B, B, A); // H = B + A
425  Curve25519::mul(p.x, p.t, p.z); // p.x = E * F
426  Curve25519::mul(p.y, D, B); // p.y = G * H
427  Curve25519::mul(p.z, p.z, D); // p.z = F * G
428  Curve25519::mul(p.t, p.t, B); // p.t = E * H
429 
430  // Move onto the next bit of s from lowest to highest.
431  if (mask != (((limb_t)1) << (LIMB_BITS - 1))) {
432  mask <<= 1;
433  } else {
434  ++sposn;
435  mask = 1;
436  }
437  }
438 
439  // Clean up.
440  clean(q);
441  clean(A);
442  clean(B);
443  clean(C);
444  clean(D);
445 }
446 
455 void Ed25519::mul(Point &result, const limb_t *s, bool constTime)
456 {
457  Point P;
458  memcpy_P(P.x, numBx, sizeof(P.x));
459  memcpy_P(P.y, numBy, sizeof(P.y));
460  memcpy_P(P.z, numBz, sizeof(P.z));
461  memcpy_P(P.t, numBt, sizeof(P.t));
462  mul(result, s, P, constTime);
463  clean(P);
464 }
465 
472 void Ed25519::add(Point &p, const Point &q)
473 {
474  limb_t A[NUM_LIMBS_256BIT];
475  limb_t B[NUM_LIMBS_256BIT];
476  limb_t C[NUM_LIMBS_256BIT];
477  limb_t D[NUM_LIMBS_256BIT];
478 
479  Curve25519::sub(A, p.y, p.x);
480  Curve25519::sub(C, q.y, q.x);
481  Curve25519::mul(A, A, C);
482  Curve25519::add(B, p.y, p.x);
483  Curve25519::add(C, q.y, q.x);
484  Curve25519::mul(B, B, C);
485  Curve25519::mul(C, p.t, q.t);
486  Curve25519::mul_P(C, C, numDx2);
487  Curve25519::mul(D, p.z, q.z);
488  Curve25519::add(D, D, D);
489  Curve25519::sub(p.t, B, A); // E = B - A
490  Curve25519::sub(p.z, D, C); // F = D - C
491  Curve25519::add(D, D, C); // G = D + C
492  Curve25519::add(B, B, A); // H = B + A
493  Curve25519::mul(p.x, p.t, p.z); // p.x = E * F
494  Curve25519::mul(p.y, D, B); // p.y = G * H
495  Curve25519::mul(p.z, p.z, D); // p.z = F * G
496  Curve25519::mul(p.t, p.t, B); // p.t = E * H
497 
498  clean(A);
499  clean(B);
500  clean(C);
501  clean(D);
502 }
503 
512 bool Ed25519::equal(const Point &p, const Point &q)
513 {
514  limb_t a[NUM_LIMBS_256BIT];
515  limb_t b[NUM_LIMBS_256BIT];
516  bool result = true;
517 
518  Curve25519::mul(a, p.x, q.z);
519  Curve25519::mul(b, q.x, p.z);
520  result &= secure_compare(a, b, sizeof(a));
521 
522  Curve25519::mul(a, p.y, q.z);
523  Curve25519::mul(b, q.y, p.z);
524  result &= secure_compare(a, b, sizeof(a));
525 
526  clean(a);
527  clean(b);
528  return result;
529 }
530 
540 void Ed25519::encodePoint(uint8_t *buf, Point &point)
541 {
542  // Convert the homogeneous coordinates into plain (x, y) coordinates:
543  // zinv = z^(-1) mod p
544  // x = x * zinv mod p
545  // y = y * zinv mod p
546  // We don't need the t coordinate, so use that to store zinv temporarily.
547  Curve25519::recip(point.t, point.z);
548  Curve25519::mul(point.x, point.x, point.t);
549  Curve25519::mul(point.y, point.y, point.t);
550 
551  // Copy the lowest bit of x to the highest bit of y.
552  point.y[NUM_LIMBS_256BIT - 1] |= (point.x[0] << (LIMB_BITS - 1));
553 
554  // Convert y into little-endian in the return buffer.
555  BigNumberUtil::packLE(buf, 32, point.y, NUM_LIMBS_256BIT);
556 }
557 
570 bool Ed25519::decodePoint(Point &point, const uint8_t *buf)
571 {
572  limb_t temp[NUM_LIMBS_256BIT];
573 
574  // Convert the input buffer from little-endian into the limbs of y.
575  BigNumberUtil::unpackLE(point.y, NUM_LIMBS_256BIT, buf, 32);
576 
577  // The high bit of y is the sign bit for x.
578  limb_t sign = point.y[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1);
579  point.y[NUM_LIMBS_256BIT - 1] &= ~(((limb_t)1) << (LIMB_BITS - 1));
580 
581  // Set z to 1.
582  memcpy_P(point.z, numBz, sizeof(point.z));
583 
584  // Compute t = (y * y - 1) * modinv(d * y * y + 1).
585  Curve25519::square(point.t, point.y);
586  Curve25519::sub(point.x, point.t, point.z);
587  Curve25519::mul_P(point.t, point.t, numD);
588  Curve25519::add(point.t, point.t, point.z);
589  Curve25519::recip(temp, point.t);
590  Curve25519::mul(point.t, point.x, temp);
591  clean(temp);
592 
593  // Check for t = 0.
594  limb_t check = point.t[0];
595  for (uint8_t posn = 1; posn < NUM_LIMBS_256BIT; ++posn)
596  check |= point.t[posn];
597  if (!check) {
598  // If the sign bit is set, then decoding has failed.
599  // Otherwise x is zero and we're done.
600  if (sign)
601  return false;
602  memset(point.x, 0, sizeof(point.x));
603  return true;
604  }
605 
606  // Recover x by taking the sqrt of t and flipping the sign if necessary.
607  if (!Curve25519::sqrt(point.x, point.t))
608  return false;
609  if (sign != (point.x[0] & ((limb_t)1))) {
610  // The signs are different so we want the other square root.
611  memset(point.t, 0, sizeof(point.t));
612  Curve25519::sub(point.x, point.t, point.x);
613  }
614 
615  // Finally, t = x * y.
616  Curve25519::mul(point.t, point.x, point.y);
617  return true;
618 }
619 
630 void Ed25519::deriveKeys(SHA512 *hash, limb_t *a, const uint8_t privateKey[32])
631 {
632  // Hash the private key to get the "a" scalar and the message prefix.
633  uint8_t *buf = (uint8_t *)(hash->state.w); // Reuse hash buffer to save memory.
634  hash->reset();
635  hash->update(privateKey, 32);
636  hash->finalize(buf, 0);
637  buf[0] &= 0xF8;
638  buf[31] &= 0x7F;
639  buf[31] |= 0x40;
640 
641  // Unpack the first half of the hash value into "a".
642  BigNumberUtil::unpackLE(a, NUM_LIMBS_256BIT, buf, 32);
643 }
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 generatePrivateKey(uint8_t privateKey[32])
Generates a private key for Ed25519 signing operations.
Definition: Ed25519.cpp:243
static limb_t add(limb_t *result, const limb_t *x, const limb_t *y, size_t size)
Adds two big numbers.
void rand(uint8_t *data, size_t len)
Generates random bytes into a caller-supplied buffer.
Definition: RNG.cpp:508
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.
Definition: Ed25519.cpp:189
SHA-512 hash algorithm.
Definition: SHA512.h:30
void reset()
Resets the hash ready for a new hashing process.
Definition: SHA512.cpp:66
void update(const void *data, size_t len)
Updates the hash with more data.
Definition: SHA512.cpp:79
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 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 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.
void finalize(void *hash, size_t len)
Finalizes the hashing process and returns the hash.
Definition: SHA512.cpp:105
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 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.
Definition: Ed25519.cpp:127
static void derivePublicKey(uint8_t publicKey[32], const uint8_t privateKey[32])
Derives the public key from a private key.
Definition: Ed25519.cpp:256