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