blob: aeb6447f3bee738feb1b323776cc193deaa0b748 [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>
Shelly Liberman05beb9a2020-09-13 15:23:56 +030070#include "mbedtls/platform_util.h"
Jarno Lamsa18987a42019-04-24 15:40:43 +030071
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,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400103 const uECC_word_t val[NUM_ECC_WORDS])
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100104{
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 ||
Andrzej Kurek0919b142020-07-06 15:28:59 -0400123 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)
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100127 {
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 };
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100156 unsigned char diff = 0;
157 unsigned char tmp1, tmp2;
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100158 volatile unsigned i;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100159
160 if (uECC_compute_param_sha256(computed) != UECC_SUCCESS) {
161 return UECC_FAILURE;
162 }
163
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100164 for (i = 0; i < 32; i++) {
165 /* make sure the order of volatile accesses is well-defined */
166 tmp1 = computed[i];
167 tmp2 = reference[i];
168 diff |= tmp1 ^ tmp2;
169 }
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100170
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100171 /* i should be 32 */
Arto Kinnunenac6d2262020-01-09 10:11:20 +0200172 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100173 diff |= (unsigned char) i ^ 32;
174
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100175 return diff;
176}
177
Jarno Lamsa18987a42019-04-24 15:40:43 +0300178/* IMPORTANT: Make sure a cryptographically-secure PRNG is set and the platform
179 * has access to enough entropy in order to feed the PRNG regularly. */
180#if default_RNG_defined
181static uECC_RNG_Function g_rng_function = &default_CSPRNG;
182#else
183static uECC_RNG_Function g_rng_function = 0;
184#endif
185
186void uECC_set_rng(uECC_RNG_Function rng_function)
187{
188 g_rng_function = rng_function;
189}
190
191uECC_RNG_Function uECC_get_rng(void)
192{
193 return g_rng_function;
194}
195
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +0100196int uECC_curve_private_key_size(void)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300197{
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +0100198 return BITS_TO_BYTES(NUM_ECC_BITS);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300199}
200
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +0100201int uECC_curve_public_key_size(void)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300202{
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +0100203 return 2 * NUM_ECC_BYTES;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300204}
205
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100206void uECC_vli_clear(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300207{
208 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100209 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300210 vli[i] = 0;
211 }
212}
213
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100214uECC_word_t uECC_vli_isZero(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300215{
216 uECC_word_t bits = 0;
217 wordcount_t i;
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100218 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300219 bits |= vli[i];
220 }
221 return (bits == 0);
222}
223
224uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit)
225{
226 return (vli[bit >> uECC_WORD_BITS_SHIFT] &
227 ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));
228}
229
230/* Counts the number of words in vli. */
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100231static wordcount_t vli_numDigits(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300232{
233
234 wordcount_t i;
235 /* Search from the end until we find a non-zero digit. We do it in reverse
236 * because we expect that most digits will be nonzero. */
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100237 for (i = NUM_ECC_WORDS - 1; i >= 0 && vli[i] == 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300238 }
239
240 return (i + 1);
241}
242
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100243bitcount_t uECC_vli_numBits(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300244{
245
246 uECC_word_t i;
247 uECC_word_t digit;
248
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100249 wordcount_t num_digits = vli_numDigits(vli);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300250 if (num_digits == 0) {
251 return 0;
252 }
253
254 digit = vli[num_digits - 1];
255 for (i = 0; digit; ++i) {
256 digit >>= 1;
257 }
258
259 return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);
260}
261
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100262void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300263{
264 wordcount_t i;
265
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100266 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300267 dest[i] = src[i];
268 }
269}
270
271cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100272 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300273{
274 wordcount_t i;
275
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100276 for (i = NUM_ECC_WORDS - 1; i >= 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300277 if (left[i] > right[i]) {
278 return 1;
279 } else if (left[i] < right[i]) {
280 return -1;
281 }
282 }
283 return 0;
284}
285
Manuel Pégourié-Gonnard2eca3d32019-11-04 14:33:09 +0100286uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300287{
288
289 uECC_word_t diff = 0;
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200290 uECC_word_t flow_monitor = 0;
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100291 uECC_word_t tmp1, tmp2;
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100292 volatile int i;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300293
Piotr Nowickif0ab6d62020-05-25 12:48:30 +0200294 /* Start from a random location and check the correct number of iterations */
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200295 int start_offset = mbedtls_platform_random_in_range(NUM_ECC_WORDS);
296
297 for (i = start_offset; i < NUM_ECC_WORDS; ++i) {
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100298 tmp1 = left[i];
299 tmp2 = right[i];
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200300 flow_monitor++;
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100301 diff |= (tmp1 ^ tmp2);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300302 }
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100303
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200304 for (i = 0; i < start_offset; ++i) {
305 tmp1 = left[i];
306 tmp2 = right[i];
307 flow_monitor++;
308 diff |= (tmp1 ^ tmp2);
309 }
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100310
Piotr Nowickif0ab6d62020-05-25 12:48:30 +0200311 /* Random delay to increase security */
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200312 mbedtls_platform_random_delay();
313
314 /* Return 0 only when diff is 0 and flow_counter is equal to NUM_ECC_WORDS */
315 return (diff | (flow_monitor ^ NUM_ECC_WORDS));
Jarno Lamsa18987a42019-04-24 15:40:43 +0300316}
317
318uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond)
319{
320 return (p_true*(cond)) | (p_false*(!cond));
321}
322
323/* Computes result = left - right, returning borrow, in constant time.
324 * Can modify in place. */
325uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100326 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300327{
328 uECC_word_t borrow = 0;
329 wordcount_t i;
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100330 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300331 uECC_word_t diff = left[i] - right[i] - borrow;
332 uECC_word_t val = (diff > left[i]);
333 borrow = cond_set(val, borrow, (diff != left[i]));
334
335 result[i] = diff;
336 }
337 return borrow;
338}
339
340/* Computes result = left + right, returning carry, in constant time.
341 * Can modify in place. */
342static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100343 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300344{
345 uECC_word_t carry = 0;
346 wordcount_t i;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100347 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300348 uECC_word_t sum = left[i] + right[i] + carry;
349 uECC_word_t val = (sum < left[i]);
350 carry = cond_set(val, carry, (sum != left[i]));
351 result[i] = sum;
352 }
353 return carry;
354}
355
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +0100356cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300357{
358 uECC_word_t tmp[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100359 uECC_word_t neg = !!uECC_vli_sub(tmp, left, right);
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100360 uECC_word_t equal = uECC_vli_isZero(tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300361 return (!equal - 2 * neg);
362}
363
364/* Computes vli = vli >> 1. */
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100365static void uECC_vli_rshift1(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300366{
367 uECC_word_t *end = vli;
368 uECC_word_t carry = 0;
369
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100370 vli += NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300371 while (vli-- > end) {
372 uECC_word_t temp = *vli;
373 *vli = (temp >> 1) | carry;
374 carry = temp << (uECC_WORD_BITS - 1);
375 }
376}
377
Manuel Pégourié-Gonnard86c4f812019-10-31 13:02:03 +0100378/* Compute a * b + r, where r is a double-word with high-order word r1 and
379 * low-order word r0, and store the result in the same double-word (r1, r0),
380 * with the carry bit stored in r2.
381 *
382 * (r2, r1, r0) = a * b + (r1, r0):
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200383 * [in] a, b: operands to be multiplied
384 * [in] r0, r1: low and high-order words of operand to add
385 * [out] r0, r1: low and high-order words of the result
386 * [out] r2: carry
387 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300388static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0,
389 uECC_word_t *r1, uECC_word_t *r2)
390{
391
392 uECC_dword_t p = (uECC_dword_t)a * b;
393 uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
394 r01 += p;
395 *r2 += (r01 < p);
396 *r1 = r01 >> uECC_WORD_BITS;
397 *r0 = (uECC_word_t)r01;
398
399}
400
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200401/* State for implementing random delays in uECC_vli_mult_rnd().
402 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100403 * The state is initialized by randomizing delays and setting i = 0.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200404 * Each call to uECC_vli_mult_rnd() uses one byte of delays and increments i.
405 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100406 * Randomized vli multiplication is used only for point operations
407 * (XYcZ_add_rnd() * and XYcZ_addC_rnd()) in scalar multiplication
408 * (ECCPoint_mult()). Those go in pair, and each pair does 14 calls to
409 * uECC_vli_mult_rnd() (6 in XYcZ_add_rnd() and 8 in XYcZ_addC_rnd(),
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100410 * indirectly through uECC_vli_modMult_rnd().
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100411 *
412 * Considering this, in order to minimize the number of calls to the RNG
413 * (which impact performance) while keeping the size of the structure low,
414 * make room for 14 randomized vli mults, which corresponds to one step in the
415 * scalar multiplication routine.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200416 */
417typedef struct {
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100418 uint8_t i;
419 uint8_t delays[14];
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100420} ecc_wait_state_t;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200421
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100422/*
423 * Reset wait_state so that it's ready to be used.
424 */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100425void ecc_wait_state_reset(ecc_wait_state_t *ws)
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100426{
427 if (ws == NULL)
428 return;
429
430 ws->i = 0;
Shelly Liberman05beb9a2020-09-13 15:23:56 +0300431 mbedtls_platform_random_buf(ws->delays, sizeof(ws->delays));
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100432}
433
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200434/* Computes result = left * right. Result must be 2 * num_words long.
435 *
436 * As a counter-measure against horizontal attacks, add noise by performing
437 * a random number of extra computations performing random additional accesses
438 * to limbs of the input.
439 *
440 * Each of the two actual computation loops is surrounded by two
441 * similar-looking waiting loops, to make the beginning and end of the actual
442 * computation harder to spot.
443 *
444 * We add 4 waiting loops of between 0 and 3 calls to muladd() each. That
445 * makes an average of 6 extra calls. Compared to the main computation which
446 * makes 64 such calls, this represents an average performance degradation of
447 * less than 10%.
448 *
449 * Compared to the original uECC_vli_mult(), loose the num_words argument as we
450 * know it's always 8. This saves a bit of code size and execution speed.
451 */
452static void uECC_vli_mult_rnd(uECC_word_t *result, const uECC_word_t *left,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400453 const uECC_word_t *right, ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300454{
455
456 uECC_word_t r0 = 0;
457 uECC_word_t r1 = 0;
458 uECC_word_t r2 = 0;
459 wordcount_t i, k;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100460 const uint8_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200461
462 /* Fetch 8 bit worth of delay from the state; 0 if we have no state */
463 uint8_t delays = s ? s->delays[s->i++] : 0;
464 uECC_word_t rr0 = 0, rr1 = 0;
465 volatile uECC_word_t r;
466
467 /* Mimic start of next loop: k in [0, 3] */
468 k = 0 + (delays & 0x03);
469 delays >>= 2;
470 /* k = 0 -> i in [1, 0] -> 0 extra muladd;
471 * k = 3 -> i in [1, 3] -> 3 extra muladd */
Manuel Pégourié-Gonnardc8814862019-11-05 10:32:37 +0100472 for (i = 1; i <= k; ++i) {
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200473 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
474 }
475 r = rr0;
476 rr0 = rr1;
477 rr1 = r2;
478 r2 = 0;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300479
480 /* Compute each digit of result in sequence, maintaining the carries. */
481 for (k = 0; k < num_words; ++k) {
482
483 for (i = 0; i <= k; ++i) {
484 muladd(left[i], right[k - i], &r0, &r1, &r2);
485 }
486
487 result[k] = r0;
488 r0 = r1;
489 r1 = r2;
490 r2 = 0;
491 }
492
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200493 /* Mimic end of previous loop: k in [4, 7] */
494 k = 4 + (delays & 0x03);
495 delays >>= 2;
496 /* k = 4 -> i in [5, 4] -> 0 extra muladd;
497 * k = 7 -> i in [5, 7] -> 3 extra muladd */
498 for (i = 5; i <= k; ++i) {
499 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
500 }
501 r = rr0;
502 rr0 = rr1;
503 rr1 = r2;
504 r2 = 0;
505
506 /* Mimic start of next loop: k in [8, 11] */
507 k = 11 - (delays & 0x03);
508 delays >>= 2;
509 /* k = 8 -> i in [5, 7] -> 3 extra muladd;
510 * k = 11 -> i in [8, 7] -> 0 extra muladd */
511 for (i = (k + 5) - num_words; i < num_words; ++i) {
512 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
513 }
514 r = rr0;
515 rr0 = rr1;
516 rr1 = r2;
517 r2 = 0;
518
Jarno Lamsa18987a42019-04-24 15:40:43 +0300519 for (k = num_words; k < num_words * 2 - 1; ++k) {
520
521 for (i = (k + 1) - num_words; i < num_words; ++i) {
522 muladd(left[i], right[k - i], &r0, &r1, &r2);
523 }
524 result[k] = r0;
525 r0 = r1;
526 r1 = r2;
527 r2 = 0;
528 }
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200529
Jarno Lamsa18987a42019-04-24 15:40:43 +0300530 result[num_words * 2 - 1] = r0;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200531
532 /* Mimic end of previous loop: k in [12, 15] */
533 k = 15 - (delays & 0x03);
534 delays >>= 2;
535 /* k = 12 -> i in [5, 7] -> 3 extra muladd;
536 * k = 15 -> i in [8, 7] -> 0 extra muladd */
537 for (i = (k + 1) - num_words; i < num_words; ++i) {
538 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
539 }
540 r = rr0;
541 rr0 = rr1;
542 rr1 = r2;
543 r2 = 0;
544
545 /* avoid warning that r is set but not used */
546 (void) r;
547}
548
Jarno Lamsa18987a42019-04-24 15:40:43 +0300549void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400550 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300551{
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100552 uECC_word_t carry = uECC_vli_add(result, left, right);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100553 if (carry || uECC_vli_cmp_unsafe(mod, result) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300554 /* result > mod (result = mod + remainder), so subtract mod to get
555 * remainder. */
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100556 uECC_vli_sub(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300557 }
558}
559
560void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400561 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300562{
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100563 uECC_word_t l_borrow = uECC_vli_sub(result, left, right);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300564 if (l_borrow) {
565 /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
566 * we can get the correct result from result + mod (with overflow). */
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100567 uECC_vli_add(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300568 }
569}
570
571/* Computes result = product % mod, where product is 2N words long. */
572/* Currently only designed to work for curve_p or curve_n. */
573void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400574 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300575{
576 uECC_word_t mod_multiple[2 * NUM_ECC_WORDS];
577 uECC_word_t tmp[2 * NUM_ECC_WORDS];
578 uECC_word_t *v[2] = {tmp, product};
579 uECC_word_t index;
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100580 const wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300581
582 /* Shift mod so its highest set bit is at the maximum position. */
583 bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) -
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100584 uECC_vli_numBits(mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300585 wordcount_t word_shift = shift / uECC_WORD_BITS;
586 wordcount_t bit_shift = shift % uECC_WORD_BITS;
587 uECC_word_t carry = 0;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100588 uECC_vli_clear(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300589 if (bit_shift > 0) {
590 for(index = 0; index < (uECC_word_t)num_words; ++index) {
591 mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;
592 carry = mod[index] >> (uECC_WORD_BITS - bit_shift);
593 }
594 } else {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100595 uECC_vli_set(mod_multiple + word_shift, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300596 }
597
598 for (index = 1; shift >= 0; --shift) {
599 uECC_word_t borrow = 0;
600 wordcount_t i;
601 for (i = 0; i < num_words * 2; ++i) {
602 uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;
603 if (diff != v[index][i]) {
604 borrow = (diff > v[index][i]);
605 }
606 v[1 - index][i] = diff;
607 }
608 /* Swap the index if there was no borrow */
609 index = !(index ^ borrow);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100610 uECC_vli_rshift1(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300611 mod_multiple[num_words - 1] |= mod_multiple[num_words] <<
Andrzej Kurek0919b142020-07-06 15:28:59 -0400612 (uECC_WORD_BITS - 1);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100613 uECC_vli_rshift1(mod_multiple + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300614 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100615 uECC_vli_set(result, v[index]);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300616}
617
618void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400619 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300620{
621 uECC_word_t product[2 * NUM_ECC_WORDS];
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100622 uECC_vli_mult_rnd(product, left, right, NULL);
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100623 uECC_vli_mmod(result, product, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300624}
625
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100626static void uECC_vli_modMult_rnd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100627 const uECC_word_t *right, ecc_wait_state_t *s)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100628{
629 uECC_word_t product[2 * NUM_ECC_WORDS];
630 uECC_vli_mult_rnd(product, left, right, s);
631
632 vli_mmod_fast_secp256r1(result, product);
633}
634
Jarno Lamsa18987a42019-04-24 15:40:43 +0300635void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100636 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300637{
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100638 uECC_vli_modMult_rnd(result, left, right, NULL);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300639}
640
Jarno Lamsa18987a42019-04-24 15:40:43 +0300641#define EVEN(vli) (!(vli[0] & 1))
642
643static void vli_modInv_update(uECC_word_t *uv,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400644 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300645{
646
647 uECC_word_t carry = 0;
648
649 if (!EVEN(uv)) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100650 carry = uECC_vli_add(uv, uv, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300651 }
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100652 uECC_vli_rshift1(uv);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300653 if (carry) {
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100654 uv[NUM_ECC_WORDS - 1] |= HIGH_BIT_SET;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300655 }
656}
657
658void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400659 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300660{
661 uECC_word_t a[NUM_ECC_WORDS], b[NUM_ECC_WORDS];
662 uECC_word_t u[NUM_ECC_WORDS], v[NUM_ECC_WORDS];
663 cmpresult_t cmpResult;
664
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100665 if (uECC_vli_isZero(input)) {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100666 uECC_vli_clear(result);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300667 return;
668 }
669
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100670 uECC_vli_set(a, input);
671 uECC_vli_set(b, mod);
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100672 uECC_vli_clear(u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300673 u[0] = 1;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100674 uECC_vli_clear(v);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100675 while ((cmpResult = uECC_vli_cmp_unsafe(a, b)) != 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300676 if (EVEN(a)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100677 uECC_vli_rshift1(a);
Andrzej Kurek0919b142020-07-06 15:28:59 -0400678 vli_modInv_update(u, mod);
679 } else if (EVEN(b)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100680 uECC_vli_rshift1(b);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100681 vli_modInv_update(v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300682 } else if (cmpResult > 0) {
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100683 uECC_vli_sub(a, a, b);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100684 uECC_vli_rshift1(a);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100685 if (uECC_vli_cmp_unsafe(u, v) < 0) {
Andrzej Kurek0919b142020-07-06 15:28:59 -0400686 uECC_vli_add(u, u, mod);
687 }
688 uECC_vli_sub(u, u, v);
689 vli_modInv_update(u, mod);
690 } else {
691 uECC_vli_sub(b, b, a);
692 uECC_vli_rshift1(b);
693 if (uECC_vli_cmp_unsafe(v, u) < 0) {
694 uECC_vli_add(v, v, mod);
695 }
696 uECC_vli_sub(v, v, u);
697 vli_modInv_update(v, mod);
698 }
Jarno Lamsa18987a42019-04-24 15:40:43 +0300699 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100700 uECC_vli_set(result, u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300701}
702
703/* ------ Point operations ------ */
704
705void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400706 uECC_word_t * Z1)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300707{
708 /* t1 = X, t2 = Y, t3 = Z */
709 uECC_word_t t4[NUM_ECC_WORDS];
710 uECC_word_t t5[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +0100711 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300712
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100713 if (uECC_vli_isZero(Z1)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300714 return;
715 }
716
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100717 uECC_vli_modMult_fast(t4, Y1, Y1); /* t4 = y1^2 */
718 uECC_vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */
719 uECC_vli_modMult_fast(t4, t4, t4); /* t4 = y1^4 */
720 uECC_vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */
721 uECC_vli_modMult_fast(Z1, Z1, Z1); /* t3 = z1^2 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300722
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100723 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */
724 uECC_vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */
725 uECC_vli_modSub(Z1, X1, Z1, curve_p); /* t3 = x1 - z1^2 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100726 uECC_vli_modMult_fast(X1, X1, Z1); /* t1 = x1^2 - z1^4 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300727
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100728 uECC_vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */
729 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300730 if (uECC_vli_testBit(X1, 0)) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100731 uECC_word_t l_carry = uECC_vli_add(X1, X1, curve_p);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100732 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300733 X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
734 } else {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100735 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300736 }
737
738 /* t1 = 3/2*(x1^2 - z1^4) = B */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100739 uECC_vli_modMult_fast(Z1, X1, X1); /* t3 = B^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100740 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - A */
741 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */
742 uECC_vli_modSub(t5, t5, Z1, curve_p); /* t5 = A - x3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100743 uECC_vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300744 /* t4 = B * (A - x3) - y1^4 = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100745 uECC_vli_modSub(t4, X1, t4, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300746
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100747 uECC_vli_set(X1, Z1);
748 uECC_vli_set(Z1, Y1);
749 uECC_vli_set(Y1, t4);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300750}
751
Manuel Pégourié-Gonnard1c6f7ea2019-11-21 09:18:29 +0100752/*
753 * @brief Computes x^3 + ax + b. result must not overlap x.
754 * @param result OUT -- x^3 + ax + b
755 * @param x IN -- value of x
756 * @param curve IN -- elliptic curve
757 */
758static void x_side_default(uECC_word_t *result,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400759 const uECC_word_t *x)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300760{
761 uECC_word_t _3[NUM_ECC_WORDS] = {3}; /* -a = 3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300762
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100763 uECC_vli_modMult_fast(result, x, x); /* r = x^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100764 uECC_vli_modSub(result, result, _3, curve_p); /* r = x^2 - 3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100765 uECC_vli_modMult_fast(result, result, x); /* r = x^3 - 3x */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300766 /* r = x^3 - 3x + b: */
Manuel Pégourié-Gonnardffd13992019-11-21 10:39:06 +0100767 uECC_vli_modAdd(result, result, curve_b, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300768}
769
770void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int*product)
771{
772 unsigned int tmp[NUM_ECC_WORDS];
773 int carry;
774
775 /* t */
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100776 uECC_vli_set(result, product);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300777
778 /* s1 */
779 tmp[0] = tmp[1] = tmp[2] = 0;
780 tmp[3] = product[11];
781 tmp[4] = product[12];
782 tmp[5] = product[13];
783 tmp[6] = product[14];
784 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100785 carry = uECC_vli_add(tmp, tmp, tmp);
786 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300787
788 /* s2 */
789 tmp[3] = product[12];
790 tmp[4] = product[13];
791 tmp[5] = product[14];
792 tmp[6] = product[15];
793 tmp[7] = 0;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100794 carry += uECC_vli_add(tmp, tmp, tmp);
795 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300796
797 /* s3 */
798 tmp[0] = product[8];
799 tmp[1] = product[9];
800 tmp[2] = product[10];
801 tmp[3] = tmp[4] = tmp[5] = 0;
802 tmp[6] = product[14];
803 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100804 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300805
806 /* s4 */
807 tmp[0] = product[9];
808 tmp[1] = product[10];
809 tmp[2] = product[11];
810 tmp[3] = product[13];
811 tmp[4] = product[14];
812 tmp[5] = product[15];
813 tmp[6] = product[13];
814 tmp[7] = product[8];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100815 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300816
817 /* d1 */
818 tmp[0] = product[11];
819 tmp[1] = product[12];
820 tmp[2] = product[13];
821 tmp[3] = tmp[4] = tmp[5] = 0;
822 tmp[6] = product[8];
823 tmp[7] = product[10];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100824 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300825
826 /* d2 */
827 tmp[0] = product[12];
828 tmp[1] = product[13];
829 tmp[2] = product[14];
830 tmp[3] = product[15];
831 tmp[4] = tmp[5] = 0;
832 tmp[6] = product[9];
833 tmp[7] = product[11];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100834 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300835
836 /* d3 */
837 tmp[0] = product[13];
838 tmp[1] = product[14];
839 tmp[2] = product[15];
840 tmp[3] = product[8];
841 tmp[4] = product[9];
842 tmp[5] = product[10];
843 tmp[6] = 0;
844 tmp[7] = product[12];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100845 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300846
847 /* d4 */
848 tmp[0] = product[14];
849 tmp[1] = product[15];
850 tmp[2] = 0;
851 tmp[3] = product[9];
852 tmp[4] = product[10];
853 tmp[5] = product[11];
854 tmp[6] = 0;
855 tmp[7] = product[13];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100856 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300857
858 if (carry < 0) {
859 do {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100860 carry += uECC_vli_add(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300861 }
862 while (carry < 0);
863 } else {
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200864 while (carry ||
Andrzej Kurek0919b142020-07-06 15:28:59 -0400865 uECC_vli_cmp_unsafe(curve_p, result) != 1) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100866 carry -= uECC_vli_sub(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300867 }
868 }
869}
870
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100871uECC_word_t EccPoint_isZero(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300872{
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100873 return uECC_vli_isZero(point);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300874}
875
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100876void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300877{
878 uECC_word_t t1[NUM_ECC_WORDS];
879
Andrzej Kurek0919b142020-07-06 15:28:59 -0400880 uECC_vli_modMult_fast(t1, Z, Z); /* z^2 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100881 uECC_vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */
882 uECC_vli_modMult_fast(t1, t1, Z); /* z^3 */
883 uECC_vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300884}
885
886/* P = (x1, y1) => 2P, (x2, y2) => P' */
887static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1,
888 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100889 const uECC_word_t * const initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300890{
891 uECC_word_t z[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300892 if (initial_Z) {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100893 uECC_vli_set(z, initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300894 } else {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100895 uECC_vli_clear(z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300896 z[0] = 1;
897 }
898
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100899 uECC_vli_set(X2, X1);
900 uECC_vli_set(Y2, Y1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300901
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100902 apply_z(X1, Y1, z);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100903 double_jacobian_default(X1, Y1, z);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100904 apply_z(X2, Y2, z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300905}
906
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100907static void XYcZ_add_rnd(uECC_word_t * X1, uECC_word_t * Y1,
908 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100909 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300910{
911 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
912 uECC_word_t t5[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300913
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100914 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100915 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100916 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
917 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100918 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100919 uECC_vli_modMult_rnd(t5, Y2, Y2, s); /* t5 = (y2 - y1)^2 = D */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300920
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100921 uECC_vli_modSub(t5, t5, X1, curve_p); /* t5 = D - B */
922 uECC_vli_modSub(t5, t5, X2, curve_p); /* t5 = D - B - C = x3 */
923 uECC_vli_modSub(X2, X2, X1, curve_p); /* t3 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100924 uECC_vli_modMult_rnd(Y1, Y1, X2, s); /* t2 = y1*(C - B) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100925 uECC_vli_modSub(X2, X1, t5, curve_p); /* t3 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100926 uECC_vli_modMult_rnd(Y2, Y2, X2, s); /* t4 = (y2 - y1)*(B - x3) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100927 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300928
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100929 uECC_vli_set(X2, t5);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300930}
931
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100932void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400933 uECC_word_t * X2, uECC_word_t * Y2)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100934{
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100935 XYcZ_add_rnd(X1, Y1, X2, Y2, NULL);
936}
937
Jarno Lamsa18987a42019-04-24 15:40:43 +0300938/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
939 Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
940 or P => P - Q, Q => P + Q
941 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100942static void XYcZ_addC_rnd(uECC_word_t * X1, uECC_word_t * Y1,
943 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100944 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300945{
946 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
947 uECC_word_t t5[NUM_ECC_WORDS];
948 uECC_word_t t6[NUM_ECC_WORDS];
949 uECC_word_t t7[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300950
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100951 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100952 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100953 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
954 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100955 uECC_vli_modAdd(t5, Y2, Y1, curve_p); /* t5 = y2 + y1 */
956 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300957
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100958 uECC_vli_modSub(t6, X2, X1, curve_p); /* t6 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100959 uECC_vli_modMult_rnd(Y1, Y1, t6, s); /* t2 = y1 * (C - B) = E */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100960 uECC_vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100961 uECC_vli_modMult_rnd(X2, Y2, Y2, s); /* t3 = (y2 - y1)^2 = D */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100962 uECC_vli_modSub(X2, X2, t6, curve_p); /* t3 = D - (B + C) = x3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300963
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100964 uECC_vli_modSub(t7, X1, X2, curve_p); /* t7 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100965 uECC_vli_modMult_rnd(Y2, Y2, t7, s); /* t4 = (y2 - y1)*(B - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300966 /* t4 = (y2 - y1)*(B - x3) - E = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100967 uECC_vli_modSub(Y2, Y2, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300968
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100969 uECC_vli_modMult_rnd(t7, t5, t5, s); /* t7 = (y2 + y1)^2 = F */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100970 uECC_vli_modSub(t7, t7, t6, curve_p); /* t7 = F - (B + C) = x3' */
971 uECC_vli_modSub(t6, t7, X1, curve_p); /* t6 = x3' - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100972 uECC_vli_modMult_rnd(t6, t6, t5, s); /* t6 = (y2+y1)*(x3' - B) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300973 /* t2 = (y2+y1)*(x3' - B) - E = y3': */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100974 uECC_vli_modSub(Y1, t6, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300975
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100976 uECC_vli_set(X1, t7);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300977}
978
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +0100979static void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point,
Jarno Lamsa18987a42019-04-24 15:40:43 +0300980 const uECC_word_t * scalar,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +0100981 const uECC_word_t * initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300982{
983 /* R0 and R1 */
984 uECC_word_t Rx[2][NUM_ECC_WORDS];
985 uECC_word_t Ry[2][NUM_ECC_WORDS];
986 uECC_word_t z[NUM_ECC_WORDS];
987 bitcount_t i;
988 uECC_word_t nb;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100989 const wordcount_t num_words = NUM_ECC_WORDS;
990 const bitcount_t num_bits = NUM_ECC_BITS + 1; /* from regularize_k */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100991 ecc_wait_state_t wait_state;
992 ecc_wait_state_t * const ws = g_rng_function ? &wait_state : NULL;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300993
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100994 uECC_vli_set(Rx[1], point);
995 uECC_vli_set(Ry[1], point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300996
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100997 XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300998
999 for (i = num_bits - 2; i > 0; --i) {
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +01001000 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001001 nb = !uECC_vli_testBit(scalar, i);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001002 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
1003 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001004 }
1005
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +01001006 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001007 nb = !uECC_vli_testBit(scalar, 0);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001008 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001009
1010 /* Find final 1/Z value. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001011 uECC_vli_modSub(z, Rx[1], Rx[0], curve_p); /* X1 - X0 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001012 uECC_vli_modMult_fast(z, z, Ry[1 - nb]); /* Yb * (X1 - X0) */
1013 uECC_vli_modMult_fast(z, z, point); /* xP * Yb * (X1 - X0) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001014 uECC_vli_modInv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0))*/
Jarno Lamsa18987a42019-04-24 15:40:43 +03001015 /* yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001016 uECC_vli_modMult_fast(z, z, point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001017 /* Xb * yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001018 uECC_vli_modMult_fast(z, z, Rx[1 - nb]);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001019 /* End 1/Z calculation */
1020
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001021 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001022 apply_z(Rx[0], Ry[0], z);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001023
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +01001024 uECC_vli_set(result, Rx[0]);
1025 uECC_vli_set(result + num_words, Ry[0]);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001026}
1027
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +01001028static uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001029 uECC_word_t *k1)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001030{
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001031 bitcount_t num_n_bits = NUM_ECC_BITS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001032
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001033 uECC_word_t carry = uECC_vli_add(k0, k, curve_n) ||
Andrzej Kurek0919b142020-07-06 15:28:59 -04001034 uECC_vli_testBit(k0, num_n_bits);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001035
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001036 uECC_vli_add(k1, k0, curve_n);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001037
1038 return carry;
1039}
1040
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001041int EccPoint_mult_safer(uECC_word_t * result, const uECC_word_t * point,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001042 const uECC_word_t * scalar)
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001043{
1044 uECC_word_t tmp[NUM_ECC_WORDS];
1045 uECC_word_t s[NUM_ECC_WORDS];
1046 uECC_word_t *k2[2] = {tmp, s};
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001047 wordcount_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001048 uECC_word_t carry;
1049 uECC_word_t *initial_Z = 0;
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001050 int r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001051 volatile int problem;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001052
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001053 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001054 problem = -1;
1055 problem = uECC_check_curve_integrity();
1056 if (problem != 0) {
1057 return UECC_FAULT_DETECTED;
1058 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001059 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001060 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001061 return UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001062 }
1063
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001064 /* Protects against invalid curve attacks */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001065 problem = -1;
1066 problem = uECC_valid_point(point);
1067 if (problem != 0) {
1068 /* invalid input, can happen without fault */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001069 return UECC_FAILURE;
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001070 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001071 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001072 if (problem != 0) {
1073 /* failure on second check means fault, though */
1074 return UECC_FAULT_DETECTED;
1075 }
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001076
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001077 /* Regularize the bitcount for the private key so that attackers cannot use a
1078 * side channel attack to learn the number of leading zeros. */
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001079 carry = regularize_k(scalar, tmp, s);
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001080
1081 /* If an RNG function was specified, get a random initial Z value to
Andrzej Kurek0919b142020-07-06 15:28:59 -04001082 * protect against side-channel attacks such as Template SPA */
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001083 if (g_rng_function) {
Andrzej Kurek3a0df032020-06-12 06:32:13 -04001084 if (uECC_generate_random_int(k2[carry], curve_p, num_words) != UECC_SUCCESS) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001085 r = UECC_FAILURE;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001086 goto clear_and_out;
1087 }
1088 initial_Z = k2[carry];
1089 }
1090
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001091 EccPoint_mult(result, point, k2[!carry], initial_Z);
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001092
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001093 /* Protect against fault injections that would make the resulting
1094 * point not lie on the intended curve */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001095 problem = -1;
1096 problem = uECC_valid_point(result);
1097 if (problem != 0) {
1098 r = UECC_FAULT_DETECTED;
1099 goto clear_and_out;
1100 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001101 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001102 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001103 r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001104 goto clear_and_out;
1105 }
1106
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001107 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001108 problem = -1;
1109 problem = uECC_check_curve_integrity();
1110 if (problem != 0) {
1111 r = UECC_FAULT_DETECTED;
1112 goto clear_and_out;
1113 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001114 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001115 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001116 r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001117 goto clear_and_out;
1118 }
1119
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001120 r = UECC_SUCCESS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001121
1122clear_and_out:
1123 /* erasing temporary buffer used to store secret: */
1124 mbedtls_platform_zeroize(k2, sizeof(k2));
1125 mbedtls_platform_zeroize(tmp, sizeof(tmp));
1126 mbedtls_platform_zeroize(s, sizeof(s));
1127
1128 return r;
1129}
1130
Jarno Lamsa18987a42019-04-24 15:40:43 +03001131uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001132 uECC_word_t *private_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001133{
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001134 return EccPoint_mult_safer(result, curve_G, private_key);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001135}
1136
1137/* Converts an integer in uECC native format to big-endian bytes. */
1138void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
Andrzej Kurek0919b142020-07-06 15:28:59 -04001139 const unsigned int *native)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001140{
1141 wordcount_t i;
1142 for (i = 0; i < num_bytes; ++i) {
1143 unsigned b = num_bytes - 1 - i;
1144 bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE));
1145 }
1146}
1147
1148/* Converts big-endian bytes to an integer in uECC native format. */
1149void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes,
Andrzej Kurek0919b142020-07-06 15:28:59 -04001150 int num_bytes)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001151{
1152 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +01001153 uECC_vli_clear(native);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001154 for (i = 0; i < num_bytes; ++i) {
1155 unsigned b = num_bytes - 1 - i;
1156 native[b / uECC_WORD_SIZE] |=
1157 (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE));
1158 }
1159}
1160
1161int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
Andrzej Kurek0919b142020-07-06 15:28:59 -04001162 wordcount_t num_words)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001163{
1164 uECC_word_t mask = (uECC_word_t)-1;
1165 uECC_word_t tries;
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +01001166 bitcount_t num_bits = uECC_vli_numBits(top);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001167
1168 if (!g_rng_function) {
Andrzej Kurek3a0df032020-06-12 06:32:13 -04001169 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001170 }
1171
1172 for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
Andrzej Kurek090365f2020-06-08 11:00:51 -04001173 if (g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE) != num_words * uECC_WORD_SIZE) {
Andrzej Kurek0919b142020-07-06 15:28:59 -04001174 return UECC_FAILURE;
1175 }
Jarno Lamsa18987a42019-04-24 15:40:43 +03001176 random[num_words - 1] &=
Andrzej Kurek0919b142020-07-06 15:28:59 -04001177 mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits));
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001178 if (!uECC_vli_isZero(random) &&
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +01001179 uECC_vli_cmp(top, random) == 1) {
Andrzej Kurek3a0df032020-06-12 06:32:13 -04001180 return UECC_SUCCESS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001181 }
1182 }
Andrzej Kurek3a0df032020-06-12 06:32:13 -04001183 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001184}
1185
1186
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001187int uECC_valid_point(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001188{
1189 uECC_word_t tmp1[NUM_ECC_WORDS];
1190 uECC_word_t tmp2[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001191 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa83d78812019-12-04 14:40:57 +02001192 volatile uECC_word_t diff = 0xffffffff;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001193
1194 /* The point at infinity is invalid. */
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001195 if (EccPoint_isZero(point)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001196 return -1;
1197 }
1198
1199 /* x and y must be smaller than p. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001200 if (uECC_vli_cmp_unsafe(curve_p, point) != 1 ||
1201 uECC_vli_cmp_unsafe(curve_p, point + num_words) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001202 return -2;
1203 }
1204
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001205 uECC_vli_modMult_fast(tmp1, point + num_words, point + num_words);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001206 x_side_default(tmp2, point); /* tmp2 = x^3 + ax + b */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001207
1208 /* Make sure that y^2 == x^3 + ax + b */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001209 diff = uECC_vli_equal(tmp1, tmp2);
1210 if (diff == 0) {
Andrzej Kurek0919b142020-07-06 15:28:59 -04001211 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001212 if (diff == 0) {
1213 return 0;
1214 }
1215 }
Jarno Lamsa18987a42019-04-24 15:40:43 +03001216
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001217 return -3;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001218}
1219
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001220int uECC_valid_public_key(const uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001221{
1222
1223 uECC_word_t _public[NUM_ECC_WORDS * 2];
1224
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001225 uECC_vli_bytesToNative(_public, public_key, NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001226 uECC_vli_bytesToNative(
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001227 _public + NUM_ECC_WORDS,
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001228 public_key + NUM_ECC_BYTES,
1229 NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001230
Manuel Pégourié-Gonnarda6115082019-11-21 10:29:14 +01001231 if (memcmp(_public, curve_G, NUM_ECC_WORDS * 2) == 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001232 return -4;
1233 }
1234
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001235 return uECC_valid_point(_public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001236}
1237
Andrzej Kurek0919b142020-07-06 15:28:59 -04001238int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001239{
Andrzej Kurekfd56f402020-05-25 11:52:05 -04001240 int ret = UECC_FAULT_DETECTED;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001241 uECC_word_t _private[NUM_ECC_WORDS];
1242 uECC_word_t _public[NUM_ECC_WORDS * 2];
1243
1244 uECC_vli_bytesToNative(
1245 _private,
1246 private_key,
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +01001247 BITS_TO_BYTES(NUM_ECC_BITS));
Jarno Lamsa18987a42019-04-24 15:40:43 +03001248
1249 /* Make sure the private key is in the range [1, n-1]. */
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001250 if (uECC_vli_isZero(_private)) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001251 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001252 }
1253
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001254 if (uECC_vli_cmp(curve_n, _private) != 1) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001255 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001256 }
1257
1258 /* Compute public key. */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001259 ret = EccPoint_compute_public_key(_public, _private);
1260 if (ret != UECC_SUCCESS) {
1261 return ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001262 }
1263
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001264 uECC_vli_nativeToBytes(public_key, NUM_ECC_BYTES, _public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001265 uECC_vli_nativeToBytes(
1266 public_key +
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001267 NUM_ECC_BYTES, NUM_ECC_BYTES, _public + NUM_ECC_WORDS);
Andrzej Kurekcf3e35c2020-07-15 22:32:08 -04001268
Andrzej Kurekfd56f402020-05-25 11:52:05 -04001269 return ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001270}