blob: df7a6928ce2046ad8b1b7c819cdba66269da2b1c [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];
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100150 static const unsigned char reference[32] = {
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100151 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;
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
163 for (i = 0; i < 32; i++)
164 diff |= computed[i] ^ reference[i];
165
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100166 /* i should be 32 */
167 mbedtls_platform_enforce_volatile_reads();
168 diff |= (unsigned char) i ^ 32;
169
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100170 return diff;
171}
172
Jarno Lamsa18987a42019-04-24 15:40:43 +0300173/* IMPORTANT: Make sure a cryptographically-secure PRNG is set and the platform
174 * has access to enough entropy in order to feed the PRNG regularly. */
175#if default_RNG_defined
176static uECC_RNG_Function g_rng_function = &default_CSPRNG;
177#else
178static uECC_RNG_Function g_rng_function = 0;
179#endif
180
181void uECC_set_rng(uECC_RNG_Function rng_function)
182{
183 g_rng_function = rng_function;
184}
185
186uECC_RNG_Function uECC_get_rng(void)
187{
188 return g_rng_function;
189}
190
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +0100191int uECC_curve_private_key_size(void)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300192{
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +0100193 return BITS_TO_BYTES(NUM_ECC_BITS);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300194}
195
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +0100196int uECC_curve_public_key_size(void)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300197{
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +0100198 return 2 * NUM_ECC_BYTES;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300199}
200
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100201void uECC_vli_clear(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300202{
203 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100204 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300205 vli[i] = 0;
206 }
207}
208
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100209uECC_word_t uECC_vli_isZero(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300210{
211 uECC_word_t bits = 0;
212 wordcount_t i;
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100213 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300214 bits |= vli[i];
215 }
216 return (bits == 0);
217}
218
219uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit)
220{
221 return (vli[bit >> uECC_WORD_BITS_SHIFT] &
222 ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));
223}
224
225/* Counts the number of words in vli. */
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100226static wordcount_t vli_numDigits(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300227{
228
229 wordcount_t i;
230 /* Search from the end until we find a non-zero digit. We do it in reverse
231 * because we expect that most digits will be nonzero. */
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100232 for (i = NUM_ECC_WORDS - 1; i >= 0 && vli[i] == 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300233 }
234
235 return (i + 1);
236}
237
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100238bitcount_t uECC_vli_numBits(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300239{
240
241 uECC_word_t i;
242 uECC_word_t digit;
243
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100244 wordcount_t num_digits = vli_numDigits(vli);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300245 if (num_digits == 0) {
246 return 0;
247 }
248
249 digit = vli[num_digits - 1];
250 for (i = 0; digit; ++i) {
251 digit >>= 1;
252 }
253
254 return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);
255}
256
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100257void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300258{
259 wordcount_t i;
260
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100261 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300262 dest[i] = src[i];
263 }
264}
265
266cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100267 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300268{
269 wordcount_t i;
270
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100271 for (i = NUM_ECC_WORDS - 1; i >= 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300272 if (left[i] > right[i]) {
273 return 1;
274 } else if (left[i] < right[i]) {
275 return -1;
276 }
277 }
278 return 0;
279}
280
Manuel Pégourié-Gonnard2eca3d32019-11-04 14:33:09 +0100281uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300282{
283
284 uECC_word_t diff = 0;
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100285 volatile int i;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300286
Manuel Pégourié-Gonnard2eca3d32019-11-04 14:33:09 +0100287 for (i = NUM_ECC_WORDS - 1; i >= 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300288 diff |= (left[i] ^ right[i]);
289 }
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100290
291 /* i should be -1 now */
292 mbedtls_platform_enforce_volatile_reads();
293 diff |= i ^ -1;
294
Manuel Pégourié-Gonnard2b6312b2019-11-06 10:42:02 +0100295 return diff;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300296}
297
298uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond)
299{
300 return (p_true*(cond)) | (p_false*(!cond));
301}
302
303/* Computes result = left - right, returning borrow, in constant time.
304 * Can modify in place. */
305uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100306 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300307{
308 uECC_word_t borrow = 0;
309 wordcount_t i;
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100310 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300311 uECC_word_t diff = left[i] - right[i] - borrow;
312 uECC_word_t val = (diff > left[i]);
313 borrow = cond_set(val, borrow, (diff != left[i]));
314
315 result[i] = diff;
316 }
317 return borrow;
318}
319
320/* Computes result = left + right, returning carry, in constant time.
321 * Can modify in place. */
322static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100323 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300324{
325 uECC_word_t carry = 0;
326 wordcount_t i;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100327 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300328 uECC_word_t sum = left[i] + right[i] + carry;
329 uECC_word_t val = (sum < left[i]);
330 carry = cond_set(val, carry, (sum != left[i]));
331 result[i] = sum;
332 }
333 return carry;
334}
335
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +0100336cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300337{
338 uECC_word_t tmp[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100339 uECC_word_t neg = !!uECC_vli_sub(tmp, left, right);
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100340 uECC_word_t equal = uECC_vli_isZero(tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300341 return (!equal - 2 * neg);
342}
343
344/* Computes vli = vli >> 1. */
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100345static void uECC_vli_rshift1(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300346{
347 uECC_word_t *end = vli;
348 uECC_word_t carry = 0;
349
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100350 vli += NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300351 while (vli-- > end) {
352 uECC_word_t temp = *vli;
353 *vli = (temp >> 1) | carry;
354 carry = temp << (uECC_WORD_BITS - 1);
355 }
356}
357
Manuel Pégourié-Gonnard86c4f812019-10-31 13:02:03 +0100358/* Compute a * b + r, where r is a double-word with high-order word r1 and
359 * low-order word r0, and store the result in the same double-word (r1, r0),
360 * with the carry bit stored in r2.
361 *
362 * (r2, r1, r0) = a * b + (r1, r0):
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200363 * [in] a, b: operands to be multiplied
364 * [in] r0, r1: low and high-order words of operand to add
365 * [out] r0, r1: low and high-order words of the result
366 * [out] r2: carry
367 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300368static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0,
369 uECC_word_t *r1, uECC_word_t *r2)
370{
371
372 uECC_dword_t p = (uECC_dword_t)a * b;
373 uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
374 r01 += p;
375 *r2 += (r01 < p);
376 *r1 = r01 >> uECC_WORD_BITS;
377 *r0 = (uECC_word_t)r01;
378
379}
380
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200381/* State for implementing random delays in uECC_vli_mult_rnd().
382 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100383 * The state is initialized by randomizing delays and setting i = 0.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200384 * Each call to uECC_vli_mult_rnd() uses one byte of delays and increments i.
385 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100386 * Randomized vli multiplication is used only for point operations
387 * (XYcZ_add_rnd() * and XYcZ_addC_rnd()) in scalar multiplication
388 * (ECCPoint_mult()). Those go in pair, and each pair does 14 calls to
389 * uECC_vli_mult_rnd() (6 in XYcZ_add_rnd() and 8 in XYcZ_addC_rnd(),
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100390 * indirectly through uECC_vli_modMult_rnd().
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100391 *
392 * Considering this, in order to minimize the number of calls to the RNG
393 * (which impact performance) while keeping the size of the structure low,
394 * make room for 14 randomized vli mults, which corresponds to one step in the
395 * scalar multiplication routine.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200396 */
397typedef struct {
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100398 uint8_t i;
399 uint8_t delays[14];
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100400} ecc_wait_state_t;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200401
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100402/*
403 * Reset wait_state so that it's ready to be used.
404 */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100405void ecc_wait_state_reset(ecc_wait_state_t *ws)
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100406{
407 if (ws == NULL)
408 return;
409
410 ws->i = 0;
411 g_rng_function(ws->delays, sizeof(ws->delays));
412}
413
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200414/* Computes result = left * right. Result must be 2 * num_words long.
415 *
416 * As a counter-measure against horizontal attacks, add noise by performing
417 * a random number of extra computations performing random additional accesses
418 * to limbs of the input.
419 *
420 * Each of the two actual computation loops is surrounded by two
421 * similar-looking waiting loops, to make the beginning and end of the actual
422 * computation harder to spot.
423 *
424 * We add 4 waiting loops of between 0 and 3 calls to muladd() each. That
425 * makes an average of 6 extra calls. Compared to the main computation which
426 * makes 64 such calls, this represents an average performance degradation of
427 * less than 10%.
428 *
429 * Compared to the original uECC_vli_mult(), loose the num_words argument as we
430 * know it's always 8. This saves a bit of code size and execution speed.
431 */
432static void uECC_vli_mult_rnd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100433 const uECC_word_t *right, ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300434{
435
436 uECC_word_t r0 = 0;
437 uECC_word_t r1 = 0;
438 uECC_word_t r2 = 0;
439 wordcount_t i, k;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100440 const uint8_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200441
442 /* Fetch 8 bit worth of delay from the state; 0 if we have no state */
443 uint8_t delays = s ? s->delays[s->i++] : 0;
444 uECC_word_t rr0 = 0, rr1 = 0;
445 volatile uECC_word_t r;
446
447 /* Mimic start of next loop: k in [0, 3] */
448 k = 0 + (delays & 0x03);
449 delays >>= 2;
450 /* k = 0 -> i in [1, 0] -> 0 extra muladd;
451 * k = 3 -> i in [1, 3] -> 3 extra muladd */
Manuel Pégourié-Gonnardc8814862019-11-05 10:32:37 +0100452 for (i = 1; i <= k; ++i) {
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200453 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
454 }
455 r = rr0;
456 rr0 = rr1;
457 rr1 = r2;
458 r2 = 0;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300459
460 /* Compute each digit of result in sequence, maintaining the carries. */
461 for (k = 0; k < num_words; ++k) {
462
463 for (i = 0; i <= k; ++i) {
464 muladd(left[i], right[k - i], &r0, &r1, &r2);
465 }
466
467 result[k] = r0;
468 r0 = r1;
469 r1 = r2;
470 r2 = 0;
471 }
472
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200473 /* Mimic end of previous loop: k in [4, 7] */
474 k = 4 + (delays & 0x03);
475 delays >>= 2;
476 /* k = 4 -> i in [5, 4] -> 0 extra muladd;
477 * k = 7 -> i in [5, 7] -> 3 extra muladd */
478 for (i = 5; i <= k; ++i) {
479 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
480 }
481 r = rr0;
482 rr0 = rr1;
483 rr1 = r2;
484 r2 = 0;
485
486 /* Mimic start of next loop: k in [8, 11] */
487 k = 11 - (delays & 0x03);
488 delays >>= 2;
489 /* k = 8 -> i in [5, 7] -> 3 extra muladd;
490 * k = 11 -> i in [8, 7] -> 0 extra muladd */
491 for (i = (k + 5) - num_words; i < num_words; ++i) {
492 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
493 }
494 r = rr0;
495 rr0 = rr1;
496 rr1 = r2;
497 r2 = 0;
498
Jarno Lamsa18987a42019-04-24 15:40:43 +0300499 for (k = num_words; k < num_words * 2 - 1; ++k) {
500
501 for (i = (k + 1) - num_words; i < num_words; ++i) {
502 muladd(left[i], right[k - i], &r0, &r1, &r2);
503 }
504 result[k] = r0;
505 r0 = r1;
506 r1 = r2;
507 r2 = 0;
508 }
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200509
Jarno Lamsa18987a42019-04-24 15:40:43 +0300510 result[num_words * 2 - 1] = r0;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200511
512 /* Mimic end of previous loop: k in [12, 15] */
513 k = 15 - (delays & 0x03);
514 delays >>= 2;
515 /* k = 12 -> i in [5, 7] -> 3 extra muladd;
516 * k = 15 -> i in [8, 7] -> 0 extra muladd */
517 for (i = (k + 1) - num_words; i < num_words; ++i) {
518 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
519 }
520 r = rr0;
521 rr0 = rr1;
522 rr1 = r2;
523 r2 = 0;
524
525 /* avoid warning that r is set but not used */
526 (void) r;
527}
528
Jarno Lamsa18987a42019-04-24 15:40:43 +0300529void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard0779be72019-11-04 14:48:22 +0100530 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300531{
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100532 uECC_word_t carry = uECC_vli_add(result, left, right);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100533 if (carry || uECC_vli_cmp_unsafe(mod, result) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300534 /* result > mod (result = mod + remainder), so subtract mod to get
535 * remainder. */
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100536 uECC_vli_sub(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300537 }
538}
539
540void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard1b0875d2019-11-04 14:50:54 +0100541 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300542{
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100543 uECC_word_t l_borrow = uECC_vli_sub(result, left, right);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300544 if (l_borrow) {
545 /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
546 * we can get the correct result from result + mod (with overflow). */
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100547 uECC_vli_add(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300548 }
549}
550
551/* Computes result = product % mod, where product is 2N words long. */
552/* Currently only designed to work for curve_p or curve_n. */
553void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100554 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300555{
556 uECC_word_t mod_multiple[2 * NUM_ECC_WORDS];
557 uECC_word_t tmp[2 * NUM_ECC_WORDS];
558 uECC_word_t *v[2] = {tmp, product};
559 uECC_word_t index;
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100560 const wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300561
562 /* Shift mod so its highest set bit is at the maximum position. */
563 bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) -
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100564 uECC_vli_numBits(mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300565 wordcount_t word_shift = shift / uECC_WORD_BITS;
566 wordcount_t bit_shift = shift % uECC_WORD_BITS;
567 uECC_word_t carry = 0;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100568 uECC_vli_clear(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300569 if (bit_shift > 0) {
570 for(index = 0; index < (uECC_word_t)num_words; ++index) {
571 mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;
572 carry = mod[index] >> (uECC_WORD_BITS - bit_shift);
573 }
574 } else {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100575 uECC_vli_set(mod_multiple + word_shift, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300576 }
577
578 for (index = 1; shift >= 0; --shift) {
579 uECC_word_t borrow = 0;
580 wordcount_t i;
581 for (i = 0; i < num_words * 2; ++i) {
582 uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;
583 if (diff != v[index][i]) {
584 borrow = (diff > v[index][i]);
585 }
586 v[1 - index][i] = diff;
587 }
588 /* Swap the index if there was no borrow */
589 index = !(index ^ borrow);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100590 uECC_vli_rshift1(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300591 mod_multiple[num_words - 1] |= mod_multiple[num_words] <<
592 (uECC_WORD_BITS - 1);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100593 uECC_vli_rshift1(mod_multiple + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300594 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100595 uECC_vli_set(result, v[index]);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300596}
597
598void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard3e20adf2019-11-04 15:00:43 +0100599 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300600{
601 uECC_word_t product[2 * NUM_ECC_WORDS];
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100602 uECC_vli_mult_rnd(product, left, right, NULL);
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100603 uECC_vli_mmod(result, product, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300604}
605
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100606static void uECC_vli_modMult_rnd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100607 const uECC_word_t *right, ecc_wait_state_t *s)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100608{
609 uECC_word_t product[2 * NUM_ECC_WORDS];
610 uECC_vli_mult_rnd(product, left, right, s);
611
612 vli_mmod_fast_secp256r1(result, product);
613}
614
Jarno Lamsa18987a42019-04-24 15:40:43 +0300615void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100616 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300617{
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100618 uECC_vli_modMult_rnd(result, left, right, NULL);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300619}
620
Jarno Lamsa18987a42019-04-24 15:40:43 +0300621#define EVEN(vli) (!(vli[0] & 1))
622
623static void vli_modInv_update(uECC_word_t *uv,
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100624 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300625{
626
627 uECC_word_t carry = 0;
628
629 if (!EVEN(uv)) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100630 carry = uECC_vli_add(uv, uv, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300631 }
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100632 uECC_vli_rshift1(uv);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300633 if (carry) {
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100634 uv[NUM_ECC_WORDS - 1] |= HIGH_BIT_SET;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300635 }
636}
637
638void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100639 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300640{
641 uECC_word_t a[NUM_ECC_WORDS], b[NUM_ECC_WORDS];
642 uECC_word_t u[NUM_ECC_WORDS], v[NUM_ECC_WORDS];
643 cmpresult_t cmpResult;
644
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100645 if (uECC_vli_isZero(input)) {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100646 uECC_vli_clear(result);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300647 return;
648 }
649
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100650 uECC_vli_set(a, input);
651 uECC_vli_set(b, mod);
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100652 uECC_vli_clear(u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300653 u[0] = 1;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100654 uECC_vli_clear(v);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100655 while ((cmpResult = uECC_vli_cmp_unsafe(a, b)) != 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300656 if (EVEN(a)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100657 uECC_vli_rshift1(a);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100658 vli_modInv_update(u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300659 } else if (EVEN(b)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100660 uECC_vli_rshift1(b);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100661 vli_modInv_update(v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300662 } else if (cmpResult > 0) {
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100663 uECC_vli_sub(a, a, b);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100664 uECC_vli_rshift1(a);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100665 if (uECC_vli_cmp_unsafe(u, v) < 0) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100666 uECC_vli_add(u, u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300667 }
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100668 uECC_vli_sub(u, u, v);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100669 vli_modInv_update(u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300670 } else {
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100671 uECC_vli_sub(b, b, a);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100672 uECC_vli_rshift1(b);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100673 if (uECC_vli_cmp_unsafe(v, u) < 0) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100674 uECC_vli_add(v, v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300675 }
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100676 uECC_vli_sub(v, v, u);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100677 vli_modInv_update(v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300678 }
679 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100680 uECC_vli_set(result, u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300681}
682
683/* ------ Point operations ------ */
684
685void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100686 uECC_word_t * Z1)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300687{
688 /* t1 = X, t2 = Y, t3 = Z */
689 uECC_word_t t4[NUM_ECC_WORDS];
690 uECC_word_t t5[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +0100691 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300692
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100693 if (uECC_vli_isZero(Z1)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300694 return;
695 }
696
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100697 uECC_vli_modMult_fast(t4, Y1, Y1); /* t4 = y1^2 */
698 uECC_vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */
699 uECC_vli_modMult_fast(t4, t4, t4); /* t4 = y1^4 */
700 uECC_vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */
701 uECC_vli_modMult_fast(Z1, Z1, Z1); /* t3 = z1^2 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300702
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100703 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */
704 uECC_vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */
705 uECC_vli_modSub(Z1, X1, Z1, curve_p); /* t3 = x1 - z1^2 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100706 uECC_vli_modMult_fast(X1, X1, Z1); /* t1 = x1^2 - z1^4 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300707
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100708 uECC_vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */
709 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300710 if (uECC_vli_testBit(X1, 0)) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100711 uECC_word_t l_carry = uECC_vli_add(X1, X1, curve_p);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100712 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300713 X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
714 } else {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100715 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300716 }
717
718 /* t1 = 3/2*(x1^2 - z1^4) = B */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100719 uECC_vli_modMult_fast(Z1, X1, X1); /* t3 = B^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100720 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - A */
721 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */
722 uECC_vli_modSub(t5, t5, Z1, curve_p); /* t5 = A - x3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100723 uECC_vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300724 /* t4 = B * (A - x3) - y1^4 = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100725 uECC_vli_modSub(t4, X1, t4, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300726
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100727 uECC_vli_set(X1, Z1);
728 uECC_vli_set(Z1, Y1);
729 uECC_vli_set(Y1, t4);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300730}
731
Manuel Pégourié-Gonnard1c6f7ea2019-11-21 09:18:29 +0100732/*
733 * @brief Computes x^3 + ax + b. result must not overlap x.
734 * @param result OUT -- x^3 + ax + b
735 * @param x IN -- value of x
736 * @param curve IN -- elliptic curve
737 */
738static void x_side_default(uECC_word_t *result,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100739 const uECC_word_t *x)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300740{
741 uECC_word_t _3[NUM_ECC_WORDS] = {3}; /* -a = 3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300742
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100743 uECC_vli_modMult_fast(result, x, x); /* r = x^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100744 uECC_vli_modSub(result, result, _3, curve_p); /* r = x^2 - 3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100745 uECC_vli_modMult_fast(result, result, x); /* r = x^3 - 3x */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300746 /* r = x^3 - 3x + b: */
Manuel Pégourié-Gonnardffd13992019-11-21 10:39:06 +0100747 uECC_vli_modAdd(result, result, curve_b, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300748}
749
Jarno Lamsa18987a42019-04-24 15:40:43 +0300750void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int*product)
751{
752 unsigned int tmp[NUM_ECC_WORDS];
753 int carry;
754
755 /* t */
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100756 uECC_vli_set(result, product);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300757
758 /* s1 */
759 tmp[0] = tmp[1] = tmp[2] = 0;
760 tmp[3] = product[11];
761 tmp[4] = product[12];
762 tmp[5] = product[13];
763 tmp[6] = product[14];
764 tmp[7] = product[15];
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 /* s2 */
769 tmp[3] = product[12];
770 tmp[4] = product[13];
771 tmp[5] = product[14];
772 tmp[6] = product[15];
773 tmp[7] = 0;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100774 carry += uECC_vli_add(tmp, tmp, tmp);
775 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300776
777 /* s3 */
778 tmp[0] = product[8];
779 tmp[1] = product[9];
780 tmp[2] = product[10];
781 tmp[3] = tmp[4] = tmp[5] = 0;
782 tmp[6] = product[14];
783 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100784 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300785
786 /* s4 */
787 tmp[0] = product[9];
788 tmp[1] = product[10];
789 tmp[2] = product[11];
790 tmp[3] = product[13];
791 tmp[4] = product[14];
792 tmp[5] = product[15];
793 tmp[6] = product[13];
794 tmp[7] = product[8];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100795 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300796
797 /* d1 */
798 tmp[0] = product[11];
799 tmp[1] = product[12];
800 tmp[2] = product[13];
801 tmp[3] = tmp[4] = tmp[5] = 0;
802 tmp[6] = product[8];
803 tmp[7] = product[10];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100804 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300805
806 /* d2 */
807 tmp[0] = product[12];
808 tmp[1] = product[13];
809 tmp[2] = product[14];
810 tmp[3] = product[15];
811 tmp[4] = tmp[5] = 0;
812 tmp[6] = product[9];
813 tmp[7] = product[11];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100814 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300815
816 /* d3 */
817 tmp[0] = product[13];
818 tmp[1] = product[14];
819 tmp[2] = product[15];
820 tmp[3] = product[8];
821 tmp[4] = product[9];
822 tmp[5] = product[10];
823 tmp[6] = 0;
824 tmp[7] = product[12];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100825 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300826
827 /* d4 */
828 tmp[0] = product[14];
829 tmp[1] = product[15];
830 tmp[2] = 0;
831 tmp[3] = product[9];
832 tmp[4] = product[10];
833 tmp[5] = product[11];
834 tmp[6] = 0;
835 tmp[7] = product[13];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100836 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300837
838 if (carry < 0) {
839 do {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100840 carry += uECC_vli_add(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300841 }
842 while (carry < 0);
843 } else {
844 while (carry ||
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100845 uECC_vli_cmp_unsafe(curve_p, result) != 1) {
846 carry -= uECC_vli_sub(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300847 }
848 }
849}
850
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100851uECC_word_t EccPoint_isZero(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300852{
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100853 return uECC_vli_isZero(point);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300854}
855
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100856void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300857{
858 uECC_word_t t1[NUM_ECC_WORDS];
859
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100860 uECC_vli_modMult_fast(t1, Z, Z); /* z^2 */
861 uECC_vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */
862 uECC_vli_modMult_fast(t1, t1, Z); /* z^3 */
863 uECC_vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300864}
865
866/* P = (x1, y1) => 2P, (x2, y2) => P' */
867static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1,
868 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100869 const uECC_word_t * const initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300870{
871 uECC_word_t z[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300872 if (initial_Z) {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100873 uECC_vli_set(z, initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300874 } else {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100875 uECC_vli_clear(z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300876 z[0] = 1;
877 }
878
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100879 uECC_vli_set(X2, X1);
880 uECC_vli_set(Y2, Y1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300881
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100882 apply_z(X1, Y1, z);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100883 double_jacobian_default(X1, Y1, z);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100884 apply_z(X2, Y2, z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300885}
886
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100887static void XYcZ_add_rnd(uECC_word_t * X1, uECC_word_t * Y1,
888 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100889 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300890{
891 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
892 uECC_word_t t5[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100893
894 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100895 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100896 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
897 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100898 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100899 uECC_vli_modMult_rnd(t5, Y2, Y2, s); /* t5 = (y2 - y1)^2 = D */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300900
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100901 uECC_vli_modSub(t5, t5, X1, curve_p); /* t5 = D - B */
902 uECC_vli_modSub(t5, t5, X2, curve_p); /* t5 = D - B - C = x3 */
903 uECC_vli_modSub(X2, X2, X1, curve_p); /* t3 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100904 uECC_vli_modMult_rnd(Y1, Y1, X2, s); /* t2 = y1*(C - B) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100905 uECC_vli_modSub(X2, X1, t5, curve_p); /* t3 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100906 uECC_vli_modMult_rnd(Y2, Y2, X2, s); /* t4 = (y2 - y1)*(B - x3) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100907 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300908
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100909 uECC_vli_set(X2, t5);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300910}
911
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100912void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100913 uECC_word_t * X2, uECC_word_t * Y2)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100914{
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100915 XYcZ_add_rnd(X1, Y1, X2, Y2, NULL);
916}
917
Jarno Lamsa18987a42019-04-24 15:40:43 +0300918/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
919 Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
920 or P => P - Q, Q => P + Q
921 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100922static void XYcZ_addC_rnd(uECC_word_t * X1, uECC_word_t * Y1,
923 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100924 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300925{
926 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
927 uECC_word_t t5[NUM_ECC_WORDS];
928 uECC_word_t t6[NUM_ECC_WORDS];
929 uECC_word_t t7[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100930
931 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100932 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100933 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
934 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100935 uECC_vli_modAdd(t5, Y2, Y1, curve_p); /* t5 = y2 + y1 */
936 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300937
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100938 uECC_vli_modSub(t6, X2, X1, curve_p); /* t6 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100939 uECC_vli_modMult_rnd(Y1, Y1, t6, s); /* t2 = y1 * (C - B) = E */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100940 uECC_vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100941 uECC_vli_modMult_rnd(X2, Y2, Y2, s); /* t3 = (y2 - y1)^2 = D */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100942 uECC_vli_modSub(X2, X2, t6, curve_p); /* t3 = D - (B + C) = x3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300943
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100944 uECC_vli_modSub(t7, X1, X2, curve_p); /* t7 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100945 uECC_vli_modMult_rnd(Y2, Y2, t7, s); /* t4 = (y2 - y1)*(B - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300946 /* t4 = (y2 - y1)*(B - x3) - E = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100947 uECC_vli_modSub(Y2, Y2, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300948
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100949 uECC_vli_modMult_rnd(t7, t5, t5, s); /* t7 = (y2 + y1)^2 = F */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100950 uECC_vli_modSub(t7, t7, t6, curve_p); /* t7 = F - (B + C) = x3' */
951 uECC_vli_modSub(t6, t7, X1, curve_p); /* t6 = x3' - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100952 uECC_vli_modMult_rnd(t6, t6, t5, s); /* t6 = (y2+y1)*(x3' - B) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300953 /* t2 = (y2+y1)*(x3' - B) - E = y3': */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100954 uECC_vli_modSub(Y1, t6, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300955
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100956 uECC_vli_set(X1, t7);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300957}
958
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +0100959static void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point,
Jarno Lamsa18987a42019-04-24 15:40:43 +0300960 const uECC_word_t * scalar,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +0100961 const uECC_word_t * initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300962{
963 /* R0 and R1 */
964 uECC_word_t Rx[2][NUM_ECC_WORDS];
965 uECC_word_t Ry[2][NUM_ECC_WORDS];
966 uECC_word_t z[NUM_ECC_WORDS];
967 bitcount_t i;
968 uECC_word_t nb;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100969 const wordcount_t num_words = NUM_ECC_WORDS;
970 const bitcount_t num_bits = NUM_ECC_BITS + 1; /* from regularize_k */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100971 ecc_wait_state_t wait_state;
972 ecc_wait_state_t * const ws = g_rng_function ? &wait_state : NULL;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300973
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100974 uECC_vli_set(Rx[1], point);
975 uECC_vli_set(Ry[1], point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300976
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100977 XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300978
979 for (i = num_bits - 2; i > 0; --i) {
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100980 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300981 nb = !uECC_vli_testBit(scalar, i);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100982 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
983 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300984 }
985
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100986 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300987 nb = !uECC_vli_testBit(scalar, 0);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100988 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300989
990 /* Find final 1/Z value. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100991 uECC_vli_modSub(z, Rx[1], Rx[0], curve_p); /* X1 - X0 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100992 uECC_vli_modMult_fast(z, z, Ry[1 - nb]); /* Yb * (X1 - X0) */
993 uECC_vli_modMult_fast(z, z, point); /* xP * Yb * (X1 - X0) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100994 uECC_vli_modInv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0))*/
Jarno Lamsa18987a42019-04-24 15:40:43 +0300995 /* yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100996 uECC_vli_modMult_fast(z, z, point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300997 /* Xb * yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100998 uECC_vli_modMult_fast(z, z, Rx[1 - nb]);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300999 /* End 1/Z calculation */
1000
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001001 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001002 apply_z(Rx[0], Ry[0], z);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001003
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +01001004 uECC_vli_set(result, Rx[0]);
1005 uECC_vli_set(result + num_words, Ry[0]);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001006}
1007
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +01001008static uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001009 uECC_word_t *k1)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001010{
1011
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001012 wordcount_t num_n_words = NUM_ECC_WORDS;
1013 bitcount_t num_n_bits = NUM_ECC_BITS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001014
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001015 uECC_word_t carry = uECC_vli_add(k0, k, curve_n) ||
Jarno Lamsa18987a42019-04-24 15:40:43 +03001016 (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) &&
1017 uECC_vli_testBit(k0, num_n_bits));
1018
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001019 uECC_vli_add(k1, k0, curve_n);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001020
1021 return carry;
1022}
1023
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001024int EccPoint_mult_safer(uECC_word_t * result, const uECC_word_t * point,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001025 const uECC_word_t * scalar)
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001026{
1027 uECC_word_t tmp[NUM_ECC_WORDS];
1028 uECC_word_t s[NUM_ECC_WORDS];
1029 uECC_word_t *k2[2] = {tmp, s};
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001030 wordcount_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001031 uECC_word_t carry;
1032 uECC_word_t *initial_Z = 0;
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001033 int r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001034 volatile int problem;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001035
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001036 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001037 problem = -1;
1038 problem = uECC_check_curve_integrity();
1039 if (problem != 0) {
1040 return UECC_FAULT_DETECTED;
1041 }
1042 mbedtls_platform_enforce_volatile_reads();
1043 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001044 return UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001045 }
1046
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001047 /* Protects against invalid curve attacks */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001048 problem = -1;
1049 problem = uECC_valid_point(point);
1050 if (problem != 0) {
1051 /* invalid input, can happen without fault */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001052 return UECC_FAILURE;
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001053 }
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001054 mbedtls_platform_enforce_volatile_reads();
1055 if (problem != 0) {
1056 /* failure on second check means fault, though */
1057 return UECC_FAULT_DETECTED;
1058 }
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001059
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001060 /* Regularize the bitcount for the private key so that attackers cannot use a
1061 * side channel attack to learn the number of leading zeros. */
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001062 carry = regularize_k(scalar, tmp, s);
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001063
1064 /* If an RNG function was specified, get a random initial Z value to
1065 * protect against side-channel attacks such as Template SPA */
1066 if (g_rng_function) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001067 if (!uECC_generate_random_int(k2[carry], curve_p, num_words)) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001068 r = UECC_FAILURE;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001069 goto clear_and_out;
1070 }
1071 initial_Z = k2[carry];
1072 }
1073
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001074 EccPoint_mult(result, point, k2[!carry], initial_Z);
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001075
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001076 /* Protect against fault injections that would make the resulting
1077 * point not lie on the intended curve */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001078 problem = -1;
1079 problem = uECC_valid_point(result);
1080 if (problem != 0) {
1081 r = UECC_FAULT_DETECTED;
1082 goto clear_and_out;
1083 }
1084 mbedtls_platform_enforce_volatile_reads();
1085 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001086 r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001087 goto clear_and_out;
1088 }
1089
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001090 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001091 problem = -1;
1092 problem = uECC_check_curve_integrity();
1093 if (problem != 0) {
1094 r = UECC_FAULT_DETECTED;
1095 goto clear_and_out;
1096 }
1097 mbedtls_platform_enforce_volatile_reads();
1098 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001099 r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001100 goto clear_and_out;
1101 }
1102
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001103 r = UECC_SUCCESS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001104
1105clear_and_out:
1106 /* erasing temporary buffer used to store secret: */
1107 mbedtls_platform_zeroize(k2, sizeof(k2));
1108 mbedtls_platform_zeroize(tmp, sizeof(tmp));
1109 mbedtls_platform_zeroize(s, sizeof(s));
1110
1111 return r;
1112}
1113
Jarno Lamsa18987a42019-04-24 15:40:43 +03001114uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001115 uECC_word_t *private_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001116{
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001117 return EccPoint_mult_safer(result, curve_G, private_key);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001118}
1119
1120/* Converts an integer in uECC native format to big-endian bytes. */
1121void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
1122 const unsigned int *native)
1123{
1124 wordcount_t i;
1125 for (i = 0; i < num_bytes; ++i) {
1126 unsigned b = num_bytes - 1 - i;
1127 bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE));
1128 }
1129}
1130
1131/* Converts big-endian bytes to an integer in uECC native format. */
1132void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes,
1133 int num_bytes)
1134{
1135 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +01001136 uECC_vli_clear(native);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001137 for (i = 0; i < num_bytes; ++i) {
1138 unsigned b = num_bytes - 1 - i;
1139 native[b / uECC_WORD_SIZE] |=
1140 (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE));
1141 }
1142}
1143
1144int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
1145 wordcount_t num_words)
1146{
1147 uECC_word_t mask = (uECC_word_t)-1;
1148 uECC_word_t tries;
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +01001149 bitcount_t num_bits = uECC_vli_numBits(top);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001150
1151 if (!g_rng_function) {
1152 return 0;
1153 }
1154
1155 for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
1156 if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) {
1157 return 0;
1158 }
1159 random[num_words - 1] &=
1160 mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits));
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001161 if (!uECC_vli_isZero(random) &&
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +01001162 uECC_vli_cmp(top, random) == 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001163 return 1;
1164 }
1165 }
1166 return 0;
1167}
1168
1169
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001170int uECC_valid_point(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001171{
1172 uECC_word_t tmp1[NUM_ECC_WORDS];
1173 uECC_word_t tmp2[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001174 wordcount_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001175 volatile uECC_word_t diff = -1u;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001176
1177 /* The point at infinity is invalid. */
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001178 if (EccPoint_isZero(point)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001179 return -1;
1180 }
1181
1182 /* x and y must be smaller than p. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001183 if (uECC_vli_cmp_unsafe(curve_p, point) != 1 ||
1184 uECC_vli_cmp_unsafe(curve_p, point + num_words) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001185 return -2;
1186 }
1187
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001188 uECC_vli_modMult_fast(tmp1, point + num_words, point + num_words);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001189 x_side_default(tmp2, point); /* tmp2 = x^3 + ax + b */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001190
1191 /* Make sure that y^2 == x^3 + ax + b */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001192 diff = uECC_vli_equal(tmp1, tmp2);
1193 if (diff == 0) {
1194 mbedtls_platform_enforce_volatile_reads();
1195 if (diff == 0) {
1196 return 0;
1197 }
1198 }
Jarno Lamsa18987a42019-04-24 15:40:43 +03001199
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001200 return -3;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001201}
1202
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001203int uECC_valid_public_key(const uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001204{
1205
1206 uECC_word_t _public[NUM_ECC_WORDS * 2];
1207
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001208 uECC_vli_bytesToNative(_public, public_key, NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001209 uECC_vli_bytesToNative(
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001210 _public + NUM_ECC_WORDS,
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001211 public_key + NUM_ECC_BYTES,
1212 NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001213
Manuel Pégourié-Gonnarda6115082019-11-21 10:29:14 +01001214 if (memcmp(_public, curve_G, NUM_ECC_WORDS * 2) == 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001215 return -4;
1216 }
1217
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001218 return uECC_valid_point(_public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001219}
1220
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001221int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001222{
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001223 int ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001224 uECC_word_t _private[NUM_ECC_WORDS];
1225 uECC_word_t _public[NUM_ECC_WORDS * 2];
1226
1227 uECC_vli_bytesToNative(
1228 _private,
1229 private_key,
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +01001230 BITS_TO_BYTES(NUM_ECC_BITS));
Jarno Lamsa18987a42019-04-24 15:40:43 +03001231
1232 /* Make sure the private key is in the range [1, n-1]. */
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001233 if (uECC_vli_isZero(_private)) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001234 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001235 }
1236
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001237 if (uECC_vli_cmp(curve_n, _private) != 1) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001238 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001239 }
1240
1241 /* Compute public key. */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001242 ret = EccPoint_compute_public_key(_public, _private);
1243 if (ret != UECC_SUCCESS) {
1244 return ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001245 }
1246
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001247 uECC_vli_nativeToBytes(public_key, NUM_ECC_BYTES, _public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001248 uECC_vli_nativeToBytes(
1249 public_key +
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001250 NUM_ECC_BYTES, NUM_ECC_BYTES, _public + NUM_ECC_WORDS);
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001251 return UECC_SUCCESS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001252}
Jarno Lamsa46132202019-04-29 14:29:52 +03001253#else
Manuel Pégourié-Gonnardafdc1b52019-05-09 11:24:11 +02001254typedef int mbedtls_dummy_tinycrypt_def;
1255#endif /* MBEDTLS_USE_TINYCRYPT */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001256