• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ecc.c - TinyCrypt implementation of common ECC functions */
2 
3 /*
4  * Copyright (c) 2014, Kenneth MacKay
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  * * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
22  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  *  Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
27  *
28  *  Redistribution and use in source and binary forms, with or without
29  *  modification, are permitted provided that the following conditions are met:
30  *
31  *    - Redistributions of source code must retain the above copyright notice,
32  *     this list of conditions and the following disclaimer.
33  *
34  *    - Redistributions in binary form must reproduce the above copyright
35  *    notice, this list of conditions and the following disclaimer in the
36  *    documentation and/or other materials provided with the distribution.
37  *
38  *    - Neither the name of Intel Corporation nor the names of its contributors
39  *    may be used to endorse or promote products derived from this software
40  *    without specific prior written permission.
41  *
42  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
46  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
47  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
48  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
49  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
50  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
52  *  POSSIBILITY OF SUCH DAMAGE.
53  */
54 
55 #include <tinycrypt/ecc.h>
56 #include <tinycrypt/ecc_platform_specific.h>
57 #include <string.h>
58 
59 /* IMPORTANT: Make sure a cryptographically-secure PRNG is set and the platform
60  * has access to enough entropy in order to feed the PRNG regularly. */
61 #if default_RNG_defined
62 static uECC_RNG_Function g_rng_function = &default_CSPRNG;
63 #else
64 static uECC_RNG_Function g_rng_function = 0;
65 #endif
66 
uECC_set_rng(uECC_RNG_Function rng_function)67 void uECC_set_rng(uECC_RNG_Function rng_function)
68 {
69     g_rng_function = rng_function;
70 }
71 
uECC_get_rng(void)72 uECC_RNG_Function uECC_get_rng(void)
73 {
74     return g_rng_function;
75 }
76 
uECC_curve_private_key_size(uECC_Curve curve)77 int uECC_curve_private_key_size(uECC_Curve curve)
78 {
79     return BITS_TO_BYTES(curve->num_n_bits);
80 }
81 
uECC_curve_public_key_size(uECC_Curve curve)82 int uECC_curve_public_key_size(uECC_Curve curve)
83 {
84     return 2 * curve->num_bytes; // 2:byte alignment
85 }
86 
uECC_vli_clear(uECC_word_t * vli,wordcount_t num_words)87 void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words)
88 {
89     wordcount_t i;
90 
91     for (i = 0; i < num_words; ++i) {
92         vli[i] = 0;
93     }
94 }
95 
uECC_vli_isZero(const uECC_word_t * vli,wordcount_t num_words)96 uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words)
97 {
98     uECC_word_t bits = 0;
99     wordcount_t i;
100 
101     for (i = 0; i < num_words; ++i) {
102         bits |= vli[i];
103     }
104     return (bits == 0);
105 }
106 
uECC_vli_testBit(const uECC_word_t * vli,bitcount_t bit)107 uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit)
108 {
109     return (vli[bit >> uECC_WORD_BITS_SHIFT] &
110             ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));
111 }
112 
113 /* Counts the number of words in vli. */
vli_numDigits(const uECC_word_t * vli,const wordcount_t max_words)114 static wordcount_t vli_numDigits(const uECC_word_t *vli,
115                                  const wordcount_t max_words)
116 {
117     wordcount_t i;
118 
119     /* Search from the end until we find a non-zero digit. We do it in reverse
120      * because we expect that most digits will be nonzero. */
121     for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) {
122     }
123     return (i + 1);
124 }
125 
uECC_vli_numBits(const uECC_word_t * vli,const wordcount_t max_words)126 bitcount_t uECC_vli_numBits(const uECC_word_t *vli,
127                             const wordcount_t max_words)
128 {
129     uECC_word_t i;
130     uECC_word_t digit;
131     wordcount_t num_digits = vli_numDigits(vli, max_words);
132     if (num_digits == 0) {
133         return 0;
134     }
135 
136     digit = vli[num_digits - 1];
137 
138     for (i = 0; digit; ++i) {
139         digit >>= 1;
140     }
141 
142     return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);
143 }
144 
uECC_vli_set(uECC_word_t * dest,const uECC_word_t * src,wordcount_t num_words)145 void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src,
146                   wordcount_t num_words)
147 {
148     wordcount_t i;
149 
150     for (i = 0; i < num_words; ++i) {
151         dest[i] = src[i];
152     }
153 }
154 
uECC_vli_cmp_unsafe(const uECC_word_t * left,const uECC_word_t * right,wordcount_t num_words)155 cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
156                                 const uECC_word_t *right,
157                                 wordcount_t num_words)
158 {
159     wordcount_t i;
160 
161     for (i = num_words - 1; i >= 0; --i) {
162         if (left[i] > right[i]) {
163             return 1;
164         } else if (left[i] < right[i]) {
165             return -1;
166         }
167     }
168 
169     return 0;
170 }
171 
uECC_vli_equal(const uECC_word_t * left,const uECC_word_t * right,wordcount_t num_words)172 uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right,
173                            wordcount_t num_words)
174 {
175     uECC_word_t diff = 0;
176     wordcount_t i;
177 
178     for (i = num_words - 1; i >= 0; --i) {
179         diff |= (left[i] ^ right[i]);
180     }
181 
182     return !(diff == 0);
183 }
184 
cond_set(uECC_word_t p_true,uECC_word_t p_false,unsigned int cond)185 uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond)
186 {
187     return (p_true * (cond)) | (p_false * (!cond));
188 }
189 
190 /* Computes result = left - right, returning borrow, in constant time.
191  * Can modify in place. */
uECC_vli_sub(uECC_word_t * result,const uECC_word_t * left,const uECC_word_t * right,wordcount_t num_words)192 uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
193                          const uECC_word_t *right, wordcount_t num_words)
194 {
195     uECC_word_t borrow = 0;
196     wordcount_t i;
197 
198     for (i = 0; i < num_words; ++i) {
199         uECC_word_t diff = left[i] - right[i] - borrow;
200         uECC_word_t val = (diff > left[i]);
201         borrow = cond_set(val, borrow, (diff != left[i]));
202         result[i] = diff;
203     }
204 
205     return borrow;
206 }
207 
208 /* Computes result = left + right, returning carry, in constant time.
209  * Can modify in place. */
uECC_vli_add(uECC_word_t * result,const uECC_word_t * left,const uECC_word_t * right,wordcount_t num_words)210 static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
211                                 const uECC_word_t *right, wordcount_t num_words)
212 {
213     uECC_word_t carry = 0;
214     wordcount_t i;
215 
216     for (i = 0; i < num_words; ++i) {
217         uECC_word_t sum = left[i] + right[i] + carry;
218         uECC_word_t val = (sum < left[i]);
219         carry = cond_set(val, carry, (sum != left[i]));
220         result[i] = sum;
221     }
222 
223     return carry;
224 }
225 
uECC_vli_cmp(const uECC_word_t * left,const uECC_word_t * right,wordcount_t num_words)226 cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right,
227                          wordcount_t num_words)
228 {
229     uECC_word_t tmp[NUM_ECC_WORDS];
230     uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words);
231     uECC_word_t equal = uECC_vli_isZero(tmp, num_words);
232     return (!equal - 2 * neg); // 2:byte alignment
233 }
234 
235 /* Computes vli = vli >> 1. */
uECC_vli_rshift1(uECC_word_t * vli,wordcount_t num_words)236 static void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words)
237 {
238     uECC_word_t *end = vli;
239     uECC_word_t carry = 0;
240     vli += num_words;
241 
242     while (vli-- > end) {
243         uECC_word_t temp = *vli;
244         *vli = (temp >> 1) | carry;
245         carry = temp << (uECC_WORD_BITS - 1);
246     }
247 }
248 
muladd(uECC_word_t a,uECC_word_t b,uECC_word_t * r0,uECC_word_t * r1,uECC_word_t * r2)249 static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0,
250                    uECC_word_t *r1, uECC_word_t *r2)
251 {
252     uECC_dword_t p = (uECC_dword_t)a * b;
253     uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
254     r01 += p;
255     *r2 += (r01 < p);
256     *r1 = r01 >> uECC_WORD_BITS;
257     *r0 = (uECC_word_t)r01;
258 }
259 
260 /* Computes result = left * right. Result must be 2 * num_words long. */
uECC_vli_mult(uECC_word_t * result,const uECC_word_t * left,const uECC_word_t * right,wordcount_t num_words)261 static void uECC_vli_mult(uECC_word_t *result, const uECC_word_t *left,
262                           const uECC_word_t *right, wordcount_t num_words)
263 {
264     uECC_word_t r0 = 0;
265     uECC_word_t r1 = 0;
266     uECC_word_t r2 = 0;
267     wordcount_t i, k;
268 
269     /* Compute each digit of result in sequence, maintaining the carries. */
270     for (k = 0; k < num_words; ++k) {
271         for (i = 0; i <= k; ++i) {
272             muladd(left[i], right[k - i], &r0, &r1, &r2);
273         }
274 
275         result[k] = r0;
276         r0 = r1;
277         r1 = r2;
278         r2 = 0;
279     }
280 
281     for (k = num_words; k < num_words * 2 - 1; ++k) {
282         for (i = (k + 1) - num_words; i < num_words; ++i) {
283             muladd(left[i], right[k - i], &r0, &r1, &r2);
284         }
285 
286         result[k] = r0;
287         r0 = r1;
288         r1 = r2;
289         r2 = 0;
290     }
291 
292     result[num_words * 2 - 1] = r0; // 2:byte alignment
293 }
294 
uECC_vli_modAdd(uECC_word_t * result,const uECC_word_t * left,const uECC_word_t * right,const uECC_word_t * mod,wordcount_t num_words)295 void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
296                      const uECC_word_t *right, const uECC_word_t *mod,
297                      wordcount_t num_words)
298 {
299     uECC_word_t carry = uECC_vli_add(result, left, right, num_words);
300     if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) {
301         /* result > mod (result = mod + remainder), so subtract mod to get
302          * remainder. */
303         uECC_vli_sub(result, result, mod, num_words);
304     }
305 }
306 
uECC_vli_modSub(uECC_word_t * result,const uECC_word_t * left,const uECC_word_t * right,const uECC_word_t * mod,wordcount_t num_words)307 void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
308                      const uECC_word_t *right, const uECC_word_t *mod,
309                      wordcount_t num_words)
310 {
311     uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words);
312     if (l_borrow) {
313         /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
314          * we can get the correct result from result + mod (with overflow). */
315         uECC_vli_add(result, result, mod, num_words);
316     }
317 }
318 
319 /* Computes result = product % mod, where product is 2N words long. */
320 /* Currently only designed to work for curve_p or curve_n. */
uECC_vli_mmod(uECC_word_t * result,uECC_word_t * product,const uECC_word_t * mod,wordcount_t num_words)321 void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
322                    const uECC_word_t *mod, wordcount_t num_words)
323 {
324     uECC_word_t mod_multiple[2 * NUM_ECC_WORDS]; // 2:byte alignment
325     uECC_word_t tmp[2 * NUM_ECC_WORDS]; // 2:byte alignment
326     uECC_word_t *v[2] = {tmp, product}; // 2:array element
327     uECC_word_t index;
328     /* Shift mod so its highest set bit is at the maximum position. */
329     bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) - // 2:byte alignment
330                        uECC_vli_numBits(mod, num_words);
331     wordcount_t word_shift = shift / uECC_WORD_BITS;
332     wordcount_t bit_shift = shift % uECC_WORD_BITS;
333     uECC_word_t carry = 0;
334     uECC_vli_clear(mod_multiple, word_shift);
335 
336     if (bit_shift > 0) {
337         for (index = 0; index < (uECC_word_t)num_words; ++index) {
338             mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;
339             carry = mod[index] >> (uECC_WORD_BITS - bit_shift);
340         }
341     } else {
342         uECC_vli_set(mod_multiple + word_shift, mod, num_words);
343     }
344 
345     for (index = 1; shift >= 0; --shift) {
346         uECC_word_t borrow = 0;
347         wordcount_t i;
348 
349         for (i = 0; i < num_words * 2; ++i) { // 2:byte alignment
350             uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;
351 
352             if (diff != v[index][i]) {
353                 borrow = (diff > v[index][i]);
354             }
355 
356             v[1 - index][i] = diff;
357         }
358 
359         /* Swap the index if there was no borrow */
360         index = !(index ^ borrow);
361         uECC_vli_rshift1(mod_multiple, num_words);
362         mod_multiple[num_words - 1] |= mod_multiple[num_words] <<
363                                        (uECC_WORD_BITS - 1);
364         uECC_vli_rshift1(mod_multiple + num_words, num_words);
365     }
366 
367     uECC_vli_set(result, v[index], num_words);
368 }
369 
uECC_vli_modMult(uECC_word_t * result,const uECC_word_t * left,const uECC_word_t * right,const uECC_word_t * mod,wordcount_t num_words)370 void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
371                       const uECC_word_t *right, const uECC_word_t *mod,
372                       wordcount_t num_words)
373 {
374     uECC_word_t product[2 * NUM_ECC_WORDS]; // 2:byte alignment
375     uECC_vli_mult(product, left, right, num_words);
376     uECC_vli_mmod(result, product, mod, num_words);
377 }
378 
uECC_vli_modMult_fast(uECC_word_t * result,const uECC_word_t * left,const uECC_word_t * right,uECC_Curve curve)379 void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
380                            const uECC_word_t *right, uECC_Curve curve)
381 {
382     uECC_word_t product[2 * NUM_ECC_WORDS]; // 2:byte alignment
383     uECC_vli_mult(product, left, right, curve->num_words);
384     curve->mmod_fast(result, product);
385 }
386 
uECC_vli_modSquare_fast(uECC_word_t * result,const uECC_word_t * left,uECC_Curve curve)387 static void uECC_vli_modSquare_fast(uECC_word_t *result,
388                                     const uECC_word_t *left,
389                                     uECC_Curve curve)
390 {
391     uECC_vli_modMult_fast(result, left, left, curve);
392 }
393 
394 #define EVEN(vli) (!((vli)[0] & 1))
395 
vli_modInv_update(uECC_word_t * uv,const uECC_word_t * mod,wordcount_t num_words)396 static void vli_modInv_update(uECC_word_t *uv,
397                               const uECC_word_t *mod,
398                               wordcount_t num_words)
399 {
400     uECC_word_t carry = 0;
401 
402     if (!EVEN(uv)) {
403         carry = uECC_vli_add(uv, uv, mod, num_words);
404     }
405 
406     uECC_vli_rshift1(uv, num_words);
407 
408     if (carry) {
409         uv[num_words - 1] |= HIGH_BIT_SET;
410     }
411 }
412 
uECC_vli_modInv(uECC_word_t * result,const uECC_word_t * input,const uECC_word_t * mod,wordcount_t num_words)413 void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
414                      const uECC_word_t *mod, wordcount_t num_words)
415 {
416     uECC_word_t a[NUM_ECC_WORDS], b[NUM_ECC_WORDS];
417     uECC_word_t u[NUM_ECC_WORDS], v[NUM_ECC_WORDS];
418     cmpresult_t cmpResult;
419 
420     if (uECC_vli_isZero(input, num_words)) {
421         uECC_vli_clear(result, num_words);
422         return;
423     }
424 
425     uECC_vli_set(a, input, num_words);
426     uECC_vli_set(b, mod, num_words);
427     uECC_vli_clear(u, num_words);
428     u[0] = 1;
429     uECC_vli_clear(v, num_words);
430 
431     while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) {
432         if (EVEN(a)) {
433             uECC_vli_rshift1(a, num_words);
434             vli_modInv_update(u, mod, num_words);
435         } else if (EVEN(b)) {
436             uECC_vli_rshift1(b, num_words);
437             vli_modInv_update(v, mod, num_words);
438         } else if (cmpResult > 0) {
439             uECC_vli_sub(a, a, b, num_words);
440             uECC_vli_rshift1(a, num_words);
441 
442             if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) {
443                 uECC_vli_add(u, u, mod, num_words);
444             }
445 
446             uECC_vli_sub(u, u, v, num_words);
447             vli_modInv_update(u, mod, num_words);
448         } else {
449             uECC_vli_sub(b, b, a, num_words);
450             uECC_vli_rshift1(b, num_words);
451 
452             if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) {
453                 uECC_vli_add(v, v, mod, num_words);
454             }
455 
456             uECC_vli_sub(v, v, u, num_words);
457             vli_modInv_update(v, mod, num_words);
458         }
459     }
460 
461     uECC_vli_set(result, u, num_words);
462 }
463 
464 /* ------ Point operations ------ */
465 
double_jacobian_default(uECC_word_t * X1,uECC_word_t * Y1,uECC_word_t * Z1,uECC_Curve curve)466 void double_jacobian_default(uECC_word_t *X1, uECC_word_t *Y1,
467                              uECC_word_t *Z1, uECC_Curve curve)
468 {
469     /* t1 = X, t2 = Y, t3 = Z */
470     uECC_word_t t4[NUM_ECC_WORDS];
471     uECC_word_t t5[NUM_ECC_WORDS];
472     wordcount_t num_words = curve->num_words;
473 
474     if (uECC_vli_isZero(Z1, num_words)) {
475         return;
476     }
477 
478     uECC_vli_modSquare_fast(t4, Y1, curve);   /* t4 = y1^2 */
479     uECC_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */
480     uECC_vli_modSquare_fast(t4, t4, curve);   /* t4 = y1^4 */
481     uECC_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */
482     uECC_vli_modSquare_fast(Z1, Z1, curve);   /* t3 = z1^2 */
483     uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */
484     uECC_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */
485     uECC_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */
486     uECC_vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */
487     uECC_vli_modAdd(Z1, X1, X1, curve->p, num_words); /* t3 = 2*(x1^2 - z1^4) */
488     uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = 3*(x1^2 - z1^4) */
489 
490     if (uECC_vli_testBit(X1, 0)) {
491         uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words);
492         uECC_vli_rshift1(X1, num_words);
493         X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
494     } else {
495         uECC_vli_rshift1(X1, num_words);
496     }
497 
498     /* t1 = 3/2*(x1^2 - z1^4) = B */
499     uECC_vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */
500     uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */
501     uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */
502     uECC_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */
503     uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */
504     /* t4 = B * (A - x3) - y1^4 = y3: */
505     uECC_vli_modSub(t4, X1, t4, curve->p, num_words);
506     uECC_vli_set(X1, Z1, num_words);
507     uECC_vli_set(Z1, Y1, num_words);
508     uECC_vli_set(Y1, t4, num_words);
509 }
510 
x_side_default(uECC_word_t * result,const uECC_word_t * x,uECC_Curve curve)511 void x_side_default(uECC_word_t *result,
512                     const uECC_word_t *x,
513                     uECC_Curve curve)
514 {
515     uECC_word_t _3[NUM_ECC_WORDS] = {3}; // 3:-a
516     wordcount_t num_words = curve->num_words;
517     uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */
518     uECC_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */
519     uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */
520     /* r = x^3 - 3x + b: */
521     uECC_vli_modAdd(result, result, curve->b, curve->p, num_words);
522 }
523 
uECC_secp256r1(void)524 uECC_Curve uECC_secp256r1(void)
525 {
526     return &curve_secp256r1;
527 }
528 
vli_mmod_fast_secp256r1(unsigned int * result,unsigned int * product)529 void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int *product)
530 {
531     unsigned int tmp[NUM_ECC_WORDS];
532     int carry;
533     /* t */
534     uECC_vli_set(result, product, NUM_ECC_WORDS);
535     /* s1 */
536     tmp[0] = tmp[1] = tmp[2] = 0; // 2:array element
537     tmp[3] = product[11]; // 3:array element, 11:array element
538     tmp[4] = product[12]; // 4:array element, 12:array element
539     tmp[5] = product[13]; // 5:array element, 13:array element
540     tmp[6] = product[14]; // 6:array element, 14:array element
541     tmp[7] = product[15]; // 7:array element, 15:array element
542     carry = uECC_vli_add(tmp, tmp, tmp, NUM_ECC_WORDS);
543     carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS);
544     /* s2 */
545     tmp[3] = product[12]; // 3:array element, 12:array element
546     tmp[4] = product[13]; // 4:array element, 13:array element
547     tmp[5] = product[14]; // 5:array element, 14:array element
548     tmp[6] = product[15]; // 6:array element, 15:array element
549     tmp[7] = 0; // 7:array element
550     carry += uECC_vli_add(tmp, tmp, tmp, NUM_ECC_WORDS);
551     carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS);
552     /* s3 */
553     tmp[0] = product[8]; // 8:array element
554     tmp[1] = product[9]; // 9:array element
555     tmp[2] = product[10]; // 2:array element, 10:array element
556     tmp[3] = tmp[4] = tmp[5] = 0; // 3:array element, 4:array element, 5:array element
557     tmp[6] = product[14]; // 6:array element, 14:array element
558     tmp[7] = product[15]; // 7:array element, 15:array element
559     carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS);
560     /* s4 */
561     tmp[0] = product[9]; // 9:array element
562     tmp[1] = product[10]; // 10:array element
563     tmp[2] = product[11]; // 2:array element, 11:array element
564     tmp[3] = product[13]; // 3:array element, 13:array element
565     tmp[4] = product[14]; // 4:array element, 14:array element
566     tmp[5] = product[15]; // 5:array element, 15:array element
567     tmp[6] = product[13]; // 6:array element, 13:array element
568     tmp[7] = product[8]; // 7:array element, 8:array element
569     carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS);
570     /* d1 */
571     tmp[0] = product[11]; // 11:array element
572     tmp[1] = product[12]; // 12:array element
573     tmp[2] = product[13]; // 2:array element, 13:array element
574     tmp[3] = tmp[4] = tmp[5] = 0; // 3:array element, 4:array element, 5:array element
575     tmp[6] = product[8]; // 6:array element, 8:array element
576     tmp[7] = product[10]; // 7:array element, 10:array element
577     carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS);
578     /* d2 */
579     tmp[0] = product[12]; // 12:array element
580     tmp[1] = product[13]; // 13:array element
581     tmp[2] = product[14]; // 2:array element, 14:array element
582     tmp[3] = product[15]; // 3:array element, 15:array element
583     tmp[4] = tmp[5] = 0; // 4:array element, 5:array element
584     tmp[6] = product[9]; // 6:array element, 9:array element
585     tmp[7] = product[11]; // 7:array element, 11:array element
586     carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS);
587     /* d3 */
588     tmp[0] = product[13]; // 13:array element
589     tmp[1] = product[14]; // 14:array element
590     tmp[2] = product[15]; // 2:array element, 15:array element
591     tmp[3] = product[8]; // 3:array element, 8:array element
592     tmp[4] = product[9]; // 4:array element, 9:array element
593     tmp[5] = product[10]; // 5:array element, 10:array element
594     tmp[6] = 0; // 6:array element
595     tmp[7] = product[12]; // 7:array element, 12:array element
596     carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS);
597     /* d4 */
598     tmp[0] = product[14]; // 14:array element
599     tmp[1] = product[15]; // 1:array element, 15:array element
600     tmp[2] = 0; // 2:array element
601     tmp[3] = product[9]; // 3:array element, 9:array element
602     tmp[4] = product[10]; // 4:array element, 10:array element
603     tmp[5] = product[11]; // 5:array element, 11:array element
604     tmp[6] = 0; // 6:array element
605     tmp[7] = product[13]; // 7:array element, 13:array element
606     carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS);
607     if (carry < 0) {
608         do {
609             carry += uECC_vli_add(result, result, curve_secp256r1.p, NUM_ECC_WORDS);
610         } while (carry < 0);
611     } else  {
612         while (carry ||
613                 uECC_vli_cmp_unsafe(curve_secp256r1.p, result, NUM_ECC_WORDS) != 1) {
614             carry -= uECC_vli_sub(result, result, curve_secp256r1.p, NUM_ECC_WORDS);
615         }
616     }
617 }
618 
EccPoint_isZero(const uECC_word_t * point,uECC_Curve curve)619 uECC_word_t EccPoint_isZero(const uECC_word_t *point, uECC_Curve curve)
620 {
621     return uECC_vli_isZero(point, curve->num_words * 2); // 2:byte alignment
622 }
623 
apply_z(uECC_word_t * X1,uECC_word_t * Y1,const uECC_word_t * const Z,uECC_Curve curve)624 void apply_z(uECC_word_t *X1, uECC_word_t *Y1, const uECC_word_t *const Z,
625              uECC_Curve curve)
626 {
627     uECC_word_t t1[NUM_ECC_WORDS];
628     uECC_vli_modSquare_fast(t1, Z, curve);    /* z^2 */
629     uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */
630     uECC_vli_modMult_fast(t1, t1, Z, curve);  /* z^3 */
631     uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */
632 }
633 
634 /* P = (x1, y1) => 2P, (x2, y2) => P' */
XYcZ_initial_double(uECC_word_t * X1,uECC_word_t * Y1,uECC_word_t * X2,uECC_word_t * Y2,const uECC_word_t * const initial_Z,uECC_Curve curve)635 static void XYcZ_initial_double(uECC_word_t *X1, uECC_word_t *Y1,
636                                 uECC_word_t *X2, uECC_word_t *Y2,
637                                 const uECC_word_t *const initial_Z,
638                                 uECC_Curve curve)
639 {
640     uECC_word_t z[NUM_ECC_WORDS];
641     wordcount_t num_words = curve->num_words;
642 
643     if (initial_Z) {
644         uECC_vli_set(z, initial_Z, num_words);
645     } else {
646         uECC_vli_clear(z, num_words);
647         z[0] = 1;
648     }
649 
650     uECC_vli_set(X2, X1, num_words);
651     uECC_vli_set(Y2, Y1, num_words);
652     apply_z(X1, Y1, z, curve);
653     curve->double_jacobian(X1, Y1, z, curve);
654     apply_z(X2, Y2, z, curve);
655 }
656 
XYcZ_add(uECC_word_t * X1,uECC_word_t * Y1,uECC_word_t * X2,uECC_word_t * Y2,uECC_Curve curve)657 void XYcZ_add(uECC_word_t *X1, uECC_word_t *Y1,
658               uECC_word_t *X2, uECC_word_t *Y2,
659               uECC_Curve curve)
660 {
661     /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
662     uECC_word_t t5[NUM_ECC_WORDS];
663     wordcount_t num_words = curve->num_words;
664     uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */
665     uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */
666     uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */
667     uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */
668     uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */
669     uECC_vli_modSquare_fast(t5, Y2, curve); /* t5 = (y2 - y1)^2 = D */
670     uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */
671     uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */
672     uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */
673     uECC_vli_modMult_fast(Y1, Y1, X2, curve); /* t2 = y1*(C - B) */
674     uECC_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */
675     uECC_vli_modMult_fast(Y2, Y2, X2, curve); /* t4 = (y2 - y1)*(B - x3) */
676     uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */
677     uECC_vli_set(X2, t5, num_words);
678 }
679 
680 /* Input P = (x1, y1, Z), Q = (x2, y2, Z)
681    Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
682    or P => P - Q, Q => P + Q
683  */
XYcZ_addC(uECC_word_t * X1,uECC_word_t * Y1,uECC_word_t * X2,uECC_word_t * Y2,uECC_Curve curve)684 static void XYcZ_addC(uECC_word_t *X1, uECC_word_t *Y1,
685                       uECC_word_t *X2, uECC_word_t *Y2,
686                       uECC_Curve curve)
687 {
688     /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
689     uECC_word_t t5[NUM_ECC_WORDS];
690     uECC_word_t t6[NUM_ECC_WORDS];
691     uECC_word_t t7[NUM_ECC_WORDS];
692     wordcount_t num_words = curve->num_words;
693     uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */
694     uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */
695     uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */
696     uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */
697     uECC_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */
698     uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */
699     uECC_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */
700     uECC_vli_modMult_fast(Y1, Y1, t6, curve); /* t2 = y1 * (C - B) = E */
701     uECC_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */
702     uECC_vli_modSquare_fast(X2, Y2, curve); /* t3 = (y2 - y1)^2 = D */
703     uECC_vli_modSub(X2, X2, t6, curve->p, num_words); /* t3 = D - (B + C) = x3 */
704     uECC_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */
705     uECC_vli_modMult_fast(Y2, Y2, t7, curve); /* t4 = (y2 - y1)*(B - x3) */
706     /* t4 = (y2 - y1)*(B - x3) - E = y3: */
707     uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words);
708     uECC_vli_modSquare_fast(t7, t5, curve); /* t7 = (y2 + y1)^2 = F */
709     uECC_vli_modSub(t7, t7, t6, curve->p, num_words); /* t7 = F - (B + C) = x3' */
710     uECC_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */
711     uECC_vli_modMult_fast(t6, t6, t5, curve); /* t6 = (y2+y1)*(x3' - B) */
712     /* t2 = (y2+y1)*(x3' - B) - E = y3': */
713     uECC_vli_modSub(Y1, t6, Y1, curve->p, num_words);
714     uECC_vli_set(X1, t7, num_words);
715 }
716 
EccPoint_mult(uECC_word_t * result,const uECC_word_t * point,const uECC_word_t * scalar,const uECC_word_t * initial_Z,bitcount_t num_bits,uECC_Curve curve)717 void EccPoint_mult(uECC_word_t *result, const uECC_word_t *point,
718                    const uECC_word_t *scalar,
719                    const uECC_word_t *initial_Z,
720                    bitcount_t num_bits, uECC_Curve curve)
721 {
722     /* R0 and R1 */
723     uECC_word_t Rx[2][NUM_ECC_WORDS]; // 2:array element
724     uECC_word_t Ry[2][NUM_ECC_WORDS]; // 2:array element
725     uECC_word_t z[NUM_ECC_WORDS];
726     bitcount_t i;
727     uECC_word_t nb;
728     wordcount_t num_words = curve->num_words;
729     uECC_vli_set(Rx[1], point, num_words);
730     uECC_vli_set(Ry[1], point + num_words, num_words);
731     XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z, curve);
732 
733     for (i = num_bits - 2; i > 0; --i) { // 2:byte alignment
734         nb = !uECC_vli_testBit(scalar, i);
735         XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve);
736         XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve);
737     }
738 
739     nb = !uECC_vli_testBit(scalar, 0);
740     XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve);
741     /* Find final 1/Z value. */
742     uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */
743     uECC_vli_modMult_fast(z, z, Ry[1 - nb], curve); /* Yb * (X1 - X0) */
744     uECC_vli_modMult_fast(z, z, point, curve); /* xP * Yb * (X1 - X0) */
745     uECC_vli_modInv(z, z, curve->p, num_words); /* 1 / (xP * Yb * (X1 - X0)) */
746     /* yP / (xP * Yb * (X1 - X0)) */
747     uECC_vli_modMult_fast(z, z, point + num_words, curve);
748     /* Xb * yP / (xP * Yb * (X1 - X0)) */
749     uECC_vli_modMult_fast(z, z, Rx[1 - nb], curve);
750     /* End 1/Z calculation */
751     XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve);
752     apply_z(Rx[0], Ry[0], z, curve);
753     uECC_vli_set(result, Rx[0], num_words);
754     uECC_vli_set(result + num_words, Ry[0], num_words);
755 }
756 
regularize_k(const uECC_word_t * const k,uECC_word_t * k0,uECC_word_t * k1,uECC_Curve curve)757 uECC_word_t regularize_k(const uECC_word_t *const k, uECC_word_t *k0,
758                          uECC_word_t *k1, uECC_Curve curve)
759 {
760     wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
761     bitcount_t num_n_bits = curve->num_n_bits;
762     uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) ||
763                         (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) && // 8:byte alignment
764                          uECC_vli_testBit(k0, num_n_bits));
765     uECC_vli_add(k1, k0, curve->n, num_n_words);
766     return carry;
767 }
768 
EccPoint_compute_public_key(uECC_word_t * result,uECC_word_t * private_key,uECC_Curve curve)769 uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
770                                         uECC_word_t *private_key,
771                                         uECC_Curve curve)
772 {
773     uECC_word_t tmp1[NUM_ECC_WORDS];
774     uECC_word_t tmp2[NUM_ECC_WORDS];
775     uECC_word_t *p2[2] = {tmp1, tmp2}; // 2:array element
776     uECC_word_t carry;
777     /* Regularize the bitcount for the private key so that attackers cannot
778      * use a side channel attack to learn the number of leading zeros. */
779     carry = regularize_k(private_key, tmp1, tmp2, curve);
780     EccPoint_mult(result, curve->G, p2[!carry], 0, curve->num_n_bits + 1, curve);
781 
782     if (EccPoint_isZero(result, curve)) {
783         return 0;
784     }
785 
786     return 1;
787 }
788 
789 /* Converts an integer in uECC native format to big-endian bytes. */
uECC_vli_nativeToBytes(uint8_t * bytes,int num_bytes,const unsigned int * native)790 void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
791                             const unsigned int *native)
792 {
793     wordcount_t i;
794 
795     for (i = 0; i < num_bytes; ++i) {
796         unsigned b = num_bytes - 1 - i;
797         bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE));
798     }
799 }
800 
801 /* Converts big-endian bytes to an integer in uECC native format. */
uECC_vli_bytesToNative(unsigned int * native,const uint8_t * bytes,int num_bytes)802 void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes,
803                             int num_bytes)
804 {
805     wordcount_t i;
806     uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE);
807 
808     for (i = 0; i < num_bytes; ++i) {
809         unsigned b = num_bytes - 1 - i;
810         native[b / uECC_WORD_SIZE] |=
811                         (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE)); // 8:byte alignment
812     }
813 }
814 
uECC_generate_random_int(uECC_word_t * random,const uECC_word_t * top,wordcount_t num_words)815 int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
816                              wordcount_t num_words)
817 {
818     uECC_word_t mask = (uECC_word_t) -1;
819     uECC_word_t tries;
820     bitcount_t num_bits = uECC_vli_numBits(top, num_words);
821 
822     if (!g_rng_function) {
823         return 0;
824     }
825 
826     for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
827         if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) {
828             return 0;
829         }
830 
831         random[num_words - 1] &=
832                         mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); // 8:byte alignment
833 
834         if (!uECC_vli_isZero(random, num_words) &&
835                 uECC_vli_cmp(top, random, num_words) == 1) {
836             return 1;
837         }
838     }
839 
840     return 0;
841 }
842 
uECC_valid_point(const uECC_word_t * point,uECC_Curve curve)843 int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve)
844 {
845     uECC_word_t tmp1[NUM_ECC_WORDS];
846     uECC_word_t tmp2[NUM_ECC_WORDS];
847     wordcount_t num_words = curve->num_words;
848 
849     /* The point at infinity is invalid. */
850     if (EccPoint_isZero(point, curve)) {
851         return -1;
852     }
853 
854     /* x and y must be smaller than p. */
855     if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 ||
856             uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) {
857         return -2; // -2:return value
858     }
859 
860     uECC_vli_modSquare_fast(tmp1, point + num_words, curve);
861     curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */
862 
863     /* Make sure that y^2 == x^3 + ax + b */
864     if (uECC_vli_equal(tmp1, tmp2, num_words) != 0) {
865         return -3; // -3:return value
866     }
867     return 0;
868 }
869 
uECC_valid_public_key(const uint8_t * public_key,uECC_Curve curve)870 int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve)
871 {
872     uECC_word_t _public[NUM_ECC_WORDS * 2]; // 2:byte alignment
873     uECC_vli_bytesToNative(_public, public_key, curve->num_bytes);
874     uECC_vli_bytesToNative(
875         _public + curve->num_words,
876         public_key + curve->num_bytes,
877         curve->num_bytes);
878 
879     if (uECC_vli_cmp_unsafe(_public, curve->G, NUM_ECC_WORDS * 2) == 0) { // 2:byte alignment
880         return -4; // -4:return value
881     }
882 
883     return uECC_valid_point(_public, curve);
884 }
885 
uECC_compute_public_key(const uint8_t * private_key,uint8_t * public_key,uECC_Curve curve)886 int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key,
887                             uECC_Curve curve)
888 {
889     uECC_word_t _private[NUM_ECC_WORDS];
890     uECC_word_t _public[NUM_ECC_WORDS * 2]; // 2:byte alignment
891     uECC_vli_bytesToNative(
892         _private,
893         private_key,
894         BITS_TO_BYTES(curve->num_n_bits));
895 
896     /* Make sure the private key is in the range [1, n-1]. */
897     if (uECC_vli_isZero(_private, BITS_TO_WORDS(curve->num_n_bits))) {
898         return 0;
899     }
900 
901     if (uECC_vli_cmp(curve->n, _private, BITS_TO_WORDS(curve->num_n_bits)) != 1) {
902         return 0;
903     }
904 
905     /* Compute public key. */
906     if (!EccPoint_compute_public_key(_public, _private, curve)) {
907         return 0;
908     }
909 
910     uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public);
911     uECC_vli_nativeToBytes(
912         public_key +
913         curve->num_bytes, curve->num_bytes, _public + curve->num_words);
914     return 1;
915 }