blob: 8f2cf0e55255bbb1347b2158263abb32026b6989 [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
Jarno Lamsa18987a42019-04-24 15:40:43 +030066#include <tinycrypt/ecc.h>
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +010067#include "mbedtls/platform_util.h"
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +010068#include "mbedtls/sha256.h"
Jarno Lamsa18987a42019-04-24 15:40:43 +030069#include <string.h>
70
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +010071/* Parameters for curve NIST P-256 aka secp256r1 */
72const uECC_word_t curve_p[NUM_ECC_WORDS] = {
73 BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
74 BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00),
75 BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
76 BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF)
77};
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +010078const uECC_word_t curve_n[NUM_ECC_WORDS] = {
79 BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3),
80 BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC),
81 BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
82 BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF)
83};
Manuel Pégourié-Gonnarda6115082019-11-21 10:29:14 +010084const uECC_word_t curve_G[2 * NUM_ECC_WORDS] = {
85 BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4),
86 BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77),
87 BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8),
88 BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B),
89 BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB),
90 BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B),
91 BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E),
92 BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F)
93};
Manuel Pégourié-Gonnardffd13992019-11-21 10:39:06 +010094const uECC_word_t curve_b[NUM_ECC_WORDS] = {
95 BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B),
96 BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65),
97 BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3),
98 BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A)
99};
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100100
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100101static int uECC_update_param_sha256(mbedtls_sha256_context *ctx,
102 const uECC_word_t val[NUM_ECC_WORDS])
103{
104 uint8_t bytes[NUM_ECC_BYTES];
105
106 uECC_vli_nativeToBytes(bytes, NUM_ECC_BYTES, val);
107 return mbedtls_sha256_update_ret(ctx, bytes, NUM_ECC_BYTES);
108}
109
110static int uECC_compute_param_sha256(unsigned char output[32])
111{
112 int ret = UECC_FAILURE;
113 mbedtls_sha256_context ctx;
114
115 mbedtls_sha256_init( &ctx );
116
117 if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) {
118 goto exit;
119 }
120
121 if (uECC_update_param_sha256(&ctx, curve_p) != 0 ||
122 uECC_update_param_sha256(&ctx, curve_n) != 0 ||
123 uECC_update_param_sha256(&ctx, curve_G) != 0 ||
124 uECC_update_param_sha256(&ctx, curve_G + NUM_ECC_WORDS) != 0 ||
125 uECC_update_param_sha256(&ctx, curve_b) != 0)
126 {
127 goto exit;
128 }
129
130 if (mbedtls_sha256_finish_ret(&ctx, output) != 0) {
131 goto exit;
132 }
133
134 ret = UECC_SUCCESS;
135
136exit:
137 mbedtls_sha256_free( &ctx );
138
139 return ret;
140}
141
142/*
143 * Check integrity of curve parameters.
144 * Return 0 if everything's OK, non-zero otherwise.
145 */
146static int uECC_check_curve_integrity(void)
147{
148 unsigned char computed[32];
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100149 static const unsigned char reference[32] = {
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100150 0x2d, 0xa1, 0xa4, 0x64, 0x45, 0x28, 0x0d, 0xe1,
151 0x93, 0xf9, 0x29, 0x2f, 0xac, 0x3e, 0xe2, 0x92,
152 0x76, 0x0a, 0xe2, 0xbc, 0xce, 0x2a, 0xa2, 0xc6,
153 0x38, 0xf2, 0x19, 0x1d, 0x76, 0x72, 0x93, 0x49,
154 };
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100155 unsigned char diff = 0;
156 unsigned char tmp1, tmp2;
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100157 volatile unsigned i;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100158
159 if (uECC_compute_param_sha256(computed) != UECC_SUCCESS) {
160 return UECC_FAILURE;
161 }
162
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100163 for (i = 0; i < 32; i++) {
164 /* make sure the order of volatile accesses is well-defined */
165 tmp1 = computed[i];
166 tmp2 = reference[i];
167 diff |= tmp1 ^ tmp2;
168 }
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100169
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100170 /* i should be 32 */
Arto Kinnunenac6d2262020-01-09 10:11:20 +0200171 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100172 diff |= (unsigned char) i ^ 32;
173
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100174 return diff;
175}
176
Jarno Lamsa18987a42019-04-24 15:40:43 +0300177/* IMPORTANT: Make sure a cryptographically-secure PRNG is set and the platform
178 * has access to enough entropy in order to feed the PRNG regularly. */
179#if default_RNG_defined
180static uECC_RNG_Function g_rng_function = &default_CSPRNG;
181#else
182static uECC_RNG_Function g_rng_function = 0;
183#endif
184
185void uECC_set_rng(uECC_RNG_Function rng_function)
186{
187 g_rng_function = rng_function;
188}
189
190uECC_RNG_Function uECC_get_rng(void)
191{
192 return g_rng_function;
193}
194
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +0100195int uECC_curve_private_key_size(void)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300196{
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +0100197 return BITS_TO_BYTES(NUM_ECC_BITS);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300198}
199
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +0100200int uECC_curve_public_key_size(void)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300201{
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +0100202 return 2 * NUM_ECC_BYTES;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300203}
204
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100205void uECC_vli_clear(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300206{
207 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100208 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300209 vli[i] = 0;
210 }
211}
212
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100213uECC_word_t uECC_vli_isZero(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300214{
215 uECC_word_t bits = 0;
216 wordcount_t i;
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100217 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300218 bits |= vli[i];
219 }
220 return (bits == 0);
221}
222
223uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit)
224{
225 return (vli[bit >> uECC_WORD_BITS_SHIFT] &
226 ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));
227}
228
229/* Counts the number of words in vli. */
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100230static wordcount_t vli_numDigits(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300231{
232
233 wordcount_t i;
234 /* Search from the end until we find a non-zero digit. We do it in reverse
235 * because we expect that most digits will be nonzero. */
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100236 for (i = NUM_ECC_WORDS - 1; i >= 0 && vli[i] == 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300237 }
238
239 return (i + 1);
240}
241
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100242bitcount_t uECC_vli_numBits(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300243{
244
245 uECC_word_t i;
246 uECC_word_t digit;
247
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100248 wordcount_t num_digits = vli_numDigits(vli);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300249 if (num_digits == 0) {
250 return 0;
251 }
252
253 digit = vli[num_digits - 1];
254 for (i = 0; digit; ++i) {
255 digit >>= 1;
256 }
257
258 return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);
259}
260
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100261void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300262{
263 wordcount_t i;
264
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100265 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300266 dest[i] = src[i];
267 }
268}
269
270cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100271 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300272{
273 wordcount_t i;
274
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100275 for (i = NUM_ECC_WORDS - 1; i >= 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300276 if (left[i] > right[i]) {
277 return 1;
278 } else if (left[i] < right[i]) {
279 return -1;
280 }
281 }
282 return 0;
283}
284
Manuel Pégourié-Gonnard2eca3d32019-11-04 14:33:09 +0100285uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300286{
287
288 uECC_word_t diff = 0;
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200289 uECC_word_t flow_monitor = 0;
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100290 uECC_word_t tmp1, tmp2;
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100291 volatile int i;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300292
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200293 int start_offset = mbedtls_platform_random_in_range(NUM_ECC_WORDS);
294
295 for (i = start_offset; i < NUM_ECC_WORDS; ++i) {
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100296 tmp1 = left[i];
297 tmp2 = right[i];
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200298 flow_monitor++;
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100299 diff |= (tmp1 ^ tmp2);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300300 }
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100301
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200302 for (i = 0; i < start_offset; ++i) {
303 tmp1 = left[i];
304 tmp2 = right[i];
305 flow_monitor++;
306 diff |= (tmp1 ^ tmp2);
307 }
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100308
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200309 mbedtls_platform_random_delay();
310
311 /* Return 0 only when diff is 0 and flow_counter is equal to NUM_ECC_WORDS */
312 return (diff | (flow_monitor ^ NUM_ECC_WORDS));
Jarno Lamsa18987a42019-04-24 15:40:43 +0300313}
314
315uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond)
316{
317 return (p_true*(cond)) | (p_false*(!cond));
318}
319
320/* Computes result = left - right, returning borrow, in constant time.
321 * Can modify in place. */
322uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100323 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300324{
325 uECC_word_t borrow = 0;
326 wordcount_t i;
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100327 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300328 uECC_word_t diff = left[i] - right[i] - borrow;
329 uECC_word_t val = (diff > left[i]);
330 borrow = cond_set(val, borrow, (diff != left[i]));
331
332 result[i] = diff;
333 }
334 return borrow;
335}
336
337/* Computes result = left + right, returning carry, in constant time.
338 * Can modify in place. */
339static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100340 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300341{
342 uECC_word_t carry = 0;
343 wordcount_t i;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100344 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300345 uECC_word_t sum = left[i] + right[i] + carry;
346 uECC_word_t val = (sum < left[i]);
347 carry = cond_set(val, carry, (sum != left[i]));
348 result[i] = sum;
349 }
350 return carry;
351}
352
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +0100353cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300354{
355 uECC_word_t tmp[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100356 uECC_word_t neg = !!uECC_vli_sub(tmp, left, right);
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100357 uECC_word_t equal = uECC_vli_isZero(tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300358 return (!equal - 2 * neg);
359}
360
361/* Computes vli = vli >> 1. */
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100362static void uECC_vli_rshift1(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300363{
364 uECC_word_t *end = vli;
365 uECC_word_t carry = 0;
366
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100367 vli += NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300368 while (vli-- > end) {
369 uECC_word_t temp = *vli;
370 *vli = (temp >> 1) | carry;
371 carry = temp << (uECC_WORD_BITS - 1);
372 }
373}
374
Manuel Pégourié-Gonnard86c4f812019-10-31 13:02:03 +0100375/* Compute a * b + r, where r is a double-word with high-order word r1 and
376 * low-order word r0, and store the result in the same double-word (r1, r0),
377 * with the carry bit stored in r2.
378 *
379 * (r2, r1, r0) = a * b + (r1, r0):
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200380 * [in] a, b: operands to be multiplied
381 * [in] r0, r1: low and high-order words of operand to add
382 * [out] r0, r1: low and high-order words of the result
383 * [out] r2: carry
384 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300385static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0,
386 uECC_word_t *r1, uECC_word_t *r2)
387{
388
389 uECC_dword_t p = (uECC_dword_t)a * b;
390 uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
391 r01 += p;
392 *r2 += (r01 < p);
393 *r1 = r01 >> uECC_WORD_BITS;
394 *r0 = (uECC_word_t)r01;
395
396}
397
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200398/* State for implementing random delays in uECC_vli_mult_rnd().
399 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100400 * The state is initialized by randomizing delays and setting i = 0.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200401 * Each call to uECC_vli_mult_rnd() uses one byte of delays and increments i.
402 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100403 * Randomized vli multiplication is used only for point operations
404 * (XYcZ_add_rnd() * and XYcZ_addC_rnd()) in scalar multiplication
405 * (ECCPoint_mult()). Those go in pair, and each pair does 14 calls to
406 * uECC_vli_mult_rnd() (6 in XYcZ_add_rnd() and 8 in XYcZ_addC_rnd(),
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100407 * indirectly through uECC_vli_modMult_rnd().
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100408 *
409 * Considering this, in order to minimize the number of calls to the RNG
410 * (which impact performance) while keeping the size of the structure low,
411 * make room for 14 randomized vli mults, which corresponds to one step in the
412 * scalar multiplication routine.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200413 */
414typedef struct {
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100415 uint8_t i;
416 uint8_t delays[14];
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100417} ecc_wait_state_t;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200418
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100419/*
420 * Reset wait_state so that it's ready to be used.
421 */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100422void ecc_wait_state_reset(ecc_wait_state_t *ws)
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100423{
424 if (ws == NULL)
425 return;
426
427 ws->i = 0;
428 g_rng_function(ws->delays, sizeof(ws->delays));
429}
430
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200431/* Computes result = left * right. Result must be 2 * num_words long.
432 *
433 * As a counter-measure against horizontal attacks, add noise by performing
434 * a random number of extra computations performing random additional accesses
435 * to limbs of the input.
436 *
437 * Each of the two actual computation loops is surrounded by two
438 * similar-looking waiting loops, to make the beginning and end of the actual
439 * computation harder to spot.
440 *
441 * We add 4 waiting loops of between 0 and 3 calls to muladd() each. That
442 * makes an average of 6 extra calls. Compared to the main computation which
443 * makes 64 such calls, this represents an average performance degradation of
444 * less than 10%.
445 *
446 * Compared to the original uECC_vli_mult(), loose the num_words argument as we
447 * know it's always 8. This saves a bit of code size and execution speed.
448 */
449static void uECC_vli_mult_rnd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100450 const uECC_word_t *right, ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300451{
452
453 uECC_word_t r0 = 0;
454 uECC_word_t r1 = 0;
455 uECC_word_t r2 = 0;
456 wordcount_t i, k;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100457 const uint8_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200458
459 /* Fetch 8 bit worth of delay from the state; 0 if we have no state */
460 uint8_t delays = s ? s->delays[s->i++] : 0;
461 uECC_word_t rr0 = 0, rr1 = 0;
462 volatile uECC_word_t r;
463
464 /* Mimic start of next loop: k in [0, 3] */
465 k = 0 + (delays & 0x03);
466 delays >>= 2;
467 /* k = 0 -> i in [1, 0] -> 0 extra muladd;
468 * k = 3 -> i in [1, 3] -> 3 extra muladd */
Manuel Pégourié-Gonnardc8814862019-11-05 10:32:37 +0100469 for (i = 1; i <= k; ++i) {
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200470 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
471 }
472 r = rr0;
473 rr0 = rr1;
474 rr1 = r2;
475 r2 = 0;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300476
477 /* Compute each digit of result in sequence, maintaining the carries. */
478 for (k = 0; k < num_words; ++k) {
479
480 for (i = 0; i <= k; ++i) {
481 muladd(left[i], right[k - i], &r0, &r1, &r2);
482 }
483
484 result[k] = r0;
485 r0 = r1;
486 r1 = r2;
487 r2 = 0;
488 }
489
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200490 /* Mimic end of previous loop: k in [4, 7] */
491 k = 4 + (delays & 0x03);
492 delays >>= 2;
493 /* k = 4 -> i in [5, 4] -> 0 extra muladd;
494 * k = 7 -> i in [5, 7] -> 3 extra muladd */
495 for (i = 5; i <= k; ++i) {
496 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
497 }
498 r = rr0;
499 rr0 = rr1;
500 rr1 = r2;
501 r2 = 0;
502
503 /* Mimic start of next loop: k in [8, 11] */
504 k = 11 - (delays & 0x03);
505 delays >>= 2;
506 /* k = 8 -> i in [5, 7] -> 3 extra muladd;
507 * k = 11 -> i in [8, 7] -> 0 extra muladd */
508 for (i = (k + 5) - 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
Jarno Lamsa18987a42019-04-24 15:40:43 +0300516 for (k = num_words; k < num_words * 2 - 1; ++k) {
517
518 for (i = (k + 1) - num_words; i < num_words; ++i) {
519 muladd(left[i], right[k - i], &r0, &r1, &r2);
520 }
521 result[k] = r0;
522 r0 = r1;
523 r1 = r2;
524 r2 = 0;
525 }
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200526
Jarno Lamsa18987a42019-04-24 15:40:43 +0300527 result[num_words * 2 - 1] = r0;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200528
529 /* Mimic end of previous loop: k in [12, 15] */
530 k = 15 - (delays & 0x03);
531 delays >>= 2;
532 /* k = 12 -> i in [5, 7] -> 3 extra muladd;
533 * k = 15 -> i in [8, 7] -> 0 extra muladd */
534 for (i = (k + 1) - num_words; i < num_words; ++i) {
535 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
536 }
537 r = rr0;
538 rr0 = rr1;
539 rr1 = r2;
540 r2 = 0;
541
542 /* avoid warning that r is set but not used */
543 (void) r;
544}
545
Jarno Lamsa18987a42019-04-24 15:40:43 +0300546void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard0779be72019-11-04 14:48:22 +0100547 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300548{
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100549 uECC_word_t carry = uECC_vli_add(result, left, right);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100550 if (carry || uECC_vli_cmp_unsafe(mod, result) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300551 /* result > mod (result = mod + remainder), so subtract mod to get
552 * remainder. */
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100553 uECC_vli_sub(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300554 }
555}
556
557void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard1b0875d2019-11-04 14:50:54 +0100558 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300559{
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100560 uECC_word_t l_borrow = uECC_vli_sub(result, left, right);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300561 if (l_borrow) {
562 /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
563 * we can get the correct result from result + mod (with overflow). */
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100564 uECC_vli_add(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300565 }
566}
567
568/* Computes result = product % mod, where product is 2N words long. */
569/* Currently only designed to work for curve_p or curve_n. */
570void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100571 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300572{
573 uECC_word_t mod_multiple[2 * NUM_ECC_WORDS];
574 uECC_word_t tmp[2 * NUM_ECC_WORDS];
575 uECC_word_t *v[2] = {tmp, product};
576 uECC_word_t index;
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100577 const wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300578
579 /* Shift mod so its highest set bit is at the maximum position. */
580 bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) -
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100581 uECC_vli_numBits(mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300582 wordcount_t word_shift = shift / uECC_WORD_BITS;
583 wordcount_t bit_shift = shift % uECC_WORD_BITS;
584 uECC_word_t carry = 0;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100585 uECC_vli_clear(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300586 if (bit_shift > 0) {
587 for(index = 0; index < (uECC_word_t)num_words; ++index) {
588 mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;
589 carry = mod[index] >> (uECC_WORD_BITS - bit_shift);
590 }
591 } else {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100592 uECC_vli_set(mod_multiple + word_shift, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300593 }
594
595 for (index = 1; shift >= 0; --shift) {
596 uECC_word_t borrow = 0;
597 wordcount_t i;
598 for (i = 0; i < num_words * 2; ++i) {
599 uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;
600 if (diff != v[index][i]) {
601 borrow = (diff > v[index][i]);
602 }
603 v[1 - index][i] = diff;
604 }
605 /* Swap the index if there was no borrow */
606 index = !(index ^ borrow);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100607 uECC_vli_rshift1(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300608 mod_multiple[num_words - 1] |= mod_multiple[num_words] <<
609 (uECC_WORD_BITS - 1);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100610 uECC_vli_rshift1(mod_multiple + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300611 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100612 uECC_vli_set(result, v[index]);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300613}
614
615void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard3e20adf2019-11-04 15:00:43 +0100616 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300617{
618 uECC_word_t product[2 * NUM_ECC_WORDS];
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100619 uECC_vli_mult_rnd(product, left, right, NULL);
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100620 uECC_vli_mmod(result, product, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300621}
622
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100623static void uECC_vli_modMult_rnd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100624 const uECC_word_t *right, ecc_wait_state_t *s)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100625{
626 uECC_word_t product[2 * NUM_ECC_WORDS];
627 uECC_vli_mult_rnd(product, left, right, s);
628
629 vli_mmod_fast_secp256r1(result, product);
630}
631
Jarno Lamsa18987a42019-04-24 15:40:43 +0300632void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100633 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300634{
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100635 uECC_vli_modMult_rnd(result, left, right, NULL);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300636}
637
Jarno Lamsa18987a42019-04-24 15:40:43 +0300638#define EVEN(vli) (!(vli[0] & 1))
639
640static void vli_modInv_update(uECC_word_t *uv,
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100641 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300642{
643
644 uECC_word_t carry = 0;
645
646 if (!EVEN(uv)) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100647 carry = uECC_vli_add(uv, uv, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300648 }
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100649 uECC_vli_rshift1(uv);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300650 if (carry) {
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100651 uv[NUM_ECC_WORDS - 1] |= HIGH_BIT_SET;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300652 }
653}
654
655void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100656 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300657{
658 uECC_word_t a[NUM_ECC_WORDS], b[NUM_ECC_WORDS];
659 uECC_word_t u[NUM_ECC_WORDS], v[NUM_ECC_WORDS];
660 cmpresult_t cmpResult;
661
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100662 if (uECC_vli_isZero(input)) {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100663 uECC_vli_clear(result);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300664 return;
665 }
666
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100667 uECC_vli_set(a, input);
668 uECC_vli_set(b, mod);
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100669 uECC_vli_clear(u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300670 u[0] = 1;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100671 uECC_vli_clear(v);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100672 while ((cmpResult = uECC_vli_cmp_unsafe(a, b)) != 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300673 if (EVEN(a)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100674 uECC_vli_rshift1(a);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100675 vli_modInv_update(u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300676 } else if (EVEN(b)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100677 uECC_vli_rshift1(b);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100678 vli_modInv_update(v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300679 } else if (cmpResult > 0) {
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100680 uECC_vli_sub(a, a, b);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100681 uECC_vli_rshift1(a);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100682 if (uECC_vli_cmp_unsafe(u, v) < 0) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100683 uECC_vli_add(u, u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300684 }
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100685 uECC_vli_sub(u, u, v);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100686 vli_modInv_update(u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300687 } else {
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100688 uECC_vli_sub(b, b, a);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100689 uECC_vli_rshift1(b);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100690 if (uECC_vli_cmp_unsafe(v, u) < 0) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100691 uECC_vli_add(v, v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300692 }
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100693 uECC_vli_sub(v, v, u);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100694 vli_modInv_update(v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300695 }
696 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100697 uECC_vli_set(result, u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300698}
699
700/* ------ Point operations ------ */
701
702void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100703 uECC_word_t * Z1)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300704{
705 /* t1 = X, t2 = Y, t3 = Z */
706 uECC_word_t t4[NUM_ECC_WORDS];
707 uECC_word_t t5[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +0100708 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300709
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100710 if (uECC_vli_isZero(Z1)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300711 return;
712 }
713
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100714 uECC_vli_modMult_fast(t4, Y1, Y1); /* t4 = y1^2 */
715 uECC_vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */
716 uECC_vli_modMult_fast(t4, t4, t4); /* t4 = y1^4 */
717 uECC_vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */
718 uECC_vli_modMult_fast(Z1, Z1, Z1); /* t3 = z1^2 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300719
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100720 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */
721 uECC_vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */
722 uECC_vli_modSub(Z1, X1, Z1, curve_p); /* t3 = x1 - z1^2 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100723 uECC_vli_modMult_fast(X1, X1, Z1); /* t1 = x1^2 - z1^4 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300724
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100725 uECC_vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */
726 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300727 if (uECC_vli_testBit(X1, 0)) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100728 uECC_word_t l_carry = uECC_vli_add(X1, X1, curve_p);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100729 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300730 X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
731 } else {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100732 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300733 }
734
735 /* t1 = 3/2*(x1^2 - z1^4) = B */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100736 uECC_vli_modMult_fast(Z1, X1, X1); /* t3 = B^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100737 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - A */
738 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */
739 uECC_vli_modSub(t5, t5, Z1, curve_p); /* t5 = A - x3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100740 uECC_vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300741 /* t4 = B * (A - x3) - y1^4 = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100742 uECC_vli_modSub(t4, X1, t4, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300743
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100744 uECC_vli_set(X1, Z1);
745 uECC_vli_set(Z1, Y1);
746 uECC_vli_set(Y1, t4);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300747}
748
Manuel Pégourié-Gonnard1c6f7ea2019-11-21 09:18:29 +0100749/*
750 * @brief Computes x^3 + ax + b. result must not overlap x.
751 * @param result OUT -- x^3 + ax + b
752 * @param x IN -- value of x
753 * @param curve IN -- elliptic curve
754 */
755static void x_side_default(uECC_word_t *result,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100756 const uECC_word_t *x)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300757{
758 uECC_word_t _3[NUM_ECC_WORDS] = {3}; /* -a = 3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300759
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100760 uECC_vli_modMult_fast(result, x, x); /* r = x^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100761 uECC_vli_modSub(result, result, _3, curve_p); /* r = x^2 - 3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100762 uECC_vli_modMult_fast(result, result, x); /* r = x^3 - 3x */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300763 /* r = x^3 - 3x + b: */
Manuel Pégourié-Gonnardffd13992019-11-21 10:39:06 +0100764 uECC_vli_modAdd(result, result, curve_b, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300765}
766
767void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int*product)
768{
769 unsigned int tmp[NUM_ECC_WORDS];
770 int carry;
771
772 /* t */
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100773 uECC_vli_set(result, product);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300774
775 /* s1 */
776 tmp[0] = tmp[1] = tmp[2] = 0;
777 tmp[3] = product[11];
778 tmp[4] = product[12];
779 tmp[5] = product[13];
780 tmp[6] = product[14];
781 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100782 carry = uECC_vli_add(tmp, tmp, tmp);
783 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300784
785 /* s2 */
786 tmp[3] = product[12];
787 tmp[4] = product[13];
788 tmp[5] = product[14];
789 tmp[6] = product[15];
790 tmp[7] = 0;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100791 carry += uECC_vli_add(tmp, tmp, tmp);
792 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300793
794 /* s3 */
795 tmp[0] = product[8];
796 tmp[1] = product[9];
797 tmp[2] = product[10];
798 tmp[3] = tmp[4] = tmp[5] = 0;
799 tmp[6] = product[14];
800 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100801 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300802
803 /* s4 */
804 tmp[0] = product[9];
805 tmp[1] = product[10];
806 tmp[2] = product[11];
807 tmp[3] = product[13];
808 tmp[4] = product[14];
809 tmp[5] = product[15];
810 tmp[6] = product[13];
811 tmp[7] = product[8];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100812 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300813
814 /* d1 */
815 tmp[0] = product[11];
816 tmp[1] = product[12];
817 tmp[2] = product[13];
818 tmp[3] = tmp[4] = tmp[5] = 0;
819 tmp[6] = product[8];
820 tmp[7] = product[10];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100821 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300822
823 /* d2 */
824 tmp[0] = product[12];
825 tmp[1] = product[13];
826 tmp[2] = product[14];
827 tmp[3] = product[15];
828 tmp[4] = tmp[5] = 0;
829 tmp[6] = product[9];
830 tmp[7] = product[11];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100831 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300832
833 /* d3 */
834 tmp[0] = product[13];
835 tmp[1] = product[14];
836 tmp[2] = product[15];
837 tmp[3] = product[8];
838 tmp[4] = product[9];
839 tmp[5] = product[10];
840 tmp[6] = 0;
841 tmp[7] = product[12];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100842 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300843
844 /* d4 */
845 tmp[0] = product[14];
846 tmp[1] = product[15];
847 tmp[2] = 0;
848 tmp[3] = product[9];
849 tmp[4] = product[10];
850 tmp[5] = product[11];
851 tmp[6] = 0;
852 tmp[7] = product[13];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100853 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300854
855 if (carry < 0) {
856 do {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100857 carry += uECC_vli_add(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300858 }
859 while (carry < 0);
860 } else {
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200861 while (carry ||
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100862 uECC_vli_cmp_unsafe(curve_p, result) != 1) {
863 carry -= uECC_vli_sub(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300864 }
865 }
866}
867
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100868uECC_word_t EccPoint_isZero(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300869{
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100870 return uECC_vli_isZero(point);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300871}
872
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100873void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300874{
875 uECC_word_t t1[NUM_ECC_WORDS];
876
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100877 uECC_vli_modMult_fast(t1, Z, Z); /* z^2 */
878 uECC_vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */
879 uECC_vli_modMult_fast(t1, t1, Z); /* z^3 */
880 uECC_vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300881}
882
883/* P = (x1, y1) => 2P, (x2, y2) => P' */
884static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1,
885 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100886 const uECC_word_t * const initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300887{
888 uECC_word_t z[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300889 if (initial_Z) {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100890 uECC_vli_set(z, initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300891 } else {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100892 uECC_vli_clear(z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300893 z[0] = 1;
894 }
895
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100896 uECC_vli_set(X2, X1);
897 uECC_vli_set(Y2, Y1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300898
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100899 apply_z(X1, Y1, z);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100900 double_jacobian_default(X1, Y1, z);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100901 apply_z(X2, Y2, z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300902}
903
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100904static void XYcZ_add_rnd(uECC_word_t * X1, uECC_word_t * Y1,
905 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100906 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300907{
908 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
909 uECC_word_t t5[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300910
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100911 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100912 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100913 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
914 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100915 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100916 uECC_vli_modMult_rnd(t5, Y2, Y2, s); /* t5 = (y2 - y1)^2 = D */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300917
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100918 uECC_vli_modSub(t5, t5, X1, curve_p); /* t5 = D - B */
919 uECC_vli_modSub(t5, t5, X2, curve_p); /* t5 = D - B - C = x3 */
920 uECC_vli_modSub(X2, X2, X1, curve_p); /* t3 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100921 uECC_vli_modMult_rnd(Y1, Y1, X2, s); /* t2 = y1*(C - B) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100922 uECC_vli_modSub(X2, X1, t5, curve_p); /* t3 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100923 uECC_vli_modMult_rnd(Y2, Y2, X2, s); /* t4 = (y2 - y1)*(B - x3) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100924 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300925
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100926 uECC_vli_set(X2, t5);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300927}
928
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100929void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100930 uECC_word_t * X2, uECC_word_t * Y2)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100931{
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100932 XYcZ_add_rnd(X1, Y1, X2, Y2, NULL);
933}
934
Jarno Lamsa18987a42019-04-24 15:40:43 +0300935/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
936 Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
937 or P => P - Q, Q => P + Q
938 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100939static void XYcZ_addC_rnd(uECC_word_t * X1, uECC_word_t * Y1,
940 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100941 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300942{
943 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
944 uECC_word_t t5[NUM_ECC_WORDS];
945 uECC_word_t t6[NUM_ECC_WORDS];
946 uECC_word_t t7[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300947
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100948 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100949 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100950 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
951 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100952 uECC_vli_modAdd(t5, Y2, Y1, curve_p); /* t5 = y2 + y1 */
953 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300954
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100955 uECC_vli_modSub(t6, X2, X1, curve_p); /* t6 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100956 uECC_vli_modMult_rnd(Y1, Y1, t6, s); /* t2 = y1 * (C - B) = E */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100957 uECC_vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100958 uECC_vli_modMult_rnd(X2, Y2, Y2, s); /* t3 = (y2 - y1)^2 = D */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100959 uECC_vli_modSub(X2, X2, t6, curve_p); /* t3 = D - (B + C) = x3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300960
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100961 uECC_vli_modSub(t7, X1, X2, curve_p); /* t7 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100962 uECC_vli_modMult_rnd(Y2, Y2, t7, s); /* t4 = (y2 - y1)*(B - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300963 /* t4 = (y2 - y1)*(B - x3) - E = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100964 uECC_vli_modSub(Y2, Y2, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300965
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100966 uECC_vli_modMult_rnd(t7, t5, t5, s); /* t7 = (y2 + y1)^2 = F */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100967 uECC_vli_modSub(t7, t7, t6, curve_p); /* t7 = F - (B + C) = x3' */
968 uECC_vli_modSub(t6, t7, X1, curve_p); /* t6 = x3' - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100969 uECC_vli_modMult_rnd(t6, t6, t5, s); /* t6 = (y2+y1)*(x3' - B) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300970 /* t2 = (y2+y1)*(x3' - B) - E = y3': */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100971 uECC_vli_modSub(Y1, t6, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300972
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100973 uECC_vli_set(X1, t7);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300974}
975
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +0100976static void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point,
Jarno Lamsa18987a42019-04-24 15:40:43 +0300977 const uECC_word_t * scalar,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +0100978 const uECC_word_t * initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300979{
980 /* R0 and R1 */
981 uECC_word_t Rx[2][NUM_ECC_WORDS];
982 uECC_word_t Ry[2][NUM_ECC_WORDS];
983 uECC_word_t z[NUM_ECC_WORDS];
984 bitcount_t i;
985 uECC_word_t nb;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100986 const wordcount_t num_words = NUM_ECC_WORDS;
987 const bitcount_t num_bits = NUM_ECC_BITS + 1; /* from regularize_k */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100988 ecc_wait_state_t wait_state;
989 ecc_wait_state_t * const ws = g_rng_function ? &wait_state : NULL;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300990
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100991 uECC_vli_set(Rx[1], point);
992 uECC_vli_set(Ry[1], point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300993
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100994 XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300995
996 for (i = num_bits - 2; i > 0; --i) {
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100997 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300998 nb = !uECC_vli_testBit(scalar, i);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100999 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
1000 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001001 }
1002
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +01001003 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001004 nb = !uECC_vli_testBit(scalar, 0);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001005 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001006
1007 /* Find final 1/Z value. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001008 uECC_vli_modSub(z, Rx[1], Rx[0], curve_p); /* X1 - X0 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001009 uECC_vli_modMult_fast(z, z, Ry[1 - nb]); /* Yb * (X1 - X0) */
1010 uECC_vli_modMult_fast(z, z, point); /* xP * Yb * (X1 - X0) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001011 uECC_vli_modInv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0))*/
Jarno Lamsa18987a42019-04-24 15:40:43 +03001012 /* yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001013 uECC_vli_modMult_fast(z, z, point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001014 /* Xb * yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001015 uECC_vli_modMult_fast(z, z, Rx[1 - nb]);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001016 /* End 1/Z calculation */
1017
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001018 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001019 apply_z(Rx[0], Ry[0], z);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001020
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +01001021 uECC_vli_set(result, Rx[0]);
1022 uECC_vli_set(result + num_words, Ry[0]);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001023}
1024
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +01001025static uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001026 uECC_word_t *k1)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001027{
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001028 bitcount_t num_n_bits = NUM_ECC_BITS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001029
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001030 uECC_word_t carry = uECC_vli_add(k0, k, curve_n) ||
Teppo Järvelin0b1d7d92019-12-13 07:39:39 +02001031 uECC_vli_testBit(k0, num_n_bits);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001032
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001033 uECC_vli_add(k1, k0, curve_n);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001034
1035 return carry;
1036}
1037
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001038int EccPoint_mult_safer(uECC_word_t * result, const uECC_word_t * point,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001039 const uECC_word_t * scalar)
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001040{
1041 uECC_word_t tmp[NUM_ECC_WORDS];
1042 uECC_word_t s[NUM_ECC_WORDS];
1043 uECC_word_t *k2[2] = {tmp, s};
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001044 wordcount_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001045 uECC_word_t carry;
1046 uECC_word_t *initial_Z = 0;
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001047 int r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001048 volatile int problem;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001049
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001050 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001051 problem = -1;
1052 problem = uECC_check_curve_integrity();
1053 if (problem != 0) {
1054 return UECC_FAULT_DETECTED;
1055 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001056 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001057 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001058 return UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001059 }
1060
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001061 /* Protects against invalid curve attacks */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001062 problem = -1;
1063 problem = uECC_valid_point(point);
1064 if (problem != 0) {
1065 /* invalid input, can happen without fault */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001066 return UECC_FAILURE;
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001067 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001068 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001069 if (problem != 0) {
1070 /* failure on second check means fault, though */
1071 return UECC_FAULT_DETECTED;
1072 }
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001073
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001074 /* Regularize the bitcount for the private key so that attackers cannot use a
1075 * side channel attack to learn the number of leading zeros. */
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001076 carry = regularize_k(scalar, tmp, s);
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001077
1078 /* If an RNG function was specified, get a random initial Z value to
1079 * protect against side-channel attacks such as Template SPA */
1080 if (g_rng_function) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001081 if (!uECC_generate_random_int(k2[carry], curve_p, num_words)) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001082 r = UECC_FAILURE;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001083 goto clear_and_out;
1084 }
1085 initial_Z = k2[carry];
1086 }
1087
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001088 EccPoint_mult(result, point, k2[!carry], initial_Z);
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001089
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001090 /* Protect against fault injections that would make the resulting
1091 * point not lie on the intended curve */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001092 problem = -1;
1093 problem = uECC_valid_point(result);
1094 if (problem != 0) {
1095 r = UECC_FAULT_DETECTED;
1096 goto clear_and_out;
1097 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001098 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001099 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001100 r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001101 goto clear_and_out;
1102 }
1103
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001104 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001105 problem = -1;
1106 problem = uECC_check_curve_integrity();
1107 if (problem != 0) {
1108 r = UECC_FAULT_DETECTED;
1109 goto clear_and_out;
1110 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001111 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001112 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001113 r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001114 goto clear_and_out;
1115 }
1116
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001117 r = UECC_SUCCESS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001118
1119clear_and_out:
1120 /* erasing temporary buffer used to store secret: */
1121 mbedtls_platform_zeroize(k2, sizeof(k2));
1122 mbedtls_platform_zeroize(tmp, sizeof(tmp));
1123 mbedtls_platform_zeroize(s, sizeof(s));
1124
1125 return r;
1126}
1127
Jarno Lamsa18987a42019-04-24 15:40:43 +03001128uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001129 uECC_word_t *private_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001130{
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001131 return EccPoint_mult_safer(result, curve_G, private_key);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001132}
1133
1134/* Converts an integer in uECC native format to big-endian bytes. */
1135void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
1136 const unsigned int *native)
1137{
1138 wordcount_t i;
1139 for (i = 0; i < num_bytes; ++i) {
1140 unsigned b = num_bytes - 1 - i;
1141 bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE));
1142 }
1143}
1144
1145/* Converts big-endian bytes to an integer in uECC native format. */
1146void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes,
1147 int num_bytes)
1148{
1149 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +01001150 uECC_vli_clear(native);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001151 for (i = 0; i < num_bytes; ++i) {
1152 unsigned b = num_bytes - 1 - i;
1153 native[b / uECC_WORD_SIZE] |=
1154 (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE));
1155 }
1156}
1157
1158int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
1159 wordcount_t num_words)
1160{
1161 uECC_word_t mask = (uECC_word_t)-1;
1162 uECC_word_t tries;
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +01001163 bitcount_t num_bits = uECC_vli_numBits(top);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001164
1165 if (!g_rng_function) {
1166 return 0;
1167 }
1168
1169 for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
1170 if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) {
1171 return 0;
1172 }
1173 random[num_words - 1] &=
1174 mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits));
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001175 if (!uECC_vli_isZero(random) &&
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +01001176 uECC_vli_cmp(top, random) == 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001177 return 1;
1178 }
1179 }
1180 return 0;
1181}
1182
1183
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001184int uECC_valid_point(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001185{
1186 uECC_word_t tmp1[NUM_ECC_WORDS];
1187 uECC_word_t tmp2[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001188 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa83d78812019-12-04 14:40:57 +02001189 volatile uECC_word_t diff = 0xffffffff;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001190
1191 /* The point at infinity is invalid. */
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001192 if (EccPoint_isZero(point)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001193 return -1;
1194 }
1195
1196 /* x and y must be smaller than p. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001197 if (uECC_vli_cmp_unsafe(curve_p, point) != 1 ||
1198 uECC_vli_cmp_unsafe(curve_p, point + num_words) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001199 return -2;
1200 }
1201
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001202 uECC_vli_modMult_fast(tmp1, point + num_words, point + num_words);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001203 x_side_default(tmp2, point); /* tmp2 = x^3 + ax + b */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001204
1205 /* Make sure that y^2 == x^3 + ax + b */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001206 diff = uECC_vli_equal(tmp1, tmp2);
1207 if (diff == 0) {
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001208 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001209 if (diff == 0) {
1210 return 0;
1211 }
1212 }
Jarno Lamsa18987a42019-04-24 15:40:43 +03001213
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001214 return -3;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001215}
1216
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001217int uECC_valid_public_key(const uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001218{
1219
1220 uECC_word_t _public[NUM_ECC_WORDS * 2];
1221
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001222 uECC_vli_bytesToNative(_public, public_key, NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001223 uECC_vli_bytesToNative(
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001224 _public + NUM_ECC_WORDS,
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001225 public_key + NUM_ECC_BYTES,
1226 NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001227
Manuel Pégourié-Gonnarda6115082019-11-21 10:29:14 +01001228 if (memcmp(_public, curve_G, NUM_ECC_WORDS * 2) == 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001229 return -4;
1230 }
1231
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001232 return uECC_valid_point(_public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001233}
1234
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001235int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001236{
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001237 int ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001238 uECC_word_t _private[NUM_ECC_WORDS];
1239 uECC_word_t _public[NUM_ECC_WORDS * 2];
1240
1241 uECC_vli_bytesToNative(
1242 _private,
1243 private_key,
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +01001244 BITS_TO_BYTES(NUM_ECC_BITS));
Jarno Lamsa18987a42019-04-24 15:40:43 +03001245
1246 /* Make sure the private key is in the range [1, n-1]. */
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001247 if (uECC_vli_isZero(_private)) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001248 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001249 }
1250
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001251 if (uECC_vli_cmp(curve_n, _private) != 1) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001252 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001253 }
1254
1255 /* Compute public key. */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001256 ret = EccPoint_compute_public_key(_public, _private);
1257 if (ret != UECC_SUCCESS) {
1258 return ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001259 }
1260
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001261 uECC_vli_nativeToBytes(public_key, NUM_ECC_BYTES, _public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001262 uECC_vli_nativeToBytes(
1263 public_key +
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001264 NUM_ECC_BYTES, NUM_ECC_BYTES, _public + NUM_ECC_WORDS);
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001265 return UECC_SUCCESS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001266}
Jarno Lamsa18987a42019-04-24 15:40:43 +03001267