blob: bf54fe8e7931edb36d77fe1ae76000d66eff2a00 [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 *
Andrzej Kurek0919b142020-07-06 15:28:59 -040036 * - Redistributions of source code must retain the above copyright notice,
37 * this list of conditions and the following disclaimer.
Jarno Lamsa18987a42019-04-24 15:40:43 +030038 *
Andrzej Kurek0919b142020-07-06 15:28:59 -040039 * - 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.
Jarno Lamsa18987a42019-04-24 15:40:43 +030042 *
Andrzej Kurek0919b142020-07-06 15:28:59 -040043 * - 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.
Jarno Lamsa18987a42019-04-24 15:40:43 +030046 *
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,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400102 const uECC_word_t val[NUM_ECC_WORDS])
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100103{
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 ||
Andrzej Kurek0919b142020-07-06 15:28:59 -0400122 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)
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100126 {
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 Nowickif0ab6d62020-05-25 12:48:30 +0200293 /* Start from a random location and check the correct number of iterations */
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200294 int start_offset = mbedtls_platform_random_in_range(NUM_ECC_WORDS);
295
296 for (i = start_offset; i < NUM_ECC_WORDS; ++i) {
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100297 tmp1 = left[i];
298 tmp2 = right[i];
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200299 flow_monitor++;
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100300 diff |= (tmp1 ^ tmp2);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300301 }
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100302
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200303 for (i = 0; i < start_offset; ++i) {
304 tmp1 = left[i];
305 tmp2 = right[i];
306 flow_monitor++;
307 diff |= (tmp1 ^ tmp2);
308 }
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100309
Piotr Nowickif0ab6d62020-05-25 12:48:30 +0200310 /* Random delay to increase security */
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200311 mbedtls_platform_random_delay();
312
313 /* Return 0 only when diff is 0 and flow_counter is equal to NUM_ECC_WORDS */
314 return (diff | (flow_monitor ^ NUM_ECC_WORDS));
Jarno Lamsa18987a42019-04-24 15:40:43 +0300315}
316
317uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond)
318{
319 return (p_true*(cond)) | (p_false*(!cond));
320}
321
322/* Computes result = left - right, returning borrow, in constant time.
323 * Can modify in place. */
324uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100325 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300326{
327 uECC_word_t borrow = 0;
328 wordcount_t i;
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100329 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300330 uECC_word_t diff = left[i] - right[i] - borrow;
331 uECC_word_t val = (diff > left[i]);
332 borrow = cond_set(val, borrow, (diff != left[i]));
333
334 result[i] = diff;
335 }
336 return borrow;
337}
338
339/* Computes result = left + right, returning carry, in constant time.
340 * Can modify in place. */
341static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100342 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300343{
344 uECC_word_t carry = 0;
345 wordcount_t i;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100346 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300347 uECC_word_t sum = left[i] + right[i] + carry;
348 uECC_word_t val = (sum < left[i]);
349 carry = cond_set(val, carry, (sum != left[i]));
350 result[i] = sum;
351 }
352 return carry;
353}
354
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +0100355cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300356{
357 uECC_word_t tmp[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100358 uECC_word_t neg = !!uECC_vli_sub(tmp, left, right);
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100359 uECC_word_t equal = uECC_vli_isZero(tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300360 return (!equal - 2 * neg);
361}
362
363/* Computes vli = vli >> 1. */
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100364static void uECC_vli_rshift1(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300365{
366 uECC_word_t *end = vli;
367 uECC_word_t carry = 0;
368
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100369 vli += NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300370 while (vli-- > end) {
371 uECC_word_t temp = *vli;
372 *vli = (temp >> 1) | carry;
373 carry = temp << (uECC_WORD_BITS - 1);
374 }
375}
376
Manuel Pégourié-Gonnard86c4f812019-10-31 13:02:03 +0100377/* Compute a * b + r, where r is a double-word with high-order word r1 and
378 * low-order word r0, and store the result in the same double-word (r1, r0),
379 * with the carry bit stored in r2.
380 *
381 * (r2, r1, r0) = a * b + (r1, r0):
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200382 * [in] a, b: operands to be multiplied
383 * [in] r0, r1: low and high-order words of operand to add
384 * [out] r0, r1: low and high-order words of the result
385 * [out] r2: carry
386 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300387static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0,
388 uECC_word_t *r1, uECC_word_t *r2)
389{
390
391 uECC_dword_t p = (uECC_dword_t)a * b;
392 uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
393 r01 += p;
394 *r2 += (r01 < p);
395 *r1 = r01 >> uECC_WORD_BITS;
396 *r0 = (uECC_word_t)r01;
397
398}
399
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200400/* State for implementing random delays in uECC_vli_mult_rnd().
401 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100402 * The state is initialized by randomizing delays and setting i = 0.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200403 * Each call to uECC_vli_mult_rnd() uses one byte of delays and increments i.
404 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100405 * Randomized vli multiplication is used only for point operations
406 * (XYcZ_add_rnd() * and XYcZ_addC_rnd()) in scalar multiplication
407 * (ECCPoint_mult()). Those go in pair, and each pair does 14 calls to
408 * uECC_vli_mult_rnd() (6 in XYcZ_add_rnd() and 8 in XYcZ_addC_rnd(),
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100409 * indirectly through uECC_vli_modMult_rnd().
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100410 *
411 * Considering this, in order to minimize the number of calls to the RNG
412 * (which impact performance) while keeping the size of the structure low,
413 * make room for 14 randomized vli mults, which corresponds to one step in the
414 * scalar multiplication routine.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200415 */
416typedef struct {
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100417 uint8_t i;
418 uint8_t delays[14];
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100419} ecc_wait_state_t;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200420
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100421/*
422 * Reset wait_state so that it's ready to be used.
423 */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100424void ecc_wait_state_reset(ecc_wait_state_t *ws)
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100425{
426 if (ws == NULL)
427 return;
428
429 ws->i = 0;
430 g_rng_function(ws->delays, sizeof(ws->delays));
431}
432
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200433/* Computes result = left * right. Result must be 2 * num_words long.
434 *
435 * As a counter-measure against horizontal attacks, add noise by performing
436 * a random number of extra computations performing random additional accesses
437 * to limbs of the input.
438 *
439 * Each of the two actual computation loops is surrounded by two
440 * similar-looking waiting loops, to make the beginning and end of the actual
441 * computation harder to spot.
442 *
443 * We add 4 waiting loops of between 0 and 3 calls to muladd() each. That
444 * makes an average of 6 extra calls. Compared to the main computation which
445 * makes 64 such calls, this represents an average performance degradation of
446 * less than 10%.
447 *
448 * Compared to the original uECC_vli_mult(), loose the num_words argument as we
449 * know it's always 8. This saves a bit of code size and execution speed.
450 */
451static void uECC_vli_mult_rnd(uECC_word_t *result, const uECC_word_t *left,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400452 const uECC_word_t *right, ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300453{
454
455 uECC_word_t r0 = 0;
456 uECC_word_t r1 = 0;
457 uECC_word_t r2 = 0;
458 wordcount_t i, k;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100459 const uint8_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200460
461 /* Fetch 8 bit worth of delay from the state; 0 if we have no state */
462 uint8_t delays = s ? s->delays[s->i++] : 0;
463 uECC_word_t rr0 = 0, rr1 = 0;
464 volatile uECC_word_t r;
465
466 /* Mimic start of next loop: k in [0, 3] */
467 k = 0 + (delays & 0x03);
468 delays >>= 2;
469 /* k = 0 -> i in [1, 0] -> 0 extra muladd;
470 * k = 3 -> i in [1, 3] -> 3 extra muladd */
Manuel Pégourié-Gonnardc8814862019-11-05 10:32:37 +0100471 for (i = 1; i <= k; ++i) {
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200472 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
473 }
474 r = rr0;
475 rr0 = rr1;
476 rr1 = r2;
477 r2 = 0;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300478
479 /* Compute each digit of result in sequence, maintaining the carries. */
480 for (k = 0; k < num_words; ++k) {
481
482 for (i = 0; i <= k; ++i) {
483 muladd(left[i], right[k - i], &r0, &r1, &r2);
484 }
485
486 result[k] = r0;
487 r0 = r1;
488 r1 = r2;
489 r2 = 0;
490 }
491
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200492 /* Mimic end of previous loop: k in [4, 7] */
493 k = 4 + (delays & 0x03);
494 delays >>= 2;
495 /* k = 4 -> i in [5, 4] -> 0 extra muladd;
496 * k = 7 -> i in [5, 7] -> 3 extra muladd */
497 for (i = 5; i <= k; ++i) {
498 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
499 }
500 r = rr0;
501 rr0 = rr1;
502 rr1 = r2;
503 r2 = 0;
504
505 /* Mimic start of next loop: k in [8, 11] */
506 k = 11 - (delays & 0x03);
507 delays >>= 2;
508 /* k = 8 -> i in [5, 7] -> 3 extra muladd;
509 * k = 11 -> i in [8, 7] -> 0 extra muladd */
510 for (i = (k + 5) - num_words; i < num_words; ++i) {
511 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
512 }
513 r = rr0;
514 rr0 = rr1;
515 rr1 = r2;
516 r2 = 0;
517
Jarno Lamsa18987a42019-04-24 15:40:43 +0300518 for (k = num_words; k < num_words * 2 - 1; ++k) {
519
520 for (i = (k + 1) - num_words; i < num_words; ++i) {
521 muladd(left[i], right[k - i], &r0, &r1, &r2);
522 }
523 result[k] = r0;
524 r0 = r1;
525 r1 = r2;
526 r2 = 0;
527 }
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200528
Jarno Lamsa18987a42019-04-24 15:40:43 +0300529 result[num_words * 2 - 1] = r0;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200530
531 /* Mimic end of previous loop: k in [12, 15] */
532 k = 15 - (delays & 0x03);
533 delays >>= 2;
534 /* k = 12 -> i in [5, 7] -> 3 extra muladd;
535 * k = 15 -> i in [8, 7] -> 0 extra muladd */
536 for (i = (k + 1) - num_words; i < num_words; ++i) {
537 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
538 }
539 r = rr0;
540 rr0 = rr1;
541 rr1 = r2;
542 r2 = 0;
543
544 /* avoid warning that r is set but not used */
545 (void) r;
546}
547
Jarno Lamsa18987a42019-04-24 15:40:43 +0300548void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400549 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300550{
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100551 uECC_word_t carry = uECC_vli_add(result, left, right);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100552 if (carry || uECC_vli_cmp_unsafe(mod, result) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300553 /* result > mod (result = mod + remainder), so subtract mod to get
554 * remainder. */
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100555 uECC_vli_sub(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300556 }
557}
558
559void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400560 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300561{
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100562 uECC_word_t l_borrow = uECC_vli_sub(result, left, right);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300563 if (l_borrow) {
564 /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
565 * we can get the correct result from result + mod (with overflow). */
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100566 uECC_vli_add(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300567 }
568}
569
570/* Computes result = product % mod, where product is 2N words long. */
571/* Currently only designed to work for curve_p or curve_n. */
572void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400573 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300574{
575 uECC_word_t mod_multiple[2 * NUM_ECC_WORDS];
576 uECC_word_t tmp[2 * NUM_ECC_WORDS];
577 uECC_word_t *v[2] = {tmp, product};
578 uECC_word_t index;
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100579 const wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300580
581 /* Shift mod so its highest set bit is at the maximum position. */
582 bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) -
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100583 uECC_vli_numBits(mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300584 wordcount_t word_shift = shift / uECC_WORD_BITS;
585 wordcount_t bit_shift = shift % uECC_WORD_BITS;
586 uECC_word_t carry = 0;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100587 uECC_vli_clear(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300588 if (bit_shift > 0) {
589 for(index = 0; index < (uECC_word_t)num_words; ++index) {
590 mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;
591 carry = mod[index] >> (uECC_WORD_BITS - bit_shift);
592 }
593 } else {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100594 uECC_vli_set(mod_multiple + word_shift, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300595 }
596
597 for (index = 1; shift >= 0; --shift) {
598 uECC_word_t borrow = 0;
599 wordcount_t i;
600 for (i = 0; i < num_words * 2; ++i) {
601 uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;
602 if (diff != v[index][i]) {
603 borrow = (diff > v[index][i]);
604 }
605 v[1 - index][i] = diff;
606 }
607 /* Swap the index if there was no borrow */
608 index = !(index ^ borrow);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100609 uECC_vli_rshift1(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300610 mod_multiple[num_words - 1] |= mod_multiple[num_words] <<
Andrzej Kurek0919b142020-07-06 15:28:59 -0400611 (uECC_WORD_BITS - 1);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100612 uECC_vli_rshift1(mod_multiple + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300613 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100614 uECC_vli_set(result, v[index]);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300615}
616
617void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400618 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300619{
620 uECC_word_t product[2 * NUM_ECC_WORDS];
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100621 uECC_vli_mult_rnd(product, left, right, NULL);
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100622 uECC_vli_mmod(result, product, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300623}
624
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100625static void uECC_vli_modMult_rnd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100626 const uECC_word_t *right, ecc_wait_state_t *s)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100627{
628 uECC_word_t product[2 * NUM_ECC_WORDS];
629 uECC_vli_mult_rnd(product, left, right, s);
630
631 vli_mmod_fast_secp256r1(result, product);
632}
633
Jarno Lamsa18987a42019-04-24 15:40:43 +0300634void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100635 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300636{
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100637 uECC_vli_modMult_rnd(result, left, right, NULL);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300638}
639
Jarno Lamsa18987a42019-04-24 15:40:43 +0300640#define EVEN(vli) (!(vli[0] & 1))
641
642static void vli_modInv_update(uECC_word_t *uv,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400643 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300644{
645
646 uECC_word_t carry = 0;
647
648 if (!EVEN(uv)) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100649 carry = uECC_vli_add(uv, uv, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300650 }
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100651 uECC_vli_rshift1(uv);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300652 if (carry) {
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100653 uv[NUM_ECC_WORDS - 1] |= HIGH_BIT_SET;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300654 }
655}
656
657void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400658 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300659{
660 uECC_word_t a[NUM_ECC_WORDS], b[NUM_ECC_WORDS];
661 uECC_word_t u[NUM_ECC_WORDS], v[NUM_ECC_WORDS];
662 cmpresult_t cmpResult;
663
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100664 if (uECC_vli_isZero(input)) {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100665 uECC_vli_clear(result);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300666 return;
667 }
668
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100669 uECC_vli_set(a, input);
670 uECC_vli_set(b, mod);
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100671 uECC_vli_clear(u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300672 u[0] = 1;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100673 uECC_vli_clear(v);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100674 while ((cmpResult = uECC_vli_cmp_unsafe(a, b)) != 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300675 if (EVEN(a)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100676 uECC_vli_rshift1(a);
Andrzej Kurek0919b142020-07-06 15:28:59 -0400677 vli_modInv_update(u, mod);
678 } else if (EVEN(b)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100679 uECC_vli_rshift1(b);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100680 vli_modInv_update(v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300681 } else if (cmpResult > 0) {
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100682 uECC_vli_sub(a, a, b);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100683 uECC_vli_rshift1(a);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100684 if (uECC_vli_cmp_unsafe(u, v) < 0) {
Andrzej Kurek0919b142020-07-06 15:28:59 -0400685 uECC_vli_add(u, u, mod);
686 }
687 uECC_vli_sub(u, u, v);
688 vli_modInv_update(u, mod);
689 } else {
690 uECC_vli_sub(b, b, a);
691 uECC_vli_rshift1(b);
692 if (uECC_vli_cmp_unsafe(v, u) < 0) {
693 uECC_vli_add(v, v, mod);
694 }
695 uECC_vli_sub(v, v, u);
696 vli_modInv_update(v, mod);
697 }
Jarno Lamsa18987a42019-04-24 15:40:43 +0300698 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100699 uECC_vli_set(result, u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300700}
701
702/* ------ Point operations ------ */
703
704void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400705 uECC_word_t * Z1)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300706{
707 /* t1 = X, t2 = Y, t3 = Z */
708 uECC_word_t t4[NUM_ECC_WORDS];
709 uECC_word_t t5[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +0100710 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300711
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100712 if (uECC_vli_isZero(Z1)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300713 return;
714 }
715
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100716 uECC_vli_modMult_fast(t4, Y1, Y1); /* t4 = y1^2 */
717 uECC_vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */
718 uECC_vli_modMult_fast(t4, t4, t4); /* t4 = y1^4 */
719 uECC_vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */
720 uECC_vli_modMult_fast(Z1, Z1, Z1); /* t3 = z1^2 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300721
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100722 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */
723 uECC_vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */
724 uECC_vli_modSub(Z1, X1, Z1, curve_p); /* t3 = x1 - z1^2 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100725 uECC_vli_modMult_fast(X1, X1, Z1); /* t1 = x1^2 - z1^4 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300726
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100727 uECC_vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */
728 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300729 if (uECC_vli_testBit(X1, 0)) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100730 uECC_word_t l_carry = uECC_vli_add(X1, X1, curve_p);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100731 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300732 X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
733 } else {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100734 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300735 }
736
737 /* t1 = 3/2*(x1^2 - z1^4) = B */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100738 uECC_vli_modMult_fast(Z1, X1, X1); /* t3 = B^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100739 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - A */
740 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */
741 uECC_vli_modSub(t5, t5, Z1, curve_p); /* t5 = A - x3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100742 uECC_vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300743 /* t4 = B * (A - x3) - y1^4 = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100744 uECC_vli_modSub(t4, X1, t4, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300745
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100746 uECC_vli_set(X1, Z1);
747 uECC_vli_set(Z1, Y1);
748 uECC_vli_set(Y1, t4);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300749}
750
Manuel Pégourié-Gonnard1c6f7ea2019-11-21 09:18:29 +0100751/*
752 * @brief Computes x^3 + ax + b. result must not overlap x.
753 * @param result OUT -- x^3 + ax + b
754 * @param x IN -- value of x
755 * @param curve IN -- elliptic curve
756 */
757static void x_side_default(uECC_word_t *result,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400758 const uECC_word_t *x)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300759{
760 uECC_word_t _3[NUM_ECC_WORDS] = {3}; /* -a = 3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300761
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100762 uECC_vli_modMult_fast(result, x, x); /* r = x^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100763 uECC_vli_modSub(result, result, _3, curve_p); /* r = x^2 - 3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100764 uECC_vli_modMult_fast(result, result, x); /* r = x^3 - 3x */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300765 /* r = x^3 - 3x + b: */
Manuel Pégourié-Gonnardffd13992019-11-21 10:39:06 +0100766 uECC_vli_modAdd(result, result, curve_b, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300767}
768
769void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int*product)
770{
771 unsigned int tmp[NUM_ECC_WORDS];
772 int carry;
773
774 /* t */
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100775 uECC_vli_set(result, product);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300776
777 /* s1 */
778 tmp[0] = tmp[1] = tmp[2] = 0;
779 tmp[3] = product[11];
780 tmp[4] = product[12];
781 tmp[5] = product[13];
782 tmp[6] = product[14];
783 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100784 carry = uECC_vli_add(tmp, tmp, tmp);
785 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300786
787 /* s2 */
788 tmp[3] = product[12];
789 tmp[4] = product[13];
790 tmp[5] = product[14];
791 tmp[6] = product[15];
792 tmp[7] = 0;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100793 carry += uECC_vli_add(tmp, tmp, tmp);
794 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300795
796 /* s3 */
797 tmp[0] = product[8];
798 tmp[1] = product[9];
799 tmp[2] = product[10];
800 tmp[3] = tmp[4] = tmp[5] = 0;
801 tmp[6] = product[14];
802 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100803 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300804
805 /* s4 */
806 tmp[0] = product[9];
807 tmp[1] = product[10];
808 tmp[2] = product[11];
809 tmp[3] = product[13];
810 tmp[4] = product[14];
811 tmp[5] = product[15];
812 tmp[6] = product[13];
813 tmp[7] = product[8];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100814 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300815
816 /* d1 */
817 tmp[0] = product[11];
818 tmp[1] = product[12];
819 tmp[2] = product[13];
820 tmp[3] = tmp[4] = tmp[5] = 0;
821 tmp[6] = product[8];
822 tmp[7] = product[10];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100823 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300824
825 /* d2 */
826 tmp[0] = product[12];
827 tmp[1] = product[13];
828 tmp[2] = product[14];
829 tmp[3] = product[15];
830 tmp[4] = tmp[5] = 0;
831 tmp[6] = product[9];
832 tmp[7] = product[11];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100833 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300834
835 /* d3 */
836 tmp[0] = product[13];
837 tmp[1] = product[14];
838 tmp[2] = product[15];
839 tmp[3] = product[8];
840 tmp[4] = product[9];
841 tmp[5] = product[10];
842 tmp[6] = 0;
843 tmp[7] = product[12];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100844 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300845
846 /* d4 */
847 tmp[0] = product[14];
848 tmp[1] = product[15];
849 tmp[2] = 0;
850 tmp[3] = product[9];
851 tmp[4] = product[10];
852 tmp[5] = product[11];
853 tmp[6] = 0;
854 tmp[7] = product[13];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100855 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300856
857 if (carry < 0) {
858 do {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100859 carry += uECC_vli_add(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300860 }
861 while (carry < 0);
862 } else {
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200863 while (carry ||
Andrzej Kurek0919b142020-07-06 15:28:59 -0400864 uECC_vli_cmp_unsafe(curve_p, result) != 1) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100865 carry -= uECC_vli_sub(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300866 }
867 }
868}
869
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100870uECC_word_t EccPoint_isZero(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300871{
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100872 return uECC_vli_isZero(point);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300873}
874
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100875void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300876{
877 uECC_word_t t1[NUM_ECC_WORDS];
878
Andrzej Kurek0919b142020-07-06 15:28:59 -0400879 uECC_vli_modMult_fast(t1, Z, Z); /* z^2 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100880 uECC_vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */
881 uECC_vli_modMult_fast(t1, t1, Z); /* z^3 */
882 uECC_vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300883}
884
885/* P = (x1, y1) => 2P, (x2, y2) => P' */
886static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1,
887 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100888 const uECC_word_t * const initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300889{
890 uECC_word_t z[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300891 if (initial_Z) {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100892 uECC_vli_set(z, initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300893 } else {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100894 uECC_vli_clear(z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300895 z[0] = 1;
896 }
897
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100898 uECC_vli_set(X2, X1);
899 uECC_vli_set(Y2, Y1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300900
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100901 apply_z(X1, Y1, z);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100902 double_jacobian_default(X1, Y1, z);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100903 apply_z(X2, Y2, z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300904}
905
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100906static void XYcZ_add_rnd(uECC_word_t * X1, uECC_word_t * Y1,
907 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100908 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300909{
910 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
911 uECC_word_t t5[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300912
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100913 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100914 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100915 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
916 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100917 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100918 uECC_vli_modMult_rnd(t5, Y2, Y2, s); /* t5 = (y2 - y1)^2 = D */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300919
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100920 uECC_vli_modSub(t5, t5, X1, curve_p); /* t5 = D - B */
921 uECC_vli_modSub(t5, t5, X2, curve_p); /* t5 = D - B - C = x3 */
922 uECC_vli_modSub(X2, X2, X1, curve_p); /* t3 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100923 uECC_vli_modMult_rnd(Y1, Y1, X2, s); /* t2 = y1*(C - B) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100924 uECC_vli_modSub(X2, X1, t5, curve_p); /* t3 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100925 uECC_vli_modMult_rnd(Y2, Y2, X2, s); /* t4 = (y2 - y1)*(B - x3) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100926 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300927
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100928 uECC_vli_set(X2, t5);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300929}
930
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100931void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400932 uECC_word_t * X2, uECC_word_t * Y2)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100933{
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100934 XYcZ_add_rnd(X1, Y1, X2, Y2, NULL);
935}
936
Jarno Lamsa18987a42019-04-24 15:40:43 +0300937/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
938 Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
939 or P => P - Q, Q => P + Q
940 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100941static void XYcZ_addC_rnd(uECC_word_t * X1, uECC_word_t * Y1,
942 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100943 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300944{
945 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
946 uECC_word_t t5[NUM_ECC_WORDS];
947 uECC_word_t t6[NUM_ECC_WORDS];
948 uECC_word_t t7[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300949
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100950 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100951 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100952 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
953 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100954 uECC_vli_modAdd(t5, Y2, Y1, curve_p); /* t5 = y2 + y1 */
955 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300956
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100957 uECC_vli_modSub(t6, X2, X1, curve_p); /* t6 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100958 uECC_vli_modMult_rnd(Y1, Y1, t6, s); /* t2 = y1 * (C - B) = E */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100959 uECC_vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100960 uECC_vli_modMult_rnd(X2, Y2, Y2, s); /* t3 = (y2 - y1)^2 = D */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100961 uECC_vli_modSub(X2, X2, t6, curve_p); /* t3 = D - (B + C) = x3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300962
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100963 uECC_vli_modSub(t7, X1, X2, curve_p); /* t7 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100964 uECC_vli_modMult_rnd(Y2, Y2, t7, s); /* t4 = (y2 - y1)*(B - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300965 /* t4 = (y2 - y1)*(B - x3) - E = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100966 uECC_vli_modSub(Y2, Y2, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300967
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100968 uECC_vli_modMult_rnd(t7, t5, t5, s); /* t7 = (y2 + y1)^2 = F */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100969 uECC_vli_modSub(t7, t7, t6, curve_p); /* t7 = F - (B + C) = x3' */
970 uECC_vli_modSub(t6, t7, X1, curve_p); /* t6 = x3' - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100971 uECC_vli_modMult_rnd(t6, t6, t5, s); /* t6 = (y2+y1)*(x3' - B) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300972 /* t2 = (y2+y1)*(x3' - B) - E = y3': */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100973 uECC_vli_modSub(Y1, t6, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300974
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100975 uECC_vli_set(X1, t7);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300976}
977
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +0100978static void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point,
Jarno Lamsa18987a42019-04-24 15:40:43 +0300979 const uECC_word_t * scalar,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +0100980 const uECC_word_t * initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300981{
982 /* R0 and R1 */
983 uECC_word_t Rx[2][NUM_ECC_WORDS];
984 uECC_word_t Ry[2][NUM_ECC_WORDS];
985 uECC_word_t z[NUM_ECC_WORDS];
986 bitcount_t i;
987 uECC_word_t nb;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100988 const wordcount_t num_words = NUM_ECC_WORDS;
989 const bitcount_t num_bits = NUM_ECC_BITS + 1; /* from regularize_k */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100990 ecc_wait_state_t wait_state;
991 ecc_wait_state_t * const ws = g_rng_function ? &wait_state : NULL;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300992
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100993 uECC_vli_set(Rx[1], point);
994 uECC_vli_set(Ry[1], point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300995
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100996 XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300997
998 for (i = num_bits - 2; i > 0; --i) {
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100999 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001000 nb = !uECC_vli_testBit(scalar, i);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001001 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
1002 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001003 }
1004
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +01001005 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001006 nb = !uECC_vli_testBit(scalar, 0);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001007 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001008
1009 /* Find final 1/Z value. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001010 uECC_vli_modSub(z, Rx[1], Rx[0], curve_p); /* X1 - X0 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001011 uECC_vli_modMult_fast(z, z, Ry[1 - nb]); /* Yb * (X1 - X0) */
1012 uECC_vli_modMult_fast(z, z, point); /* xP * Yb * (X1 - X0) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001013 uECC_vli_modInv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0))*/
Jarno Lamsa18987a42019-04-24 15:40:43 +03001014 /* yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001015 uECC_vli_modMult_fast(z, z, point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001016 /* Xb * yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001017 uECC_vli_modMult_fast(z, z, Rx[1 - nb]);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001018 /* End 1/Z calculation */
1019
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001020 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001021 apply_z(Rx[0], Ry[0], z);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001022
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +01001023 uECC_vli_set(result, Rx[0]);
1024 uECC_vli_set(result + num_words, Ry[0]);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001025}
1026
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +01001027static uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001028 uECC_word_t *k1)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001029{
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001030 bitcount_t num_n_bits = NUM_ECC_BITS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001031
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001032 uECC_word_t carry = uECC_vli_add(k0, k, curve_n) ||
Andrzej Kurek0919b142020-07-06 15:28:59 -04001033 uECC_vli_testBit(k0, num_n_bits);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001034
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001035 uECC_vli_add(k1, k0, curve_n);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001036
1037 return carry;
1038}
1039
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001040int EccPoint_mult_safer(uECC_word_t * result, const uECC_word_t * point,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001041 const uECC_word_t * scalar)
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001042{
1043 uECC_word_t tmp[NUM_ECC_WORDS];
1044 uECC_word_t s[NUM_ECC_WORDS];
1045 uECC_word_t *k2[2] = {tmp, s};
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001046 wordcount_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001047 uECC_word_t carry;
1048 uECC_word_t *initial_Z = 0;
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001049 int r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001050 volatile int problem;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001051
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001052 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001053 problem = -1;
1054 problem = uECC_check_curve_integrity();
1055 if (problem != 0) {
1056 return UECC_FAULT_DETECTED;
1057 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001058 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001059 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001060 return UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001061 }
1062
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001063 /* Protects against invalid curve attacks */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001064 problem = -1;
1065 problem = uECC_valid_point(point);
1066 if (problem != 0) {
1067 /* invalid input, can happen without fault */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001068 return UECC_FAILURE;
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001069 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001070 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001071 if (problem != 0) {
1072 /* failure on second check means fault, though */
1073 return UECC_FAULT_DETECTED;
1074 }
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001075
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001076 /* Regularize the bitcount for the private key so that attackers cannot use a
1077 * side channel attack to learn the number of leading zeros. */
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001078 carry = regularize_k(scalar, tmp, s);
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001079
1080 /* If an RNG function was specified, get a random initial Z value to
Andrzej Kurek0919b142020-07-06 15:28:59 -04001081 * protect against side-channel attacks such as Template SPA */
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001082 if (g_rng_function) {
Andrzej Kurek3a0df032020-06-12 06:32:13 -04001083 if (uECC_generate_random_int(k2[carry], curve_p, num_words) != UECC_SUCCESS) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001084 r = UECC_FAILURE;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001085 goto clear_and_out;
1086 }
1087 initial_Z = k2[carry];
1088 }
1089
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001090 EccPoint_mult(result, point, k2[!carry], initial_Z);
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001091
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001092 /* Protect against fault injections that would make the resulting
1093 * point not lie on the intended curve */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001094 problem = -1;
1095 problem = uECC_valid_point(result);
1096 if (problem != 0) {
1097 r = UECC_FAULT_DETECTED;
1098 goto clear_and_out;
1099 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001100 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001101 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001102 r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001103 goto clear_and_out;
1104 }
1105
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001106 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001107 problem = -1;
1108 problem = uECC_check_curve_integrity();
1109 if (problem != 0) {
1110 r = UECC_FAULT_DETECTED;
1111 goto clear_and_out;
1112 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001113 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001114 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001115 r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001116 goto clear_and_out;
1117 }
1118
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001119 r = UECC_SUCCESS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001120
1121clear_and_out:
1122 /* erasing temporary buffer used to store secret: */
1123 mbedtls_platform_zeroize(k2, sizeof(k2));
1124 mbedtls_platform_zeroize(tmp, sizeof(tmp));
1125 mbedtls_platform_zeroize(s, sizeof(s));
1126
1127 return r;
1128}
1129
Jarno Lamsa18987a42019-04-24 15:40:43 +03001130uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001131 uECC_word_t *private_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001132{
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001133 return EccPoint_mult_safer(result, curve_G, private_key);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001134}
1135
1136/* Converts an integer in uECC native format to big-endian bytes. */
1137void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
Andrzej Kurek0919b142020-07-06 15:28:59 -04001138 const unsigned int *native)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001139{
1140 wordcount_t i;
1141 for (i = 0; i < num_bytes; ++i) {
1142 unsigned b = num_bytes - 1 - i;
1143 bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE));
1144 }
1145}
1146
1147/* Converts big-endian bytes to an integer in uECC native format. */
1148void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes,
Andrzej Kurek0919b142020-07-06 15:28:59 -04001149 int num_bytes)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001150{
1151 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +01001152 uECC_vli_clear(native);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001153 for (i = 0; i < num_bytes; ++i) {
1154 unsigned b = num_bytes - 1 - i;
1155 native[b / uECC_WORD_SIZE] |=
1156 (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE));
1157 }
1158}
1159
1160int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
Andrzej Kurek0919b142020-07-06 15:28:59 -04001161 wordcount_t num_words)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001162{
1163 uECC_word_t mask = (uECC_word_t)-1;
1164 uECC_word_t tries;
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +01001165 bitcount_t num_bits = uECC_vli_numBits(top);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001166
1167 if (!g_rng_function) {
Andrzej Kurek3a0df032020-06-12 06:32:13 -04001168 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001169 }
1170
1171 for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
Andrzej Kurek090365f2020-06-08 11:00:51 -04001172 if (g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE) != num_words * uECC_WORD_SIZE) {
Andrzej Kurek0919b142020-07-06 15:28:59 -04001173 return UECC_FAILURE;
1174 }
Jarno Lamsa18987a42019-04-24 15:40:43 +03001175 random[num_words - 1] &=
Andrzej Kurek0919b142020-07-06 15:28:59 -04001176 mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits));
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001177 if (!uECC_vli_isZero(random) &&
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +01001178 uECC_vli_cmp(top, random) == 1) {
Andrzej Kurek3a0df032020-06-12 06:32:13 -04001179 return UECC_SUCCESS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001180 }
1181 }
Andrzej Kurek3a0df032020-06-12 06:32:13 -04001182 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001183}
1184
1185
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001186int uECC_valid_point(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001187{
1188 uECC_word_t tmp1[NUM_ECC_WORDS];
1189 uECC_word_t tmp2[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001190 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa83d78812019-12-04 14:40:57 +02001191 volatile uECC_word_t diff = 0xffffffff;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001192
1193 /* The point at infinity is invalid. */
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001194 if (EccPoint_isZero(point)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001195 return -1;
1196 }
1197
1198 /* x and y must be smaller than p. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001199 if (uECC_vli_cmp_unsafe(curve_p, point) != 1 ||
1200 uECC_vli_cmp_unsafe(curve_p, point + num_words) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001201 return -2;
1202 }
1203
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001204 uECC_vli_modMult_fast(tmp1, point + num_words, point + num_words);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001205 x_side_default(tmp2, point); /* tmp2 = x^3 + ax + b */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001206
1207 /* Make sure that y^2 == x^3 + ax + b */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001208 diff = uECC_vli_equal(tmp1, tmp2);
1209 if (diff == 0) {
Andrzej Kurek0919b142020-07-06 15:28:59 -04001210 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001211 if (diff == 0) {
1212 return 0;
1213 }
1214 }
Jarno Lamsa18987a42019-04-24 15:40:43 +03001215
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001216 return -3;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001217}
1218
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001219int uECC_valid_public_key(const uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001220{
1221
1222 uECC_word_t _public[NUM_ECC_WORDS * 2];
1223
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001224 uECC_vli_bytesToNative(_public, public_key, NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001225 uECC_vli_bytesToNative(
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001226 _public + NUM_ECC_WORDS,
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001227 public_key + NUM_ECC_BYTES,
1228 NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001229
Manuel Pégourié-Gonnarda6115082019-11-21 10:29:14 +01001230 if (memcmp(_public, curve_G, NUM_ECC_WORDS * 2) == 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001231 return -4;
1232 }
1233
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001234 return uECC_valid_point(_public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001235}
1236
Andrzej Kurek0919b142020-07-06 15:28:59 -04001237int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001238{
Andrzej Kurekfd56f402020-05-25 11:52:05 -04001239 int ret = UECC_FAULT_DETECTED;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001240 uECC_word_t _private[NUM_ECC_WORDS];
1241 uECC_word_t _public[NUM_ECC_WORDS * 2];
1242
1243 uECC_vli_bytesToNative(
1244 _private,
1245 private_key,
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +01001246 BITS_TO_BYTES(NUM_ECC_BITS));
Jarno Lamsa18987a42019-04-24 15:40:43 +03001247
1248 /* Make sure the private key is in the range [1, n-1]. */
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001249 if (uECC_vli_isZero(_private)) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001250 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001251 }
1252
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001253 if (uECC_vli_cmp(curve_n, _private) != 1) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001254 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001255 }
1256
1257 /* Compute public key. */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001258 ret = EccPoint_compute_public_key(_public, _private);
1259 if (ret != UECC_SUCCESS) {
1260 return ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001261 }
1262
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001263 uECC_vli_nativeToBytes(public_key, NUM_ECC_BYTES, _public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001264 uECC_vli_nativeToBytes(
1265 public_key +
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001266 NUM_ECC_BYTES, NUM_ECC_BYTES, _public + NUM_ECC_WORDS);
Andrzej Kurekcf3e35c2020-07-15 22:32:08 -04001267
Andrzej Kurekfd56f402020-05-25 11:52:05 -04001268 return ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001269}