blob: 381beff54270995ac082f62f9e9eb563e7fe1790 [file] [log] [blame]
Jarno Lamsa18987a42019-04-24 15:40:43 +03001/* ecc.c - TinyCrypt implementation of common ECC functions */
2
3/*
Simon Butcher92c3d1f2019-09-09 17:25:08 +01004 * Copyright (c) 2019, Arm Limited (or its affiliates), All Rights Reserved.
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8/*
Jarno Lamsa18987a42019-04-24 15:40:43 +03009 * Copyright (c) 2014, Kenneth MacKay
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 * * Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions are met:
35 *
36 * - Redistributions of source code must retain the above copyright notice,
37 * this list of conditions and the following disclaimer.
38 *
39 * - Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 *
43 * - Neither the name of Intel Corporation nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57 * POSSIBILITY OF SUCH DAMAGE.
58 */
59
Hanno Becker36ae7582019-07-23 15:52:35 +010060#if !defined(MBEDTLS_CONFIG_FILE)
61#include "mbedtls/config.h"
62#else
63#include MBEDTLS_CONFIG_FILE
64#endif
65
Manuel Pégourié-Gonnardafdc1b52019-05-09 11:24:11 +020066#if defined(MBEDTLS_USE_TINYCRYPT)
Jarno Lamsa18987a42019-04-24 15:40:43 +030067#include <tinycrypt/ecc.h>
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +010068#include "mbedtls/platform_util.h"
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +010069#include "mbedtls/sha256.h"
Jarno Lamsa18987a42019-04-24 15:40:43 +030070#include <string.h>
71
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +010072/* Parameters for curve NIST P-256 aka secp256r1 */
73const uECC_word_t curve_p[NUM_ECC_WORDS] = {
74 BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
75 BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00),
76 BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
77 BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF)
78};
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +010079const uECC_word_t curve_n[NUM_ECC_WORDS] = {
80 BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3),
81 BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC),
82 BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
83 BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF)
84};
Manuel Pégourié-Gonnarda6115082019-11-21 10:29:14 +010085const uECC_word_t curve_G[2 * NUM_ECC_WORDS] = {
86 BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4),
87 BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77),
88 BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8),
89 BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B),
90 BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB),
91 BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B),
92 BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E),
93 BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F)
94};
Manuel Pégourié-Gonnardffd13992019-11-21 10:39:06 +010095const uECC_word_t curve_b[NUM_ECC_WORDS] = {
96 BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B),
97 BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65),
98 BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3),
99 BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A)
100};
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100101
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100102static int uECC_update_param_sha256(mbedtls_sha256_context *ctx,
103 const uECC_word_t val[NUM_ECC_WORDS])
104{
105 uint8_t bytes[NUM_ECC_BYTES];
106
107 uECC_vli_nativeToBytes(bytes, NUM_ECC_BYTES, val);
108 return mbedtls_sha256_update_ret(ctx, bytes, NUM_ECC_BYTES);
109}
110
111static int uECC_compute_param_sha256(unsigned char output[32])
112{
113 int ret = UECC_FAILURE;
114 mbedtls_sha256_context ctx;
115
116 mbedtls_sha256_init( &ctx );
117
118 if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) {
119 goto exit;
120 }
121
122 if (uECC_update_param_sha256(&ctx, curve_p) != 0 ||
123 uECC_update_param_sha256(&ctx, curve_n) != 0 ||
124 uECC_update_param_sha256(&ctx, curve_G) != 0 ||
125 uECC_update_param_sha256(&ctx, curve_G + NUM_ECC_WORDS) != 0 ||
126 uECC_update_param_sha256(&ctx, curve_b) != 0)
127 {
128 goto exit;
129 }
130
131 if (mbedtls_sha256_finish_ret(&ctx, output) != 0) {
132 goto exit;
133 }
134
135 ret = UECC_SUCCESS;
136
137exit:
138 mbedtls_sha256_free( &ctx );
139
140 return ret;
141}
142
143/*
144 * Check integrity of curve parameters.
145 * Return 0 if everything's OK, non-zero otherwise.
146 */
147static int uECC_check_curve_integrity(void)
148{
149 unsigned char computed[32];
150 unsigned char reference[32] = {
151 0x2d, 0xa1, 0xa4, 0x64, 0x45, 0x28, 0x0d, 0xe1,
152 0x93, 0xf9, 0x29, 0x2f, 0xac, 0x3e, 0xe2, 0x92,
153 0x76, 0x0a, 0xe2, 0xbc, 0xce, 0x2a, 0xa2, 0xc6,
154 0x38, 0xf2, 0x19, 0x1d, 0x76, 0x72, 0x93, 0x49,
155 };
156 volatile unsigned char diff = 0;
157 unsigned char i;
158
159 if (uECC_compute_param_sha256(computed) != UECC_SUCCESS) {
160 return UECC_FAILURE;
161 }
162
163 for (i = 0; i < 32; i++)
164 diff |= computed[i] ^ reference[i];
165
166 return diff;
167}
168
Jarno Lamsa18987a42019-04-24 15:40:43 +0300169/* IMPORTANT: Make sure a cryptographically-secure PRNG is set and the platform
170 * has access to enough entropy in order to feed the PRNG regularly. */
171#if default_RNG_defined
172static uECC_RNG_Function g_rng_function = &default_CSPRNG;
173#else
174static uECC_RNG_Function g_rng_function = 0;
175#endif
176
177void uECC_set_rng(uECC_RNG_Function rng_function)
178{
179 g_rng_function = rng_function;
180}
181
182uECC_RNG_Function uECC_get_rng(void)
183{
184 return g_rng_function;
185}
186
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +0100187int uECC_curve_private_key_size(void)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300188{
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +0100189 return BITS_TO_BYTES(NUM_ECC_BITS);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300190}
191
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +0100192int uECC_curve_public_key_size(void)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300193{
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +0100194 return 2 * NUM_ECC_BYTES;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300195}
196
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100197void uECC_vli_clear(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300198{
199 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100200 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300201 vli[i] = 0;
202 }
203}
204
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100205uECC_word_t uECC_vli_isZero(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300206{
207 uECC_word_t bits = 0;
208 wordcount_t i;
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100209 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300210 bits |= vli[i];
211 }
212 return (bits == 0);
213}
214
215uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit)
216{
217 return (vli[bit >> uECC_WORD_BITS_SHIFT] &
218 ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));
219}
220
221/* Counts the number of words in vli. */
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100222static wordcount_t vli_numDigits(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300223{
224
225 wordcount_t i;
226 /* Search from the end until we find a non-zero digit. We do it in reverse
227 * because we expect that most digits will be nonzero. */
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100228 for (i = NUM_ECC_WORDS - 1; i >= 0 && vli[i] == 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300229 }
230
231 return (i + 1);
232}
233
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100234bitcount_t uECC_vli_numBits(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300235{
236
237 uECC_word_t i;
238 uECC_word_t digit;
239
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100240 wordcount_t num_digits = vli_numDigits(vli);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300241 if (num_digits == 0) {
242 return 0;
243 }
244
245 digit = vli[num_digits - 1];
246 for (i = 0; digit; ++i) {
247 digit >>= 1;
248 }
249
250 return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);
251}
252
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100253void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300254{
255 wordcount_t i;
256
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100257 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300258 dest[i] = src[i];
259 }
260}
261
262cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100263 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300264{
265 wordcount_t i;
266
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100267 for (i = NUM_ECC_WORDS - 1; i >= 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300268 if (left[i] > right[i]) {
269 return 1;
270 } else if (left[i] < right[i]) {
271 return -1;
272 }
273 }
274 return 0;
275}
276
Manuel Pégourié-Gonnard2eca3d32019-11-04 14:33:09 +0100277uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300278{
279
280 uECC_word_t diff = 0;
281 wordcount_t i;
282
Manuel Pégourié-Gonnard2eca3d32019-11-04 14:33:09 +0100283 for (i = NUM_ECC_WORDS - 1; i >= 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300284 diff |= (left[i] ^ right[i]);
285 }
Manuel Pégourié-Gonnard2b6312b2019-11-06 10:42:02 +0100286 return diff;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300287}
288
289uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond)
290{
291 return (p_true*(cond)) | (p_false*(!cond));
292}
293
294/* Computes result = left - right, returning borrow, in constant time.
295 * Can modify in place. */
296uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100297 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300298{
299 uECC_word_t borrow = 0;
300 wordcount_t i;
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100301 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300302 uECC_word_t diff = left[i] - right[i] - borrow;
303 uECC_word_t val = (diff > left[i]);
304 borrow = cond_set(val, borrow, (diff != left[i]));
305
306 result[i] = diff;
307 }
308 return borrow;
309}
310
311/* Computes result = left + right, returning carry, in constant time.
312 * Can modify in place. */
313static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100314 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300315{
316 uECC_word_t carry = 0;
317 wordcount_t i;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100318 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300319 uECC_word_t sum = left[i] + right[i] + carry;
320 uECC_word_t val = (sum < left[i]);
321 carry = cond_set(val, carry, (sum != left[i]));
322 result[i] = sum;
323 }
324 return carry;
325}
326
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +0100327cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300328{
329 uECC_word_t tmp[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100330 uECC_word_t neg = !!uECC_vli_sub(tmp, left, right);
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100331 uECC_word_t equal = uECC_vli_isZero(tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300332 return (!equal - 2 * neg);
333}
334
335/* Computes vli = vli >> 1. */
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100336static void uECC_vli_rshift1(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300337{
338 uECC_word_t *end = vli;
339 uECC_word_t carry = 0;
340
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100341 vli += NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300342 while (vli-- > end) {
343 uECC_word_t temp = *vli;
344 *vli = (temp >> 1) | carry;
345 carry = temp << (uECC_WORD_BITS - 1);
346 }
347}
348
Manuel Pégourié-Gonnard86c4f812019-10-31 13:02:03 +0100349/* Compute a * b + r, where r is a double-word with high-order word r1 and
350 * low-order word r0, and store the result in the same double-word (r1, r0),
351 * with the carry bit stored in r2.
352 *
353 * (r2, r1, r0) = a * b + (r1, r0):
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200354 * [in] a, b: operands to be multiplied
355 * [in] r0, r1: low and high-order words of operand to add
356 * [out] r0, r1: low and high-order words of the result
357 * [out] r2: carry
358 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300359static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0,
360 uECC_word_t *r1, uECC_word_t *r2)
361{
362
363 uECC_dword_t p = (uECC_dword_t)a * b;
364 uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
365 r01 += p;
366 *r2 += (r01 < p);
367 *r1 = r01 >> uECC_WORD_BITS;
368 *r0 = (uECC_word_t)r01;
369
370}
371
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200372/* State for implementing random delays in uECC_vli_mult_rnd().
373 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100374 * The state is initialized by randomizing delays and setting i = 0.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200375 * Each call to uECC_vli_mult_rnd() uses one byte of delays and increments i.
376 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100377 * Randomized vli multiplication is used only for point operations
378 * (XYcZ_add_rnd() * and XYcZ_addC_rnd()) in scalar multiplication
379 * (ECCPoint_mult()). Those go in pair, and each pair does 14 calls to
380 * uECC_vli_mult_rnd() (6 in XYcZ_add_rnd() and 8 in XYcZ_addC_rnd(),
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100381 * indirectly through uECC_vli_modMult_rnd().
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100382 *
383 * Considering this, in order to minimize the number of calls to the RNG
384 * (which impact performance) while keeping the size of the structure low,
385 * make room for 14 randomized vli mults, which corresponds to one step in the
386 * scalar multiplication routine.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200387 */
388typedef struct {
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100389 uint8_t i;
390 uint8_t delays[14];
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100391} ecc_wait_state_t;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200392
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100393/*
394 * Reset wait_state so that it's ready to be used.
395 */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100396void ecc_wait_state_reset(ecc_wait_state_t *ws)
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100397{
398 if (ws == NULL)
399 return;
400
401 ws->i = 0;
402 g_rng_function(ws->delays, sizeof(ws->delays));
403}
404
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200405/* Computes result = left * right. Result must be 2 * num_words long.
406 *
407 * As a counter-measure against horizontal attacks, add noise by performing
408 * a random number of extra computations performing random additional accesses
409 * to limbs of the input.
410 *
411 * Each of the two actual computation loops is surrounded by two
412 * similar-looking waiting loops, to make the beginning and end of the actual
413 * computation harder to spot.
414 *
415 * We add 4 waiting loops of between 0 and 3 calls to muladd() each. That
416 * makes an average of 6 extra calls. Compared to the main computation which
417 * makes 64 such calls, this represents an average performance degradation of
418 * less than 10%.
419 *
420 * Compared to the original uECC_vli_mult(), loose the num_words argument as we
421 * know it's always 8. This saves a bit of code size and execution speed.
422 */
423static void uECC_vli_mult_rnd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100424 const uECC_word_t *right, ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300425{
426
427 uECC_word_t r0 = 0;
428 uECC_word_t r1 = 0;
429 uECC_word_t r2 = 0;
430 wordcount_t i, k;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100431 const uint8_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200432
433 /* Fetch 8 bit worth of delay from the state; 0 if we have no state */
434 uint8_t delays = s ? s->delays[s->i++] : 0;
435 uECC_word_t rr0 = 0, rr1 = 0;
436 volatile uECC_word_t r;
437
438 /* Mimic start of next loop: k in [0, 3] */
439 k = 0 + (delays & 0x03);
440 delays >>= 2;
441 /* k = 0 -> i in [1, 0] -> 0 extra muladd;
442 * k = 3 -> i in [1, 3] -> 3 extra muladd */
Manuel Pégourié-Gonnardc8814862019-11-05 10:32:37 +0100443 for (i = 1; i <= k; ++i) {
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200444 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
445 }
446 r = rr0;
447 rr0 = rr1;
448 rr1 = r2;
449 r2 = 0;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300450
451 /* Compute each digit of result in sequence, maintaining the carries. */
452 for (k = 0; k < num_words; ++k) {
453
454 for (i = 0; i <= k; ++i) {
455 muladd(left[i], right[k - i], &r0, &r1, &r2);
456 }
457
458 result[k] = r0;
459 r0 = r1;
460 r1 = r2;
461 r2 = 0;
462 }
463
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200464 /* Mimic end of previous loop: k in [4, 7] */
465 k = 4 + (delays & 0x03);
466 delays >>= 2;
467 /* k = 4 -> i in [5, 4] -> 0 extra muladd;
468 * k = 7 -> i in [5, 7] -> 3 extra muladd */
469 for (i = 5; i <= k; ++i) {
470 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
471 }
472 r = rr0;
473 rr0 = rr1;
474 rr1 = r2;
475 r2 = 0;
476
477 /* Mimic start of next loop: k in [8, 11] */
478 k = 11 - (delays & 0x03);
479 delays >>= 2;
480 /* k = 8 -> i in [5, 7] -> 3 extra muladd;
481 * k = 11 -> i in [8, 7] -> 0 extra muladd */
482 for (i = (k + 5) - num_words; i < num_words; ++i) {
483 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
484 }
485 r = rr0;
486 rr0 = rr1;
487 rr1 = r2;
488 r2 = 0;
489
Jarno Lamsa18987a42019-04-24 15:40:43 +0300490 for (k = num_words; k < num_words * 2 - 1; ++k) {
491
492 for (i = (k + 1) - num_words; i < num_words; ++i) {
493 muladd(left[i], right[k - i], &r0, &r1, &r2);
494 }
495 result[k] = r0;
496 r0 = r1;
497 r1 = r2;
498 r2 = 0;
499 }
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200500
Jarno Lamsa18987a42019-04-24 15:40:43 +0300501 result[num_words * 2 - 1] = r0;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200502
503 /* Mimic end of previous loop: k in [12, 15] */
504 k = 15 - (delays & 0x03);
505 delays >>= 2;
506 /* k = 12 -> i in [5, 7] -> 3 extra muladd;
507 * k = 15 -> i in [8, 7] -> 0 extra muladd */
508 for (i = (k + 1) - num_words; i < num_words; ++i) {
509 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
510 }
511 r = rr0;
512 rr0 = rr1;
513 rr1 = r2;
514 r2 = 0;
515
516 /* avoid warning that r is set but not used */
517 (void) r;
518}
519
Jarno Lamsa18987a42019-04-24 15:40:43 +0300520void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard0779be72019-11-04 14:48:22 +0100521 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300522{
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100523 uECC_word_t carry = uECC_vli_add(result, left, right);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100524 if (carry || uECC_vli_cmp_unsafe(mod, result) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300525 /* result > mod (result = mod + remainder), so subtract mod to get
526 * remainder. */
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100527 uECC_vli_sub(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300528 }
529}
530
531void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard1b0875d2019-11-04 14:50:54 +0100532 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300533{
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100534 uECC_word_t l_borrow = uECC_vli_sub(result, left, right);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300535 if (l_borrow) {
536 /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
537 * we can get the correct result from result + mod (with overflow). */
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100538 uECC_vli_add(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300539 }
540}
541
542/* Computes result = product % mod, where product is 2N words long. */
543/* Currently only designed to work for curve_p or curve_n. */
544void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100545 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300546{
547 uECC_word_t mod_multiple[2 * NUM_ECC_WORDS];
548 uECC_word_t tmp[2 * NUM_ECC_WORDS];
549 uECC_word_t *v[2] = {tmp, product};
550 uECC_word_t index;
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100551 const wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300552
553 /* Shift mod so its highest set bit is at the maximum position. */
554 bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) -
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100555 uECC_vli_numBits(mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300556 wordcount_t word_shift = shift / uECC_WORD_BITS;
557 wordcount_t bit_shift = shift % uECC_WORD_BITS;
558 uECC_word_t carry = 0;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100559 uECC_vli_clear(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300560 if (bit_shift > 0) {
561 for(index = 0; index < (uECC_word_t)num_words; ++index) {
562 mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;
563 carry = mod[index] >> (uECC_WORD_BITS - bit_shift);
564 }
565 } else {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100566 uECC_vli_set(mod_multiple + word_shift, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300567 }
568
569 for (index = 1; shift >= 0; --shift) {
570 uECC_word_t borrow = 0;
571 wordcount_t i;
572 for (i = 0; i < num_words * 2; ++i) {
573 uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;
574 if (diff != v[index][i]) {
575 borrow = (diff > v[index][i]);
576 }
577 v[1 - index][i] = diff;
578 }
579 /* Swap the index if there was no borrow */
580 index = !(index ^ borrow);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100581 uECC_vli_rshift1(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300582 mod_multiple[num_words - 1] |= mod_multiple[num_words] <<
583 (uECC_WORD_BITS - 1);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100584 uECC_vli_rshift1(mod_multiple + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300585 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100586 uECC_vli_set(result, v[index]);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300587}
588
589void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard3e20adf2019-11-04 15:00:43 +0100590 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300591{
592 uECC_word_t product[2 * NUM_ECC_WORDS];
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100593 uECC_vli_mult_rnd(product, left, right, NULL);
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100594 uECC_vli_mmod(result, product, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300595}
596
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100597static void uECC_vli_modMult_rnd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100598 const uECC_word_t *right, ecc_wait_state_t *s)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100599{
600 uECC_word_t product[2 * NUM_ECC_WORDS];
601 uECC_vli_mult_rnd(product, left, right, s);
602
603 vli_mmod_fast_secp256r1(result, product);
604}
605
Jarno Lamsa18987a42019-04-24 15:40:43 +0300606void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100607 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300608{
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100609 uECC_vli_modMult_rnd(result, left, right, NULL);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300610}
611
Jarno Lamsa18987a42019-04-24 15:40:43 +0300612#define EVEN(vli) (!(vli[0] & 1))
613
614static void vli_modInv_update(uECC_word_t *uv,
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100615 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300616{
617
618 uECC_word_t carry = 0;
619
620 if (!EVEN(uv)) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100621 carry = uECC_vli_add(uv, uv, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300622 }
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100623 uECC_vli_rshift1(uv);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300624 if (carry) {
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100625 uv[NUM_ECC_WORDS - 1] |= HIGH_BIT_SET;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300626 }
627}
628
629void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100630 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300631{
632 uECC_word_t a[NUM_ECC_WORDS], b[NUM_ECC_WORDS];
633 uECC_word_t u[NUM_ECC_WORDS], v[NUM_ECC_WORDS];
634 cmpresult_t cmpResult;
635
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100636 if (uECC_vli_isZero(input)) {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100637 uECC_vli_clear(result);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300638 return;
639 }
640
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100641 uECC_vli_set(a, input);
642 uECC_vli_set(b, mod);
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100643 uECC_vli_clear(u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300644 u[0] = 1;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100645 uECC_vli_clear(v);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100646 while ((cmpResult = uECC_vli_cmp_unsafe(a, b)) != 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300647 if (EVEN(a)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100648 uECC_vli_rshift1(a);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100649 vli_modInv_update(u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300650 } else if (EVEN(b)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100651 uECC_vli_rshift1(b);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100652 vli_modInv_update(v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300653 } else if (cmpResult > 0) {
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100654 uECC_vli_sub(a, a, b);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100655 uECC_vli_rshift1(a);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100656 if (uECC_vli_cmp_unsafe(u, v) < 0) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100657 uECC_vli_add(u, u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300658 }
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100659 uECC_vli_sub(u, u, v);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100660 vli_modInv_update(u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300661 } else {
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100662 uECC_vli_sub(b, b, a);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100663 uECC_vli_rshift1(b);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100664 if (uECC_vli_cmp_unsafe(v, u) < 0) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100665 uECC_vli_add(v, v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300666 }
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100667 uECC_vli_sub(v, v, u);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100668 vli_modInv_update(v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300669 }
670 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100671 uECC_vli_set(result, u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300672}
673
674/* ------ Point operations ------ */
675
676void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100677 uECC_word_t * Z1)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300678{
679 /* t1 = X, t2 = Y, t3 = Z */
680 uECC_word_t t4[NUM_ECC_WORDS];
681 uECC_word_t t5[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +0100682 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300683
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100684 if (uECC_vli_isZero(Z1)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300685 return;
686 }
687
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100688 uECC_vli_modMult_fast(t4, Y1, Y1); /* t4 = y1^2 */
689 uECC_vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */
690 uECC_vli_modMult_fast(t4, t4, t4); /* t4 = y1^4 */
691 uECC_vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */
692 uECC_vli_modMult_fast(Z1, Z1, Z1); /* t3 = z1^2 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300693
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100694 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */
695 uECC_vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */
696 uECC_vli_modSub(Z1, X1, Z1, curve_p); /* t3 = x1 - z1^2 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100697 uECC_vli_modMult_fast(X1, X1, Z1); /* t1 = x1^2 - z1^4 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300698
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100699 uECC_vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */
700 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300701 if (uECC_vli_testBit(X1, 0)) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100702 uECC_word_t l_carry = uECC_vli_add(X1, X1, curve_p);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100703 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300704 X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
705 } else {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100706 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300707 }
708
709 /* t1 = 3/2*(x1^2 - z1^4) = B */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100710 uECC_vli_modMult_fast(Z1, X1, X1); /* t3 = B^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100711 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - A */
712 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */
713 uECC_vli_modSub(t5, t5, Z1, curve_p); /* t5 = A - x3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100714 uECC_vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300715 /* t4 = B * (A - x3) - y1^4 = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100716 uECC_vli_modSub(t4, X1, t4, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300717
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100718 uECC_vli_set(X1, Z1);
719 uECC_vli_set(Z1, Y1);
720 uECC_vli_set(Y1, t4);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300721}
722
Manuel Pégourié-Gonnard1c6f7ea2019-11-21 09:18:29 +0100723/*
724 * @brief Computes x^3 + ax + b. result must not overlap x.
725 * @param result OUT -- x^3 + ax + b
726 * @param x IN -- value of x
727 * @param curve IN -- elliptic curve
728 */
729static void x_side_default(uECC_word_t *result,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100730 const uECC_word_t *x)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300731{
732 uECC_word_t _3[NUM_ECC_WORDS] = {3}; /* -a = 3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300733
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100734 uECC_vli_modMult_fast(result, x, x); /* r = x^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100735 uECC_vli_modSub(result, result, _3, curve_p); /* r = x^2 - 3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100736 uECC_vli_modMult_fast(result, result, x); /* r = x^3 - 3x */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300737 /* r = x^3 - 3x + b: */
Manuel Pégourié-Gonnardffd13992019-11-21 10:39:06 +0100738 uECC_vli_modAdd(result, result, curve_b, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300739}
740
Jarno Lamsa18987a42019-04-24 15:40:43 +0300741void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int*product)
742{
743 unsigned int tmp[NUM_ECC_WORDS];
744 int carry;
745
746 /* t */
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100747 uECC_vli_set(result, product);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300748
749 /* s1 */
750 tmp[0] = tmp[1] = tmp[2] = 0;
751 tmp[3] = product[11];
752 tmp[4] = product[12];
753 tmp[5] = product[13];
754 tmp[6] = product[14];
755 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100756 carry = uECC_vli_add(tmp, tmp, tmp);
757 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300758
759 /* s2 */
760 tmp[3] = product[12];
761 tmp[4] = product[13];
762 tmp[5] = product[14];
763 tmp[6] = product[15];
764 tmp[7] = 0;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100765 carry += uECC_vli_add(tmp, tmp, tmp);
766 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300767
768 /* s3 */
769 tmp[0] = product[8];
770 tmp[1] = product[9];
771 tmp[2] = product[10];
772 tmp[3] = tmp[4] = tmp[5] = 0;
773 tmp[6] = product[14];
774 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100775 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300776
777 /* s4 */
778 tmp[0] = product[9];
779 tmp[1] = product[10];
780 tmp[2] = product[11];
781 tmp[3] = product[13];
782 tmp[4] = product[14];
783 tmp[5] = product[15];
784 tmp[6] = product[13];
785 tmp[7] = product[8];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100786 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300787
788 /* d1 */
789 tmp[0] = product[11];
790 tmp[1] = product[12];
791 tmp[2] = product[13];
792 tmp[3] = tmp[4] = tmp[5] = 0;
793 tmp[6] = product[8];
794 tmp[7] = product[10];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100795 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300796
797 /* d2 */
798 tmp[0] = product[12];
799 tmp[1] = product[13];
800 tmp[2] = product[14];
801 tmp[3] = product[15];
802 tmp[4] = tmp[5] = 0;
803 tmp[6] = product[9];
804 tmp[7] = product[11];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100805 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300806
807 /* d3 */
808 tmp[0] = product[13];
809 tmp[1] = product[14];
810 tmp[2] = product[15];
811 tmp[3] = product[8];
812 tmp[4] = product[9];
813 tmp[5] = product[10];
814 tmp[6] = 0;
815 tmp[7] = product[12];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100816 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300817
818 /* d4 */
819 tmp[0] = product[14];
820 tmp[1] = product[15];
821 tmp[2] = 0;
822 tmp[3] = product[9];
823 tmp[4] = product[10];
824 tmp[5] = product[11];
825 tmp[6] = 0;
826 tmp[7] = product[13];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100827 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300828
829 if (carry < 0) {
830 do {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100831 carry += uECC_vli_add(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300832 }
833 while (carry < 0);
834 } else {
835 while (carry ||
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100836 uECC_vli_cmp_unsafe(curve_p, result) != 1) {
837 carry -= uECC_vli_sub(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300838 }
839 }
840}
841
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100842uECC_word_t EccPoint_isZero(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300843{
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100844 return uECC_vli_isZero(point);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300845}
846
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100847void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300848{
849 uECC_word_t t1[NUM_ECC_WORDS];
850
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100851 uECC_vli_modMult_fast(t1, Z, Z); /* z^2 */
852 uECC_vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */
853 uECC_vli_modMult_fast(t1, t1, Z); /* z^3 */
854 uECC_vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300855}
856
857/* P = (x1, y1) => 2P, (x2, y2) => P' */
858static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1,
859 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100860 const uECC_word_t * const initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300861{
862 uECC_word_t z[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300863 if (initial_Z) {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100864 uECC_vli_set(z, initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300865 } else {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100866 uECC_vli_clear(z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300867 z[0] = 1;
868 }
869
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100870 uECC_vli_set(X2, X1);
871 uECC_vli_set(Y2, Y1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300872
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100873 apply_z(X1, Y1, z);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100874 double_jacobian_default(X1, Y1, z);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100875 apply_z(X2, Y2, z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300876}
877
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100878static void XYcZ_add_rnd(uECC_word_t * X1, uECC_word_t * Y1,
879 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100880 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300881{
882 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
883 uECC_word_t t5[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100884
885 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100886 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100887 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
888 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100889 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100890 uECC_vli_modMult_rnd(t5, Y2, Y2, s); /* t5 = (y2 - y1)^2 = D */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300891
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100892 uECC_vli_modSub(t5, t5, X1, curve_p); /* t5 = D - B */
893 uECC_vli_modSub(t5, t5, X2, curve_p); /* t5 = D - B - C = x3 */
894 uECC_vli_modSub(X2, X2, X1, curve_p); /* t3 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100895 uECC_vli_modMult_rnd(Y1, Y1, X2, s); /* t2 = y1*(C - B) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100896 uECC_vli_modSub(X2, X1, t5, curve_p); /* t3 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100897 uECC_vli_modMult_rnd(Y2, Y2, X2, s); /* t4 = (y2 - y1)*(B - x3) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100898 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300899
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100900 uECC_vli_set(X2, t5);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300901}
902
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100903void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100904 uECC_word_t * X2, uECC_word_t * Y2)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100905{
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100906 XYcZ_add_rnd(X1, Y1, X2, Y2, NULL);
907}
908
Jarno Lamsa18987a42019-04-24 15:40:43 +0300909/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
910 Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
911 or P => P - Q, Q => P + Q
912 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100913static void XYcZ_addC_rnd(uECC_word_t * X1, uECC_word_t * Y1,
914 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100915 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300916{
917 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
918 uECC_word_t t5[NUM_ECC_WORDS];
919 uECC_word_t t6[NUM_ECC_WORDS];
920 uECC_word_t t7[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100921
922 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100923 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100924 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
925 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100926 uECC_vli_modAdd(t5, Y2, Y1, curve_p); /* t5 = y2 + y1 */
927 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300928
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100929 uECC_vli_modSub(t6, X2, X1, curve_p); /* t6 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100930 uECC_vli_modMult_rnd(Y1, Y1, t6, s); /* t2 = y1 * (C - B) = E */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100931 uECC_vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100932 uECC_vli_modMult_rnd(X2, Y2, Y2, s); /* t3 = (y2 - y1)^2 = D */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100933 uECC_vli_modSub(X2, X2, t6, curve_p); /* t3 = D - (B + C) = x3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300934
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100935 uECC_vli_modSub(t7, X1, X2, curve_p); /* t7 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100936 uECC_vli_modMult_rnd(Y2, Y2, t7, s); /* t4 = (y2 - y1)*(B - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300937 /* t4 = (y2 - y1)*(B - x3) - E = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100938 uECC_vli_modSub(Y2, Y2, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300939
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100940 uECC_vli_modMult_rnd(t7, t5, t5, s); /* t7 = (y2 + y1)^2 = F */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100941 uECC_vli_modSub(t7, t7, t6, curve_p); /* t7 = F - (B + C) = x3' */
942 uECC_vli_modSub(t6, t7, X1, curve_p); /* t6 = x3' - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100943 uECC_vli_modMult_rnd(t6, t6, t5, s); /* t6 = (y2+y1)*(x3' - B) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300944 /* t2 = (y2+y1)*(x3' - B) - E = y3': */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100945 uECC_vli_modSub(Y1, t6, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300946
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100947 uECC_vli_set(X1, t7);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300948}
949
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +0100950static void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point,
Jarno Lamsa18987a42019-04-24 15:40:43 +0300951 const uECC_word_t * scalar,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +0100952 const uECC_word_t * initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300953{
954 /* R0 and R1 */
955 uECC_word_t Rx[2][NUM_ECC_WORDS];
956 uECC_word_t Ry[2][NUM_ECC_WORDS];
957 uECC_word_t z[NUM_ECC_WORDS];
958 bitcount_t i;
959 uECC_word_t nb;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100960 const wordcount_t num_words = NUM_ECC_WORDS;
961 const bitcount_t num_bits = NUM_ECC_BITS + 1; /* from regularize_k */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100962 ecc_wait_state_t wait_state;
963 ecc_wait_state_t * const ws = g_rng_function ? &wait_state : NULL;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300964
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100965 uECC_vli_set(Rx[1], point);
966 uECC_vli_set(Ry[1], point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300967
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100968 XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300969
970 for (i = num_bits - 2; i > 0; --i) {
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100971 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300972 nb = !uECC_vli_testBit(scalar, i);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100973 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
974 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300975 }
976
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100977 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300978 nb = !uECC_vli_testBit(scalar, 0);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100979 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300980
981 /* Find final 1/Z value. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100982 uECC_vli_modSub(z, Rx[1], Rx[0], curve_p); /* X1 - X0 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100983 uECC_vli_modMult_fast(z, z, Ry[1 - nb]); /* Yb * (X1 - X0) */
984 uECC_vli_modMult_fast(z, z, point); /* xP * Yb * (X1 - X0) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100985 uECC_vli_modInv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0))*/
Jarno Lamsa18987a42019-04-24 15:40:43 +0300986 /* yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100987 uECC_vli_modMult_fast(z, z, point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300988 /* Xb * yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100989 uECC_vli_modMult_fast(z, z, Rx[1 - nb]);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300990 /* End 1/Z calculation */
991
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100992 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100993 apply_z(Rx[0], Ry[0], z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300994
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100995 uECC_vli_set(result, Rx[0]);
996 uECC_vli_set(result + num_words, Ry[0]);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300997}
998
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +0100999static uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001000 uECC_word_t *k1)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001001{
1002
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001003 wordcount_t num_n_words = NUM_ECC_WORDS;
1004 bitcount_t num_n_bits = NUM_ECC_BITS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001005
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001006 uECC_word_t carry = uECC_vli_add(k0, k, curve_n) ||
Jarno Lamsa18987a42019-04-24 15:40:43 +03001007 (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) &&
1008 uECC_vli_testBit(k0, num_n_bits));
1009
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001010 uECC_vli_add(k1, k0, curve_n);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001011
1012 return carry;
1013}
1014
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001015int EccPoint_mult_safer(uECC_word_t * result, const uECC_word_t * point,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001016 const uECC_word_t * scalar)
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001017{
1018 uECC_word_t tmp[NUM_ECC_WORDS];
1019 uECC_word_t s[NUM_ECC_WORDS];
1020 uECC_word_t *k2[2] = {tmp, s};
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001021 wordcount_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001022 uECC_word_t carry;
1023 uECC_word_t *initial_Z = 0;
1024 int r;
1025
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001026 /* Protect against faults modifying curve paremeters in flash */
1027 if (uECC_check_curve_integrity() != 0) {
1028 return 0;
1029 }
1030
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001031 /* Protects against invalid curves attacks */
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001032 if (uECC_valid_point(point) != 0 ) {
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001033 return 0;
1034 }
1035
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001036 /* Regularize the bitcount for the private key so that attackers cannot use a
1037 * side channel attack to learn the number of leading zeros. */
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001038 carry = regularize_k(scalar, tmp, s);
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001039
1040 /* If an RNG function was specified, get a random initial Z value to
1041 * protect against side-channel attacks such as Template SPA */
1042 if (g_rng_function) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001043 if (!uECC_generate_random_int(k2[carry], curve_p, num_words)) {
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001044 r = 0;
1045 goto clear_and_out;
1046 }
1047 initial_Z = k2[carry];
1048 }
1049
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001050 EccPoint_mult(result, point, k2[!carry], initial_Z);
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001051
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001052 /* Protect against fault injections that would make the resulting
1053 * point not lie on the intended curve */
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001054 if (uECC_valid_point(result) != 0 ) {
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001055 r = 0;
1056 goto clear_and_out;
1057 }
1058
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001059 /* Protect against faults modifying curve paremeters in flash */
1060 if (uECC_check_curve_integrity() != 0) {
1061 r = 0;
1062 goto clear_and_out;
1063 }
1064
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001065 r = 1;
1066
1067clear_and_out:
1068 /* erasing temporary buffer used to store secret: */
1069 mbedtls_platform_zeroize(k2, sizeof(k2));
1070 mbedtls_platform_zeroize(tmp, sizeof(tmp));
1071 mbedtls_platform_zeroize(s, sizeof(s));
1072
1073 return r;
1074}
1075
Jarno Lamsa18987a42019-04-24 15:40:43 +03001076uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001077 uECC_word_t *private_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001078{
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001079 return EccPoint_mult_safer(result, curve_G, private_key);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001080}
1081
1082/* Converts an integer in uECC native format to big-endian bytes. */
1083void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
1084 const unsigned int *native)
1085{
1086 wordcount_t i;
1087 for (i = 0; i < num_bytes; ++i) {
1088 unsigned b = num_bytes - 1 - i;
1089 bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE));
1090 }
1091}
1092
1093/* Converts big-endian bytes to an integer in uECC native format. */
1094void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes,
1095 int num_bytes)
1096{
1097 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +01001098 uECC_vli_clear(native);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001099 for (i = 0; i < num_bytes; ++i) {
1100 unsigned b = num_bytes - 1 - i;
1101 native[b / uECC_WORD_SIZE] |=
1102 (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE));
1103 }
1104}
1105
1106int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
1107 wordcount_t num_words)
1108{
1109 uECC_word_t mask = (uECC_word_t)-1;
1110 uECC_word_t tries;
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +01001111 bitcount_t num_bits = uECC_vli_numBits(top);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001112
1113 if (!g_rng_function) {
1114 return 0;
1115 }
1116
1117 for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
1118 if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) {
1119 return 0;
1120 }
1121 random[num_words - 1] &=
1122 mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits));
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001123 if (!uECC_vli_isZero(random) &&
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +01001124 uECC_vli_cmp(top, random) == 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001125 return 1;
1126 }
1127 }
1128 return 0;
1129}
1130
1131
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001132int uECC_valid_point(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001133{
1134 uECC_word_t tmp1[NUM_ECC_WORDS];
1135 uECC_word_t tmp2[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001136 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001137
1138 /* The point at infinity is invalid. */
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001139 if (EccPoint_isZero(point)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001140 return -1;
1141 }
1142
1143 /* x and y must be smaller than p. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001144 if (uECC_vli_cmp_unsafe(curve_p, point) != 1 ||
1145 uECC_vli_cmp_unsafe(curve_p, point + num_words) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001146 return -2;
1147 }
1148
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001149 uECC_vli_modMult_fast(tmp1, point + num_words, point + num_words);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001150 x_side_default(tmp2, point); /* tmp2 = x^3 + ax + b */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001151
1152 /* Make sure that y^2 == x^3 + ax + b */
Manuel Pégourié-Gonnard2eca3d32019-11-04 14:33:09 +01001153 if (uECC_vli_equal(tmp1, tmp2) != 0)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001154 return -3;
1155
1156 return 0;
1157}
1158
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001159int uECC_valid_public_key(const uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001160{
1161
1162 uECC_word_t _public[NUM_ECC_WORDS * 2];
1163
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001164 uECC_vli_bytesToNative(_public, public_key, NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001165 uECC_vli_bytesToNative(
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001166 _public + NUM_ECC_WORDS,
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001167 public_key + NUM_ECC_BYTES,
1168 NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001169
Manuel Pégourié-Gonnarda6115082019-11-21 10:29:14 +01001170 if (memcmp(_public, curve_G, NUM_ECC_WORDS * 2) == 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001171 return -4;
1172 }
1173
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001174 return uECC_valid_point(_public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001175}
1176
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001177int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001178{
1179
1180 uECC_word_t _private[NUM_ECC_WORDS];
1181 uECC_word_t _public[NUM_ECC_WORDS * 2];
1182
1183 uECC_vli_bytesToNative(
1184 _private,
1185 private_key,
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +01001186 BITS_TO_BYTES(NUM_ECC_BITS));
Jarno Lamsa18987a42019-04-24 15:40:43 +03001187
1188 /* Make sure the private key is in the range [1, n-1]. */
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001189 if (uECC_vli_isZero(_private)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001190 return 0;
1191 }
1192
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001193 if (uECC_vli_cmp(curve_n, _private) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001194 return 0;
1195 }
1196
1197 /* Compute public key. */
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001198 if (!EccPoint_compute_public_key(_public, _private)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001199 return 0;
1200 }
1201
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001202 uECC_vli_nativeToBytes(public_key, NUM_ECC_BYTES, _public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001203 uECC_vli_nativeToBytes(
1204 public_key +
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001205 NUM_ECC_BYTES, NUM_ECC_BYTES, _public + NUM_ECC_WORDS);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001206 return 1;
1207}
Jarno Lamsa46132202019-04-29 14:29:52 +03001208#else
Manuel Pégourié-Gonnardafdc1b52019-05-09 11:24:11 +02001209typedef int mbedtls_dummy_tinycrypt_def;
1210#endif /* MBEDTLS_USE_TINYCRYPT */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001211