blob: c6c722a951a5cad9ba0f0db0c55dbfe4f4df6000 [file] [log] [blame]
Jarno Lamsa18987a42019-04-24 15:40:43 +03001/* ecc.c - TinyCrypt implementation of common ECC functions */
2
3/*
Simon Butcher92c3d1f2019-09-09 17:25:08 +01004 * Copyright (c) 2019, Arm Limited (or its affiliates), All Rights Reserved.
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8/*
Jarno Lamsa18987a42019-04-24 15:40:43 +03009 * Copyright (c) 2014, Kenneth MacKay
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 * * Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions are met:
35 *
36 * - Redistributions of source code must retain the above copyright notice,
37 * this list of conditions and the following disclaimer.
38 *
39 * - Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 *
43 * - Neither the name of Intel Corporation nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57 * POSSIBILITY OF SUCH DAMAGE.
58 */
59
Hanno Becker36ae7582019-07-23 15:52:35 +010060#if !defined(MBEDTLS_CONFIG_FILE)
61#include "mbedtls/config.h"
62#else
63#include MBEDTLS_CONFIG_FILE
64#endif
65
Jarno Lamsa18987a42019-04-24 15:40:43 +030066#include <tinycrypt/ecc.h>
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +010067#include "mbedtls/platform_util.h"
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +010068#include "mbedtls/sha256.h"
Jarno Lamsa18987a42019-04-24 15:40:43 +030069#include <string.h>
70
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +010071/* Parameters for curve NIST P-256 aka secp256r1 */
72const uECC_word_t curve_p[NUM_ECC_WORDS] = {
73 BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
74 BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00),
75 BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
76 BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF)
77};
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +010078const uECC_word_t curve_n[NUM_ECC_WORDS] = {
79 BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3),
80 BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC),
81 BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
82 BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF)
83};
Manuel Pégourié-Gonnarda6115082019-11-21 10:29:14 +010084const uECC_word_t curve_G[2 * NUM_ECC_WORDS] = {
85 BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4),
86 BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77),
87 BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8),
88 BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B),
89 BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB),
90 BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B),
91 BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E),
92 BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F)
93};
Manuel Pégourié-Gonnardffd13992019-11-21 10:39:06 +010094const uECC_word_t curve_b[NUM_ECC_WORDS] = {
95 BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B),
96 BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65),
97 BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3),
98 BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A)
99};
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100100
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100101static int uECC_update_param_sha256(mbedtls_sha256_context *ctx,
102 const uECC_word_t val[NUM_ECC_WORDS])
103{
104 uint8_t bytes[NUM_ECC_BYTES];
105
106 uECC_vli_nativeToBytes(bytes, NUM_ECC_BYTES, val);
107 return mbedtls_sha256_update_ret(ctx, bytes, NUM_ECC_BYTES);
108}
109
110static int uECC_compute_param_sha256(unsigned char output[32])
111{
112 int ret = UECC_FAILURE;
113 mbedtls_sha256_context ctx;
114
115 mbedtls_sha256_init( &ctx );
116
117 if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) {
118 goto exit;
119 }
120
121 if (uECC_update_param_sha256(&ctx, curve_p) != 0 ||
122 uECC_update_param_sha256(&ctx, curve_n) != 0 ||
123 uECC_update_param_sha256(&ctx, curve_G) != 0 ||
124 uECC_update_param_sha256(&ctx, curve_G + NUM_ECC_WORDS) != 0 ||
125 uECC_update_param_sha256(&ctx, curve_b) != 0)
126 {
127 goto exit;
128 }
129
130 if (mbedtls_sha256_finish_ret(&ctx, output) != 0) {
131 goto exit;
132 }
133
134 ret = UECC_SUCCESS;
135
136exit:
137 mbedtls_sha256_free( &ctx );
138
139 return ret;
140}
141
142/*
143 * Check integrity of curve parameters.
144 * Return 0 if everything's OK, non-zero otherwise.
145 */
146static int uECC_check_curve_integrity(void)
147{
148 unsigned char computed[32];
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100149 static const unsigned char reference[32] = {
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100150 0x2d, 0xa1, 0xa4, 0x64, 0x45, 0x28, 0x0d, 0xe1,
151 0x93, 0xf9, 0x29, 0x2f, 0xac, 0x3e, 0xe2, 0x92,
152 0x76, 0x0a, 0xe2, 0xbc, 0xce, 0x2a, 0xa2, 0xc6,
153 0x38, 0xf2, 0x19, 0x1d, 0x76, 0x72, 0x93, 0x49,
154 };
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100155 unsigned char diff = 0;
156 unsigned char tmp1, tmp2;
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100157 volatile unsigned i;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100158
159 if (uECC_compute_param_sha256(computed) != UECC_SUCCESS) {
160 return UECC_FAILURE;
161 }
162
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100163 for (i = 0; i < 32; i++) {
164 /* make sure the order of volatile accesses is well-defined */
165 tmp1 = computed[i];
166 tmp2 = reference[i];
167 diff |= tmp1 ^ tmp2;
168 }
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100169
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100170 /* i should be 32 */
Arto Kinnunenac6d2262020-01-09 10:11:20 +0200171 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100172 diff |= (unsigned char) i ^ 32;
173
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100174 return diff;
175}
176
Jarno Lamsa18987a42019-04-24 15:40:43 +0300177/* IMPORTANT: Make sure a cryptographically-secure PRNG is set and the platform
178 * has access to enough entropy in order to feed the PRNG regularly. */
179#if default_RNG_defined
180static uECC_RNG_Function g_rng_function = &default_CSPRNG;
181#else
182static uECC_RNG_Function g_rng_function = 0;
183#endif
184
185void uECC_set_rng(uECC_RNG_Function rng_function)
186{
187 g_rng_function = rng_function;
188}
189
190uECC_RNG_Function uECC_get_rng(void)
191{
192 return g_rng_function;
193}
194
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +0100195int uECC_curve_private_key_size(void)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300196{
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +0100197 return BITS_TO_BYTES(NUM_ECC_BITS);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300198}
199
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +0100200int uECC_curve_public_key_size(void)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300201{
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +0100202 return 2 * NUM_ECC_BYTES;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300203}
204
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100205void uECC_vli_clear(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300206{
207 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100208 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300209 vli[i] = 0;
210 }
211}
212
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100213uECC_word_t uECC_vli_isZero(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300214{
215 uECC_word_t bits = 0;
216 wordcount_t i;
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100217 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300218 bits |= vli[i];
219 }
220 return (bits == 0);
221}
222
223uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit)
224{
225 return (vli[bit >> uECC_WORD_BITS_SHIFT] &
226 ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));
227}
228
229/* Counts the number of words in vli. */
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100230static wordcount_t vli_numDigits(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300231{
232
233 wordcount_t i;
234 /* Search from the end until we find a non-zero digit. We do it in reverse
235 * because we expect that most digits will be nonzero. */
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100236 for (i = NUM_ECC_WORDS - 1; i >= 0 && vli[i] == 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300237 }
238
239 return (i + 1);
240}
241
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100242bitcount_t uECC_vli_numBits(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300243{
244
245 uECC_word_t i;
246 uECC_word_t digit;
247
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100248 wordcount_t num_digits = vli_numDigits(vli);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300249 if (num_digits == 0) {
250 return 0;
251 }
252
253 digit = vli[num_digits - 1];
254 for (i = 0; digit; ++i) {
255 digit >>= 1;
256 }
257
258 return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);
259}
260
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100261void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300262{
263 wordcount_t i;
264
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100265 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300266 dest[i] = src[i];
267 }
268}
269
270cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100271 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300272{
273 wordcount_t i;
274
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100275 for (i = NUM_ECC_WORDS - 1; i >= 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300276 if (left[i] > right[i]) {
277 return 1;
278 } else if (left[i] < right[i]) {
279 return -1;
280 }
281 }
282 return 0;
283}
284
Manuel Pégourié-Gonnard2eca3d32019-11-04 14:33:09 +0100285uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300286{
287
288 uECC_word_t diff = 0;
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100289 uECC_word_t tmp1, tmp2;
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100290 volatile int i;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300291
Manuel Pégourié-Gonnard2eca3d32019-11-04 14:33:09 +0100292 for (i = NUM_ECC_WORDS - 1; i >= 0; --i) {
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100293 tmp1 = left[i];
294 tmp2 = right[i];
295 diff |= (tmp1 ^ tmp2);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300296 }
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100297
298 /* i should be -1 now */
Arto Kinnunenac6d2262020-01-09 10:11:20 +0200299 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100300 diff |= i ^ -1;
301
Manuel Pégourié-Gonnard2b6312b2019-11-06 10:42:02 +0100302 return diff;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300303}
304
305uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond)
306{
307 return (p_true*(cond)) | (p_false*(!cond));
308}
309
310/* Computes result = left - right, returning borrow, in constant time.
311 * Can modify in place. */
312uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100313 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300314{
315 uECC_word_t borrow = 0;
316 wordcount_t i;
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100317 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300318 uECC_word_t diff = left[i] - right[i] - borrow;
319 uECC_word_t val = (diff > left[i]);
320 borrow = cond_set(val, borrow, (diff != left[i]));
321
322 result[i] = diff;
323 }
324 return borrow;
325}
326
327/* Computes result = left + right, returning carry, in constant time.
328 * Can modify in place. */
329static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100330 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300331{
332 uECC_word_t carry = 0;
333 wordcount_t i;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100334 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300335 uECC_word_t sum = left[i] + right[i] + carry;
336 uECC_word_t val = (sum < left[i]);
337 carry = cond_set(val, carry, (sum != left[i]));
338 result[i] = sum;
339 }
340 return carry;
341}
342
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +0100343cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300344{
345 uECC_word_t tmp[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100346 uECC_word_t neg = !!uECC_vli_sub(tmp, left, right);
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100347 uECC_word_t equal = uECC_vli_isZero(tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300348 return (!equal - 2 * neg);
349}
350
351/* Computes vli = vli >> 1. */
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100352static void uECC_vli_rshift1(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300353{
354 uECC_word_t *end = vli;
355 uECC_word_t carry = 0;
356
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100357 vli += NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300358 while (vli-- > end) {
359 uECC_word_t temp = *vli;
360 *vli = (temp >> 1) | carry;
361 carry = temp << (uECC_WORD_BITS - 1);
362 }
363}
364
Manuel Pégourié-Gonnard86c4f812019-10-31 13:02:03 +0100365/* Compute a * b + r, where r is a double-word with high-order word r1 and
366 * low-order word r0, and store the result in the same double-word (r1, r0),
367 * with the carry bit stored in r2.
368 *
369 * (r2, r1, r0) = a * b + (r1, r0):
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200370 * [in] a, b: operands to be multiplied
371 * [in] r0, r1: low and high-order words of operand to add
372 * [out] r0, r1: low and high-order words of the result
373 * [out] r2: carry
374 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300375static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0,
376 uECC_word_t *r1, uECC_word_t *r2)
377{
378
379 uECC_dword_t p = (uECC_dword_t)a * b;
380 uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
381 r01 += p;
382 *r2 += (r01 < p);
383 *r1 = r01 >> uECC_WORD_BITS;
384 *r0 = (uECC_word_t)r01;
385
386}
387
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200388/* State for implementing random delays in uECC_vli_mult_rnd().
389 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100390 * The state is initialized by randomizing delays and setting i = 0.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200391 * Each call to uECC_vli_mult_rnd() uses one byte of delays and increments i.
392 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100393 * Randomized vli multiplication is used only for point operations
394 * (XYcZ_add_rnd() * and XYcZ_addC_rnd()) in scalar multiplication
395 * (ECCPoint_mult()). Those go in pair, and each pair does 14 calls to
396 * uECC_vli_mult_rnd() (6 in XYcZ_add_rnd() and 8 in XYcZ_addC_rnd(),
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100397 * indirectly through uECC_vli_modMult_rnd().
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100398 *
399 * Considering this, in order to minimize the number of calls to the RNG
400 * (which impact performance) while keeping the size of the structure low,
401 * make room for 14 randomized vli mults, which corresponds to one step in the
402 * scalar multiplication routine.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200403 */
404typedef struct {
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100405 uint8_t i;
406 uint8_t delays[14];
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100407} ecc_wait_state_t;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200408
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100409/*
410 * Reset wait_state so that it's ready to be used.
411 */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100412void ecc_wait_state_reset(ecc_wait_state_t *ws)
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100413{
414 if (ws == NULL)
415 return;
416
417 ws->i = 0;
418 g_rng_function(ws->delays, sizeof(ws->delays));
419}
420
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200421/* Computes result = left * right. Result must be 2 * num_words long.
422 *
423 * As a counter-measure against horizontal attacks, add noise by performing
424 * a random number of extra computations performing random additional accesses
425 * to limbs of the input.
426 *
427 * Each of the two actual computation loops is surrounded by two
428 * similar-looking waiting loops, to make the beginning and end of the actual
429 * computation harder to spot.
430 *
431 * We add 4 waiting loops of between 0 and 3 calls to muladd() each. That
432 * makes an average of 6 extra calls. Compared to the main computation which
433 * makes 64 such calls, this represents an average performance degradation of
434 * less than 10%.
435 *
436 * Compared to the original uECC_vli_mult(), loose the num_words argument as we
437 * know it's always 8. This saves a bit of code size and execution speed.
438 */
439static void uECC_vli_mult_rnd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100440 const uECC_word_t *right, ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300441{
442
443 uECC_word_t r0 = 0;
444 uECC_word_t r1 = 0;
445 uECC_word_t r2 = 0;
446 wordcount_t i, k;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100447 const uint8_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200448
449 /* Fetch 8 bit worth of delay from the state; 0 if we have no state */
450 uint8_t delays = s ? s->delays[s->i++] : 0;
451 uECC_word_t rr0 = 0, rr1 = 0;
452 volatile uECC_word_t r;
453
454 /* Mimic start of next loop: k in [0, 3] */
455 k = 0 + (delays & 0x03);
456 delays >>= 2;
457 /* k = 0 -> i in [1, 0] -> 0 extra muladd;
458 * k = 3 -> i in [1, 3] -> 3 extra muladd */
Manuel Pégourié-Gonnardc8814862019-11-05 10:32:37 +0100459 for (i = 1; i <= k; ++i) {
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200460 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
461 }
462 r = rr0;
463 rr0 = rr1;
464 rr1 = r2;
465 r2 = 0;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300466
467 /* Compute each digit of result in sequence, maintaining the carries. */
468 for (k = 0; k < num_words; ++k) {
469
470 for (i = 0; i <= k; ++i) {
471 muladd(left[i], right[k - i], &r0, &r1, &r2);
472 }
473
474 result[k] = r0;
475 r0 = r1;
476 r1 = r2;
477 r2 = 0;
478 }
479
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200480 /* Mimic end of previous loop: k in [4, 7] */
481 k = 4 + (delays & 0x03);
482 delays >>= 2;
483 /* k = 4 -> i in [5, 4] -> 0 extra muladd;
484 * k = 7 -> i in [5, 7] -> 3 extra muladd */
485 for (i = 5; i <= k; ++i) {
486 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
487 }
488 r = rr0;
489 rr0 = rr1;
490 rr1 = r2;
491 r2 = 0;
492
493 /* Mimic start of next loop: k in [8, 11] */
494 k = 11 - (delays & 0x03);
495 delays >>= 2;
496 /* k = 8 -> i in [5, 7] -> 3 extra muladd;
497 * k = 11 -> i in [8, 7] -> 0 extra muladd */
498 for (i = (k + 5) - num_words; i < num_words; ++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
Jarno Lamsa18987a42019-04-24 15:40:43 +0300506 for (k = num_words; k < num_words * 2 - 1; ++k) {
507
508 for (i = (k + 1) - num_words; i < num_words; ++i) {
509 muladd(left[i], right[k - i], &r0, &r1, &r2);
510 }
511 result[k] = r0;
512 r0 = r1;
513 r1 = r2;
514 r2 = 0;
515 }
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200516
Jarno Lamsa18987a42019-04-24 15:40:43 +0300517 result[num_words * 2 - 1] = r0;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200518
519 /* Mimic end of previous loop: k in [12, 15] */
520 k = 15 - (delays & 0x03);
521 delays >>= 2;
522 /* k = 12 -> i in [5, 7] -> 3 extra muladd;
523 * k = 15 -> i in [8, 7] -> 0 extra muladd */
524 for (i = (k + 1) - num_words; i < num_words; ++i) {
525 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
526 }
527 r = rr0;
528 rr0 = rr1;
529 rr1 = r2;
530 r2 = 0;
531
532 /* avoid warning that r is set but not used */
533 (void) r;
534}
535
Jarno Lamsa18987a42019-04-24 15:40:43 +0300536void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard0779be72019-11-04 14:48:22 +0100537 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300538{
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100539 uECC_word_t carry = uECC_vli_add(result, left, right);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100540 if (carry || uECC_vli_cmp_unsafe(mod, result) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300541 /* result > mod (result = mod + remainder), so subtract mod to get
542 * remainder. */
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100543 uECC_vli_sub(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300544 }
545}
546
547void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard1b0875d2019-11-04 14:50:54 +0100548 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300549{
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100550 uECC_word_t l_borrow = uECC_vli_sub(result, left, right);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300551 if (l_borrow) {
552 /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
553 * we can get the correct result from result + mod (with overflow). */
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100554 uECC_vli_add(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300555 }
556}
557
558/* Computes result = product % mod, where product is 2N words long. */
559/* Currently only designed to work for curve_p or curve_n. */
560void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100561 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300562{
563 uECC_word_t mod_multiple[2 * NUM_ECC_WORDS];
564 uECC_word_t tmp[2 * NUM_ECC_WORDS];
565 uECC_word_t *v[2] = {tmp, product};
566 uECC_word_t index;
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100567 const wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300568
569 /* Shift mod so its highest set bit is at the maximum position. */
570 bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) -
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100571 uECC_vli_numBits(mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300572 wordcount_t word_shift = shift / uECC_WORD_BITS;
573 wordcount_t bit_shift = shift % uECC_WORD_BITS;
574 uECC_word_t carry = 0;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100575 uECC_vli_clear(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300576 if (bit_shift > 0) {
577 for(index = 0; index < (uECC_word_t)num_words; ++index) {
578 mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;
579 carry = mod[index] >> (uECC_WORD_BITS - bit_shift);
580 }
581 } else {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100582 uECC_vli_set(mod_multiple + word_shift, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300583 }
584
585 for (index = 1; shift >= 0; --shift) {
586 uECC_word_t borrow = 0;
587 wordcount_t i;
588 for (i = 0; i < num_words * 2; ++i) {
589 uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;
590 if (diff != v[index][i]) {
591 borrow = (diff > v[index][i]);
592 }
593 v[1 - index][i] = diff;
594 }
595 /* Swap the index if there was no borrow */
596 index = !(index ^ borrow);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100597 uECC_vli_rshift1(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300598 mod_multiple[num_words - 1] |= mod_multiple[num_words] <<
599 (uECC_WORD_BITS - 1);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100600 uECC_vli_rshift1(mod_multiple + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300601 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100602 uECC_vli_set(result, v[index]);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300603}
604
605void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard3e20adf2019-11-04 15:00:43 +0100606 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300607{
608 uECC_word_t product[2 * NUM_ECC_WORDS];
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100609 uECC_vli_mult_rnd(product, left, right, NULL);
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100610 uECC_vli_mmod(result, product, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300611}
612
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100613static void uECC_vli_modMult_rnd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100614 const uECC_word_t *right, ecc_wait_state_t *s)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100615{
616 uECC_word_t product[2 * NUM_ECC_WORDS];
617 uECC_vli_mult_rnd(product, left, right, s);
618
619 vli_mmod_fast_secp256r1(result, product);
620}
621
Jarno Lamsa18987a42019-04-24 15:40:43 +0300622void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100623 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300624{
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100625 uECC_vli_modMult_rnd(result, left, right, NULL);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300626}
627
Jarno Lamsa18987a42019-04-24 15:40:43 +0300628#define EVEN(vli) (!(vli[0] & 1))
629
630static void vli_modInv_update(uECC_word_t *uv,
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100631 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300632{
633
634 uECC_word_t carry = 0;
635
636 if (!EVEN(uv)) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100637 carry = uECC_vli_add(uv, uv, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300638 }
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100639 uECC_vli_rshift1(uv);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300640 if (carry) {
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100641 uv[NUM_ECC_WORDS - 1] |= HIGH_BIT_SET;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300642 }
643}
644
645void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100646 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300647{
648 uECC_word_t a[NUM_ECC_WORDS], b[NUM_ECC_WORDS];
649 uECC_word_t u[NUM_ECC_WORDS], v[NUM_ECC_WORDS];
650 cmpresult_t cmpResult;
651
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100652 if (uECC_vli_isZero(input)) {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100653 uECC_vli_clear(result);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300654 return;
655 }
656
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100657 uECC_vli_set(a, input);
658 uECC_vli_set(b, mod);
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100659 uECC_vli_clear(u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300660 u[0] = 1;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100661 uECC_vli_clear(v);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100662 while ((cmpResult = uECC_vli_cmp_unsafe(a, b)) != 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300663 if (EVEN(a)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100664 uECC_vli_rshift1(a);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100665 vli_modInv_update(u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300666 } else if (EVEN(b)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100667 uECC_vli_rshift1(b);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100668 vli_modInv_update(v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300669 } else if (cmpResult > 0) {
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100670 uECC_vli_sub(a, a, b);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100671 uECC_vli_rshift1(a);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100672 if (uECC_vli_cmp_unsafe(u, v) < 0) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100673 uECC_vli_add(u, u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300674 }
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100675 uECC_vli_sub(u, u, v);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100676 vli_modInv_update(u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300677 } else {
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100678 uECC_vli_sub(b, b, a);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100679 uECC_vli_rshift1(b);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100680 if (uECC_vli_cmp_unsafe(v, u) < 0) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100681 uECC_vli_add(v, v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300682 }
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100683 uECC_vli_sub(v, v, u);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100684 vli_modInv_update(v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300685 }
686 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100687 uECC_vli_set(result, u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300688}
689
690/* ------ Point operations ------ */
691
692void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100693 uECC_word_t * Z1)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300694{
695 /* t1 = X, t2 = Y, t3 = Z */
696 uECC_word_t t4[NUM_ECC_WORDS];
697 uECC_word_t t5[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +0100698 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300699
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100700 if (uECC_vli_isZero(Z1)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300701 return;
702 }
703
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100704 uECC_vli_modMult_fast(t4, Y1, Y1); /* t4 = y1^2 */
705 uECC_vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */
706 uECC_vli_modMult_fast(t4, t4, t4); /* t4 = y1^4 */
707 uECC_vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */
708 uECC_vli_modMult_fast(Z1, Z1, Z1); /* t3 = z1^2 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300709
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100710 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */
711 uECC_vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */
712 uECC_vli_modSub(Z1, X1, Z1, curve_p); /* t3 = x1 - z1^2 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100713 uECC_vli_modMult_fast(X1, X1, Z1); /* t1 = x1^2 - z1^4 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300714
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100715 uECC_vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */
716 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300717 if (uECC_vli_testBit(X1, 0)) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100718 uECC_word_t l_carry = uECC_vli_add(X1, X1, curve_p);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100719 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300720 X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
721 } else {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100722 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300723 }
724
725 /* t1 = 3/2*(x1^2 - z1^4) = B */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100726 uECC_vli_modMult_fast(Z1, X1, X1); /* t3 = B^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100727 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - A */
728 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */
729 uECC_vli_modSub(t5, t5, Z1, curve_p); /* t5 = A - x3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100730 uECC_vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300731 /* t4 = B * (A - x3) - y1^4 = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100732 uECC_vli_modSub(t4, X1, t4, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300733
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100734 uECC_vli_set(X1, Z1);
735 uECC_vli_set(Z1, Y1);
736 uECC_vli_set(Y1, t4);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300737}
738
Manuel Pégourié-Gonnard1c6f7ea2019-11-21 09:18:29 +0100739/*
740 * @brief Computes x^3 + ax + b. result must not overlap x.
741 * @param result OUT -- x^3 + ax + b
742 * @param x IN -- value of x
743 * @param curve IN -- elliptic curve
744 */
745static void x_side_default(uECC_word_t *result,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100746 const uECC_word_t *x)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300747{
748 uECC_word_t _3[NUM_ECC_WORDS] = {3}; /* -a = 3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300749
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100750 uECC_vli_modMult_fast(result, x, x); /* r = x^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100751 uECC_vli_modSub(result, result, _3, curve_p); /* r = x^2 - 3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100752 uECC_vli_modMult_fast(result, result, x); /* r = x^3 - 3x */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300753 /* r = x^3 - 3x + b: */
Manuel Pégourié-Gonnardffd13992019-11-21 10:39:06 +0100754 uECC_vli_modAdd(result, result, curve_b, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300755}
756
757void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int*product)
758{
759 unsigned int tmp[NUM_ECC_WORDS];
760 int carry;
761
762 /* t */
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100763 uECC_vli_set(result, product);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300764
765 /* s1 */
766 tmp[0] = tmp[1] = tmp[2] = 0;
767 tmp[3] = product[11];
768 tmp[4] = product[12];
769 tmp[5] = product[13];
770 tmp[6] = product[14];
771 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100772 carry = uECC_vli_add(tmp, tmp, tmp);
773 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300774
775 /* s2 */
776 tmp[3] = product[12];
777 tmp[4] = product[13];
778 tmp[5] = product[14];
779 tmp[6] = product[15];
780 tmp[7] = 0;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100781 carry += uECC_vli_add(tmp, tmp, tmp);
782 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300783
784 /* s3 */
785 tmp[0] = product[8];
786 tmp[1] = product[9];
787 tmp[2] = product[10];
788 tmp[3] = tmp[4] = tmp[5] = 0;
789 tmp[6] = product[14];
790 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100791 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300792
793 /* s4 */
794 tmp[0] = product[9];
795 tmp[1] = product[10];
796 tmp[2] = product[11];
797 tmp[3] = product[13];
798 tmp[4] = product[14];
799 tmp[5] = product[15];
800 tmp[6] = product[13];
801 tmp[7] = product[8];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100802 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300803
804 /* d1 */
805 tmp[0] = product[11];
806 tmp[1] = product[12];
807 tmp[2] = product[13];
808 tmp[3] = tmp[4] = tmp[5] = 0;
809 tmp[6] = product[8];
810 tmp[7] = product[10];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100811 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300812
813 /* d2 */
814 tmp[0] = product[12];
815 tmp[1] = product[13];
816 tmp[2] = product[14];
817 tmp[3] = product[15];
818 tmp[4] = tmp[5] = 0;
819 tmp[6] = product[9];
820 tmp[7] = product[11];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100821 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300822
823 /* d3 */
824 tmp[0] = product[13];
825 tmp[1] = product[14];
826 tmp[2] = product[15];
827 tmp[3] = product[8];
828 tmp[4] = product[9];
829 tmp[5] = product[10];
830 tmp[6] = 0;
831 tmp[7] = product[12];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100832 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300833
834 /* d4 */
835 tmp[0] = product[14];
836 tmp[1] = product[15];
837 tmp[2] = 0;
838 tmp[3] = product[9];
839 tmp[4] = product[10];
840 tmp[5] = product[11];
841 tmp[6] = 0;
842 tmp[7] = product[13];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100843 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300844
845 if (carry < 0) {
846 do {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100847 carry += uECC_vli_add(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300848 }
849 while (carry < 0);
850 } else {
851 while (carry ||
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100852 uECC_vli_cmp_unsafe(curve_p, result) != 1) {
853 carry -= uECC_vli_sub(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300854 }
855 }
856}
857
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100858uECC_word_t EccPoint_isZero(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300859{
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100860 return uECC_vli_isZero(point);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300861}
862
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100863void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300864{
865 uECC_word_t t1[NUM_ECC_WORDS];
866
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100867 uECC_vli_modMult_fast(t1, Z, Z); /* z^2 */
868 uECC_vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */
869 uECC_vli_modMult_fast(t1, t1, Z); /* z^3 */
870 uECC_vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300871}
872
873/* P = (x1, y1) => 2P, (x2, y2) => P' */
874static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1,
875 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100876 const uECC_word_t * const initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300877{
878 uECC_word_t z[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300879 if (initial_Z) {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100880 uECC_vli_set(z, initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300881 } else {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100882 uECC_vli_clear(z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300883 z[0] = 1;
884 }
885
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100886 uECC_vli_set(X2, X1);
887 uECC_vli_set(Y2, Y1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300888
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100889 apply_z(X1, Y1, z);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100890 double_jacobian_default(X1, Y1, z);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100891 apply_z(X2, Y2, z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300892}
893
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100894static void XYcZ_add_rnd(uECC_word_t * X1, uECC_word_t * Y1,
895 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100896 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300897{
898 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
899 uECC_word_t t5[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300900
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100901 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100902 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100903 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
904 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100905 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100906 uECC_vli_modMult_rnd(t5, Y2, Y2, s); /* t5 = (y2 - y1)^2 = D */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300907
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100908 uECC_vli_modSub(t5, t5, X1, curve_p); /* t5 = D - B */
909 uECC_vli_modSub(t5, t5, X2, curve_p); /* t5 = D - B - C = x3 */
910 uECC_vli_modSub(X2, X2, X1, curve_p); /* t3 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100911 uECC_vli_modMult_rnd(Y1, Y1, X2, s); /* t2 = y1*(C - B) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100912 uECC_vli_modSub(X2, X1, t5, curve_p); /* t3 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100913 uECC_vli_modMult_rnd(Y2, Y2, X2, s); /* t4 = (y2 - y1)*(B - x3) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100914 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300915
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100916 uECC_vli_set(X2, t5);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300917}
918
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100919void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100920 uECC_word_t * X2, uECC_word_t * Y2)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100921{
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100922 XYcZ_add_rnd(X1, Y1, X2, Y2, NULL);
923}
924
Jarno Lamsa18987a42019-04-24 15:40:43 +0300925/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
926 Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
927 or P => P - Q, Q => P + Q
928 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100929static void XYcZ_addC_rnd(uECC_word_t * X1, uECC_word_t * Y1,
930 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100931 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300932{
933 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
934 uECC_word_t t5[NUM_ECC_WORDS];
935 uECC_word_t t6[NUM_ECC_WORDS];
936 uECC_word_t t7[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300937
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100938 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100939 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100940 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
941 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100942 uECC_vli_modAdd(t5, Y2, Y1, curve_p); /* t5 = y2 + y1 */
943 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300944
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100945 uECC_vli_modSub(t6, X2, X1, curve_p); /* t6 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100946 uECC_vli_modMult_rnd(Y1, Y1, t6, s); /* t2 = y1 * (C - B) = E */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100947 uECC_vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100948 uECC_vli_modMult_rnd(X2, Y2, Y2, s); /* t3 = (y2 - y1)^2 = D */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100949 uECC_vli_modSub(X2, X2, t6, curve_p); /* t3 = D - (B + C) = x3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300950
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100951 uECC_vli_modSub(t7, X1, X2, curve_p); /* t7 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100952 uECC_vli_modMult_rnd(Y2, Y2, t7, s); /* t4 = (y2 - y1)*(B - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300953 /* t4 = (y2 - y1)*(B - x3) - E = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100954 uECC_vli_modSub(Y2, Y2, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300955
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100956 uECC_vli_modMult_rnd(t7, t5, t5, s); /* t7 = (y2 + y1)^2 = F */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100957 uECC_vli_modSub(t7, t7, t6, curve_p); /* t7 = F - (B + C) = x3' */
958 uECC_vli_modSub(t6, t7, X1, curve_p); /* t6 = x3' - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100959 uECC_vli_modMult_rnd(t6, t6, t5, s); /* t6 = (y2+y1)*(x3' - B) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300960 /* t2 = (y2+y1)*(x3' - B) - E = y3': */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100961 uECC_vli_modSub(Y1, t6, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300962
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100963 uECC_vli_set(X1, t7);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300964}
965
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +0100966static void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point,
Jarno Lamsa18987a42019-04-24 15:40:43 +0300967 const uECC_word_t * scalar,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +0100968 const uECC_word_t * initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300969{
970 /* R0 and R1 */
971 uECC_word_t Rx[2][NUM_ECC_WORDS];
972 uECC_word_t Ry[2][NUM_ECC_WORDS];
973 uECC_word_t z[NUM_ECC_WORDS];
974 bitcount_t i;
975 uECC_word_t nb;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100976 const wordcount_t num_words = NUM_ECC_WORDS;
977 const bitcount_t num_bits = NUM_ECC_BITS + 1; /* from regularize_k */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100978 ecc_wait_state_t wait_state;
979 ecc_wait_state_t * const ws = g_rng_function ? &wait_state : NULL;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300980
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100981 uECC_vli_set(Rx[1], point);
982 uECC_vli_set(Ry[1], point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300983
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100984 XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300985
986 for (i = num_bits - 2; i > 0; --i) {
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100987 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300988 nb = !uECC_vli_testBit(scalar, i);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100989 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
990 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300991 }
992
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100993 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300994 nb = !uECC_vli_testBit(scalar, 0);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100995 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300996
997 /* Find final 1/Z value. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100998 uECC_vli_modSub(z, Rx[1], Rx[0], curve_p); /* X1 - X0 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100999 uECC_vli_modMult_fast(z, z, Ry[1 - nb]); /* Yb * (X1 - X0) */
1000 uECC_vli_modMult_fast(z, z, point); /* xP * Yb * (X1 - X0) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001001 uECC_vli_modInv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0))*/
Jarno Lamsa18987a42019-04-24 15:40:43 +03001002 /* yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001003 uECC_vli_modMult_fast(z, z, point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001004 /* Xb * yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001005 uECC_vli_modMult_fast(z, z, Rx[1 - nb]);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001006 /* End 1/Z calculation */
1007
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001008 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001009 apply_z(Rx[0], Ry[0], z);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001010
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +01001011 uECC_vli_set(result, Rx[0]);
1012 uECC_vli_set(result + num_words, Ry[0]);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001013}
1014
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +01001015static uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001016 uECC_word_t *k1)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001017{
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001018 bitcount_t num_n_bits = NUM_ECC_BITS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001019
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001020 uECC_word_t carry = uECC_vli_add(k0, k, curve_n) ||
Teppo Järvelin0b1d7d92019-12-13 07:39:39 +02001021 uECC_vli_testBit(k0, num_n_bits);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001022
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001023 uECC_vli_add(k1, k0, curve_n);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001024
1025 return carry;
1026}
1027
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001028int EccPoint_mult_safer(uECC_word_t * result, const uECC_word_t * point,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001029 const uECC_word_t * scalar)
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001030{
1031 uECC_word_t tmp[NUM_ECC_WORDS];
1032 uECC_word_t s[NUM_ECC_WORDS];
1033 uECC_word_t *k2[2] = {tmp, s};
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001034 wordcount_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001035 uECC_word_t carry;
1036 uECC_word_t *initial_Z = 0;
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001037 int r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001038 volatile int problem;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001039
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001040 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001041 problem = -1;
1042 problem = uECC_check_curve_integrity();
1043 if (problem != 0) {
1044 return UECC_FAULT_DETECTED;
1045 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001046 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001047 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001048 return UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001049 }
1050
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001051 /* Protects against invalid curve attacks */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001052 problem = -1;
1053 problem = uECC_valid_point(point);
1054 if (problem != 0) {
1055 /* invalid input, can happen without fault */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001056 return UECC_FAILURE;
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001057 }
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) {
1060 /* failure on second check means fault, though */
1061 return UECC_FAULT_DETECTED;
1062 }
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001063
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001064 /* Regularize the bitcount for the private key so that attackers cannot use a
1065 * side channel attack to learn the number of leading zeros. */
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001066 carry = regularize_k(scalar, tmp, s);
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001067
1068 /* If an RNG function was specified, get a random initial Z value to
1069 * protect against side-channel attacks such as Template SPA */
1070 if (g_rng_function) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001071 if (!uECC_generate_random_int(k2[carry], curve_p, num_words)) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001072 r = UECC_FAILURE;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001073 goto clear_and_out;
1074 }
1075 initial_Z = k2[carry];
1076 }
1077
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001078 EccPoint_mult(result, point, k2[!carry], initial_Z);
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001079
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001080 /* Protect against fault injections that would make the resulting
1081 * point not lie on the intended curve */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001082 problem = -1;
1083 problem = uECC_valid_point(result);
1084 if (problem != 0) {
1085 r = UECC_FAULT_DETECTED;
1086 goto clear_and_out;
1087 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001088 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001089 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001090 r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001091 goto clear_and_out;
1092 }
1093
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001094 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001095 problem = -1;
1096 problem = uECC_check_curve_integrity();
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é-Gonnard2b909612019-11-21 13:37:00 +01001104 goto clear_and_out;
1105 }
1106
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001107 r = UECC_SUCCESS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001108
1109clear_and_out:
1110 /* erasing temporary buffer used to store secret: */
1111 mbedtls_platform_zeroize(k2, sizeof(k2));
1112 mbedtls_platform_zeroize(tmp, sizeof(tmp));
1113 mbedtls_platform_zeroize(s, sizeof(s));
1114
1115 return r;
1116}
1117
Jarno Lamsa18987a42019-04-24 15:40:43 +03001118uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001119 uECC_word_t *private_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001120{
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001121 return EccPoint_mult_safer(result, curve_G, private_key);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001122}
1123
1124/* Converts an integer in uECC native format to big-endian bytes. */
1125void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
1126 const unsigned int *native)
1127{
1128 wordcount_t i;
1129 for (i = 0; i < num_bytes; ++i) {
1130 unsigned b = num_bytes - 1 - i;
1131 bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE));
1132 }
1133}
1134
1135/* Converts big-endian bytes to an integer in uECC native format. */
1136void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes,
1137 int num_bytes)
1138{
1139 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +01001140 uECC_vli_clear(native);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001141 for (i = 0; i < num_bytes; ++i) {
1142 unsigned b = num_bytes - 1 - i;
1143 native[b / uECC_WORD_SIZE] |=
1144 (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE));
1145 }
1146}
1147
1148int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
1149 wordcount_t num_words)
1150{
1151 uECC_word_t mask = (uECC_word_t)-1;
1152 uECC_word_t tries;
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +01001153 bitcount_t num_bits = uECC_vli_numBits(top);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001154
1155 if (!g_rng_function) {
1156 return 0;
1157 }
1158
1159 for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
1160 if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) {
1161 return 0;
1162 }
1163 random[num_words - 1] &=
1164 mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits));
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001165 if (!uECC_vli_isZero(random) &&
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +01001166 uECC_vli_cmp(top, random) == 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001167 return 1;
1168 }
1169 }
1170 return 0;
1171}
1172
1173
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001174int uECC_valid_point(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001175{
1176 uECC_word_t tmp1[NUM_ECC_WORDS];
1177 uECC_word_t tmp2[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001178 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa83d78812019-12-04 14:40:57 +02001179 volatile uECC_word_t diff = 0xffffffff;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001180
1181 /* The point at infinity is invalid. */
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001182 if (EccPoint_isZero(point)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001183 return -1;
1184 }
1185
1186 /* x and y must be smaller than p. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001187 if (uECC_vli_cmp_unsafe(curve_p, point) != 1 ||
1188 uECC_vli_cmp_unsafe(curve_p, point + num_words) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001189 return -2;
1190 }
1191
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001192 uECC_vli_modMult_fast(tmp1, point + num_words, point + num_words);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001193 x_side_default(tmp2, point); /* tmp2 = x^3 + ax + b */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001194
1195 /* Make sure that y^2 == x^3 + ax + b */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001196 diff = uECC_vli_equal(tmp1, tmp2);
1197 if (diff == 0) {
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001198 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001199 if (diff == 0) {
1200 return 0;
1201 }
1202 }
Jarno Lamsa18987a42019-04-24 15:40:43 +03001203
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001204 return -3;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001205}
1206
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001207int uECC_valid_public_key(const uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001208{
1209
1210 uECC_word_t _public[NUM_ECC_WORDS * 2];
1211
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001212 uECC_vli_bytesToNative(_public, public_key, NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001213 uECC_vli_bytesToNative(
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001214 _public + NUM_ECC_WORDS,
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001215 public_key + NUM_ECC_BYTES,
1216 NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001217
Manuel Pégourié-Gonnarda6115082019-11-21 10:29:14 +01001218 if (memcmp(_public, curve_G, NUM_ECC_WORDS * 2) == 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001219 return -4;
1220 }
1221
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001222 return uECC_valid_point(_public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001223}
1224
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001225int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001226{
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001227 int ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001228 uECC_word_t _private[NUM_ECC_WORDS];
1229 uECC_word_t _public[NUM_ECC_WORDS * 2];
1230
1231 uECC_vli_bytesToNative(
1232 _private,
1233 private_key,
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +01001234 BITS_TO_BYTES(NUM_ECC_BITS));
Jarno Lamsa18987a42019-04-24 15:40:43 +03001235
1236 /* Make sure the private key is in the range [1, n-1]. */
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001237 if (uECC_vli_isZero(_private)) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001238 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001239 }
1240
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001241 if (uECC_vli_cmp(curve_n, _private) != 1) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001242 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001243 }
1244
1245 /* Compute public key. */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001246 ret = EccPoint_compute_public_key(_public, _private);
1247 if (ret != UECC_SUCCESS) {
1248 return ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001249 }
1250
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001251 uECC_vli_nativeToBytes(public_key, NUM_ECC_BYTES, _public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001252 uECC_vli_nativeToBytes(
1253 public_key +
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001254 NUM_ECC_BYTES, NUM_ECC_BYTES, _public + NUM_ECC_WORDS);
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001255 return UECC_SUCCESS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001256}
Jarno Lamsa18987a42019-04-24 15:40:43 +03001257