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 }