blob: 086555a0494bfa8fc2730c8e322f6c0882e68b88 [file] [log] [blame]
Jarno Lamsa18987a42019-04-24 15:40:43 +03001/* ecc.c - TinyCrypt implementation of common ECC functions */
2
3/*
Simon Butcher92c3d1f2019-09-09 17:25:08 +01004 * Copyright (c) 2019, Arm Limited (or its affiliates), All Rights Reserved.
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8/*
Jarno Lamsa18987a42019-04-24 15:40:43 +03009 * Copyright (c) 2014, Kenneth MacKay
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 * * Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions are met:
35 *
36 * - Redistributions of source code must retain the above copyright notice,
37 * this list of conditions and the following disclaimer.
38 *
39 * - Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 *
43 * - Neither the name of Intel Corporation nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57 * POSSIBILITY OF SUCH DAMAGE.
58 */
59
Hanno Becker36ae7582019-07-23 15:52:35 +010060#if !defined(MBEDTLS_CONFIG_FILE)
61#include "mbedtls/config.h"
62#else
63#include MBEDTLS_CONFIG_FILE
64#endif
65
Manuel Pégourié-Gonnardafdc1b52019-05-09 11:24:11 +020066#if defined(MBEDTLS_USE_TINYCRYPT)
Jarno Lamsa18987a42019-04-24 15:40:43 +030067#include <tinycrypt/ecc.h>
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +010068#include "mbedtls/platform_util.h"
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +010069#include "mbedtls/sha256.h"
Jarno Lamsa18987a42019-04-24 15:40:43 +030070#include <string.h>
71
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +010072/* Parameters for curve NIST P-256 aka secp256r1 */
73const uECC_word_t curve_p[NUM_ECC_WORDS] = {
74 BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
75 BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00),
76 BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
77 BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF)
78};
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +010079const uECC_word_t curve_n[NUM_ECC_WORDS] = {
80 BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3),
81 BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC),
82 BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
83 BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF)
84};
Manuel Pégourié-Gonnarda6115082019-11-21 10:29:14 +010085const uECC_word_t curve_G[2 * NUM_ECC_WORDS] = {
86 BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4),
87 BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77),
88 BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8),
89 BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B),
90 BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB),
91 BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B),
92 BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E),
93 BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F)
94};
Manuel Pégourié-Gonnardffd13992019-11-21 10:39:06 +010095const uECC_word_t curve_b[NUM_ECC_WORDS] = {
96 BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B),
97 BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65),
98 BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3),
99 BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A)
100};
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100101
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100102static int uECC_update_param_sha256(mbedtls_sha256_context *ctx,
103 const uECC_word_t val[NUM_ECC_WORDS])
104{
105 uint8_t bytes[NUM_ECC_BYTES];
106
107 uECC_vli_nativeToBytes(bytes, NUM_ECC_BYTES, val);
108 return mbedtls_sha256_update_ret(ctx, bytes, NUM_ECC_BYTES);
109}
110
111static int uECC_compute_param_sha256(unsigned char output[32])
112{
113 int ret = UECC_FAILURE;
114 mbedtls_sha256_context ctx;
115
116 mbedtls_sha256_init( &ctx );
117
118 if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) {
119 goto exit;
120 }
121
122 if (uECC_update_param_sha256(&ctx, curve_p) != 0 ||
123 uECC_update_param_sha256(&ctx, curve_n) != 0 ||
124 uECC_update_param_sha256(&ctx, curve_G) != 0 ||
125 uECC_update_param_sha256(&ctx, curve_G + NUM_ECC_WORDS) != 0 ||
126 uECC_update_param_sha256(&ctx, curve_b) != 0)
127 {
128 goto exit;
129 }
130
131 if (mbedtls_sha256_finish_ret(&ctx, output) != 0) {
132 goto exit;
133 }
134
135 ret = UECC_SUCCESS;
136
137exit:
138 mbedtls_sha256_free( &ctx );
139
140 return ret;
141}
142
143/*
144 * Check integrity of curve parameters.
145 * Return 0 if everything's OK, non-zero otherwise.
146 */
147static int uECC_check_curve_integrity(void)
148{
149 unsigned char computed[32];
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100150 static const unsigned char reference[32] = {
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100151 0x2d, 0xa1, 0xa4, 0x64, 0x45, 0x28, 0x0d, 0xe1,
152 0x93, 0xf9, 0x29, 0x2f, 0xac, 0x3e, 0xe2, 0x92,
153 0x76, 0x0a, 0xe2, 0xbc, 0xce, 0x2a, 0xa2, 0xc6,
154 0x38, 0xf2, 0x19, 0x1d, 0x76, 0x72, 0x93, 0x49,
155 };
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 */
172 mbedtls_platform_enforce_volatile_reads();
173 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;
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100290 uECC_word_t tmp1, tmp2;
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100291 volatile int i;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300292
Manuel Pégourié-Gonnard2eca3d32019-11-04 14:33:09 +0100293 for (i = NUM_ECC_WORDS - 1; i >= 0; --i) {
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100294 tmp1 = left[i];
295 tmp2 = right[i];
296 diff |= (tmp1 ^ tmp2);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300297 }
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100298
299 /* i should be -1 now */
300 mbedtls_platform_enforce_volatile_reads();
301 diff |= i ^ -1;
302
Manuel Pégourié-Gonnard2b6312b2019-11-06 10:42:02 +0100303 return diff;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300304}
305
306uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond)
307{
308 return (p_true*(cond)) | (p_false*(!cond));
309}
310
311/* Computes result = left - right, returning borrow, in constant time.
312 * Can modify in place. */
313uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100314 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300315{
316 uECC_word_t borrow = 0;
317 wordcount_t i;
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100318 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300319 uECC_word_t diff = left[i] - right[i] - borrow;
320 uECC_word_t val = (diff > left[i]);
321 borrow = cond_set(val, borrow, (diff != left[i]));
322
323 result[i] = diff;
324 }
325 return borrow;
326}
327
328/* Computes result = left + right, returning carry, in constant time.
329 * Can modify in place. */
330static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100331 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300332{
333 uECC_word_t carry = 0;
334 wordcount_t i;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100335 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300336 uECC_word_t sum = left[i] + right[i] + carry;
337 uECC_word_t val = (sum < left[i]);
338 carry = cond_set(val, carry, (sum != left[i]));
339 result[i] = sum;
340 }
341 return carry;
342}
343
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +0100344cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300345{
346 uECC_word_t tmp[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100347 uECC_word_t neg = !!uECC_vli_sub(tmp, left, right);
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100348 uECC_word_t equal = uECC_vli_isZero(tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300349 return (!equal - 2 * neg);
350}
351
352/* Computes vli = vli >> 1. */
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100353static void uECC_vli_rshift1(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300354{
355 uECC_word_t *end = vli;
356 uECC_word_t carry = 0;
357
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100358 vli += NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300359 while (vli-- > end) {
360 uECC_word_t temp = *vli;
361 *vli = (temp >> 1) | carry;
362 carry = temp << (uECC_WORD_BITS - 1);
363 }
364}
365
Manuel Pégourié-Gonnard86c4f812019-10-31 13:02:03 +0100366/* Compute a * b + r, where r is a double-word with high-order word r1 and
367 * low-order word r0, and store the result in the same double-word (r1, r0),
368 * with the carry bit stored in r2.
369 *
370 * (r2, r1, r0) = a * b + (r1, r0):
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200371 * [in] a, b: operands to be multiplied
372 * [in] r0, r1: low and high-order words of operand to add
373 * [out] r0, r1: low and high-order words of the result
374 * [out] r2: carry
375 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300376static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0,
377 uECC_word_t *r1, uECC_word_t *r2)
378{
379
380 uECC_dword_t p = (uECC_dword_t)a * b;
381 uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
382 r01 += p;
383 *r2 += (r01 < p);
384 *r1 = r01 >> uECC_WORD_BITS;
385 *r0 = (uECC_word_t)r01;
386
387}
388
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200389/* State for implementing random delays in uECC_vli_mult_rnd().
390 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100391 * The state is initialized by randomizing delays and setting i = 0.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200392 * Each call to uECC_vli_mult_rnd() uses one byte of delays and increments i.
393 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100394 * Randomized vli multiplication is used only for point operations
395 * (XYcZ_add_rnd() * and XYcZ_addC_rnd()) in scalar multiplication
396 * (ECCPoint_mult()). Those go in pair, and each pair does 14 calls to
397 * uECC_vli_mult_rnd() (6 in XYcZ_add_rnd() and 8 in XYcZ_addC_rnd(),
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100398 * indirectly through uECC_vli_modMult_rnd().
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100399 *
400 * Considering this, in order to minimize the number of calls to the RNG
401 * (which impact performance) while keeping the size of the structure low,
402 * make room for 14 randomized vli mults, which corresponds to one step in the
403 * scalar multiplication routine.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200404 */
405typedef struct {
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100406 uint8_t i;
407 uint8_t delays[14];
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100408} ecc_wait_state_t;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200409
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100410/*
411 * Reset wait_state so that it's ready to be used.
412 */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100413void ecc_wait_state_reset(ecc_wait_state_t *ws)
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100414{
415 if (ws == NULL)
416 return;
417
418 ws->i = 0;
419 g_rng_function(ws->delays, sizeof(ws->delays));
420}
421
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200422/* Computes result = left * right. Result must be 2 * num_words long.
423 *
424 * As a counter-measure against horizontal attacks, add noise by performing
425 * a random number of extra computations performing random additional accesses
426 * to limbs of the input.
427 *
428 * Each of the two actual computation loops is surrounded by two
429 * similar-looking waiting loops, to make the beginning and end of the actual
430 * computation harder to spot.
431 *
432 * We add 4 waiting loops of between 0 and 3 calls to muladd() each. That
433 * makes an average of 6 extra calls. Compared to the main computation which
434 * makes 64 such calls, this represents an average performance degradation of
435 * less than 10%.
436 *
437 * Compared to the original uECC_vli_mult(), loose the num_words argument as we
438 * know it's always 8. This saves a bit of code size and execution speed.
439 */
440static void uECC_vli_mult_rnd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100441 const uECC_word_t *right, ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300442{
443
444 uECC_word_t r0 = 0;
445 uECC_word_t r1 = 0;
446 uECC_word_t r2 = 0;
447 wordcount_t i, k;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100448 const uint8_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200449
450 /* Fetch 8 bit worth of delay from the state; 0 if we have no state */
451 uint8_t delays = s ? s->delays[s->i++] : 0;
452 uECC_word_t rr0 = 0, rr1 = 0;
453 volatile uECC_word_t r;
454
455 /* Mimic start of next loop: k in [0, 3] */
456 k = 0 + (delays & 0x03);
457 delays >>= 2;
458 /* k = 0 -> i in [1, 0] -> 0 extra muladd;
459 * k = 3 -> i in [1, 3] -> 3 extra muladd */
Manuel Pégourié-Gonnardc8814862019-11-05 10:32:37 +0100460 for (i = 1; i <= k; ++i) {
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200461 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
462 }
463 r = rr0;
464 rr0 = rr1;
465 rr1 = r2;
466 r2 = 0;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300467
468 /* Compute each digit of result in sequence, maintaining the carries. */
469 for (k = 0; k < num_words; ++k) {
470
471 for (i = 0; i <= k; ++i) {
472 muladd(left[i], right[k - i], &r0, &r1, &r2);
473 }
474
475 result[k] = r0;
476 r0 = r1;
477 r1 = r2;
478 r2 = 0;
479 }
480
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200481 /* Mimic end of previous loop: k in [4, 7] */
482 k = 4 + (delays & 0x03);
483 delays >>= 2;
484 /* k = 4 -> i in [5, 4] -> 0 extra muladd;
485 * k = 7 -> i in [5, 7] -> 3 extra muladd */
486 for (i = 5; i <= k; ++i) {
487 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
488 }
489 r = rr0;
490 rr0 = rr1;
491 rr1 = r2;
492 r2 = 0;
493
494 /* Mimic start of next loop: k in [8, 11] */
495 k = 11 - (delays & 0x03);
496 delays >>= 2;
497 /* k = 8 -> i in [5, 7] -> 3 extra muladd;
498 * k = 11 -> i in [8, 7] -> 0 extra muladd */
499 for (i = (k + 5) - num_words; i < num_words; ++i) {
500 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
501 }
502 r = rr0;
503 rr0 = rr1;
504 rr1 = r2;
505 r2 = 0;
506
Jarno Lamsa18987a42019-04-24 15:40:43 +0300507 for (k = num_words; k < num_words * 2 - 1; ++k) {
508
509 for (i = (k + 1) - num_words; i < num_words; ++i) {
510 muladd(left[i], right[k - i], &r0, &r1, &r2);
511 }
512 result[k] = r0;
513 r0 = r1;
514 r1 = r2;
515 r2 = 0;
516 }
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200517
Jarno Lamsa18987a42019-04-24 15:40:43 +0300518 result[num_words * 2 - 1] = r0;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200519
520 /* Mimic end of previous loop: k in [12, 15] */
521 k = 15 - (delays & 0x03);
522 delays >>= 2;
523 /* k = 12 -> i in [5, 7] -> 3 extra muladd;
524 * k = 15 -> i in [8, 7] -> 0 extra muladd */
525 for (i = (k + 1) - num_words; i < num_words; ++i) {
526 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
527 }
528 r = rr0;
529 rr0 = rr1;
530 rr1 = r2;
531 r2 = 0;
532
533 /* avoid warning that r is set but not used */
534 (void) r;
535}
536
Jarno Lamsa18987a42019-04-24 15:40:43 +0300537void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard0779be72019-11-04 14:48:22 +0100538 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300539{
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100540 uECC_word_t carry = uECC_vli_add(result, left, right);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100541 if (carry || uECC_vli_cmp_unsafe(mod, result) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300542 /* result > mod (result = mod + remainder), so subtract mod to get
543 * remainder. */
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100544 uECC_vli_sub(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300545 }
546}
547
548void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard1b0875d2019-11-04 14:50:54 +0100549 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300550{
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100551 uECC_word_t l_borrow = uECC_vli_sub(result, left, right);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300552 if (l_borrow) {
553 /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
554 * we can get the correct result from result + mod (with overflow). */
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100555 uECC_vli_add(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300556 }
557}
558
559/* Computes result = product % mod, where product is 2N words long. */
560/* Currently only designed to work for curve_p or curve_n. */
561void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100562 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300563{
564 uECC_word_t mod_multiple[2 * NUM_ECC_WORDS];
565 uECC_word_t tmp[2 * NUM_ECC_WORDS];
566 uECC_word_t *v[2] = {tmp, product};
567 uECC_word_t index;
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100568 const wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300569
570 /* Shift mod so its highest set bit is at the maximum position. */
571 bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) -
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100572 uECC_vli_numBits(mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300573 wordcount_t word_shift = shift / uECC_WORD_BITS;
574 wordcount_t bit_shift = shift % uECC_WORD_BITS;
575 uECC_word_t carry = 0;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100576 uECC_vli_clear(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300577 if (bit_shift > 0) {
578 for(index = 0; index < (uECC_word_t)num_words; ++index) {
579 mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;
580 carry = mod[index] >> (uECC_WORD_BITS - bit_shift);
581 }
582 } else {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100583 uECC_vli_set(mod_multiple + word_shift, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300584 }
585
586 for (index = 1; shift >= 0; --shift) {
587 uECC_word_t borrow = 0;
588 wordcount_t i;
589 for (i = 0; i < num_words * 2; ++i) {
590 uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;
591 if (diff != v[index][i]) {
592 borrow = (diff > v[index][i]);
593 }
594 v[1 - index][i] = diff;
595 }
596 /* Swap the index if there was no borrow */
597 index = !(index ^ borrow);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100598 uECC_vli_rshift1(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300599 mod_multiple[num_words - 1] |= mod_multiple[num_words] <<
600 (uECC_WORD_BITS - 1);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100601 uECC_vli_rshift1(mod_multiple + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300602 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100603 uECC_vli_set(result, v[index]);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300604}
605
606void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard3e20adf2019-11-04 15:00:43 +0100607 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300608{
609 uECC_word_t product[2 * NUM_ECC_WORDS];
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100610 uECC_vli_mult_rnd(product, left, right, NULL);
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100611 uECC_vli_mmod(result, product, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300612}
613
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100614static void uECC_vli_modMult_rnd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100615 const uECC_word_t *right, ecc_wait_state_t *s)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100616{
617 uECC_word_t product[2 * NUM_ECC_WORDS];
618 uECC_vli_mult_rnd(product, left, right, s);
619
620 vli_mmod_fast_secp256r1(result, product);
621}
622
Jarno Lamsa18987a42019-04-24 15:40:43 +0300623void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100624 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300625{
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100626 uECC_vli_modMult_rnd(result, left, right, NULL);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300627}
628
Jarno Lamsa18987a42019-04-24 15:40:43 +0300629#define EVEN(vli) (!(vli[0] & 1))
630
631static void vli_modInv_update(uECC_word_t *uv,
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100632 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300633{
634
635 uECC_word_t carry = 0;
636
637 if (!EVEN(uv)) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100638 carry = uECC_vli_add(uv, uv, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300639 }
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100640 uECC_vli_rshift1(uv);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300641 if (carry) {
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100642 uv[NUM_ECC_WORDS - 1] |= HIGH_BIT_SET;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300643 }
644}
645
646void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100647 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300648{
649 uECC_word_t a[NUM_ECC_WORDS], b[NUM_ECC_WORDS];
650 uECC_word_t u[NUM_ECC_WORDS], v[NUM_ECC_WORDS];
651 cmpresult_t cmpResult;
652
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100653 if (uECC_vli_isZero(input)) {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100654 uECC_vli_clear(result);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300655 return;
656 }
657
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100658 uECC_vli_set(a, input);
659 uECC_vli_set(b, mod);
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100660 uECC_vli_clear(u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300661 u[0] = 1;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100662 uECC_vli_clear(v);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100663 while ((cmpResult = uECC_vli_cmp_unsafe(a, b)) != 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300664 if (EVEN(a)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100665 uECC_vli_rshift1(a);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100666 vli_modInv_update(u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300667 } else if (EVEN(b)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100668 uECC_vli_rshift1(b);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100669 vli_modInv_update(v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300670 } else if (cmpResult > 0) {
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100671 uECC_vli_sub(a, a, b);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100672 uECC_vli_rshift1(a);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100673 if (uECC_vli_cmp_unsafe(u, v) < 0) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100674 uECC_vli_add(u, u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300675 }
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100676 uECC_vli_sub(u, u, v);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100677 vli_modInv_update(u, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300678 } else {
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100679 uECC_vli_sub(b, b, a);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100680 uECC_vli_rshift1(b);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100681 if (uECC_vli_cmp_unsafe(v, u) < 0) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100682 uECC_vli_add(v, v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300683 }
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100684 uECC_vli_sub(v, v, u);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100685 vli_modInv_update(v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300686 }
687 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100688 uECC_vli_set(result, u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300689}
690
691/* ------ Point operations ------ */
692
693void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100694 uECC_word_t * Z1)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300695{
696 /* t1 = X, t2 = Y, t3 = Z */
697 uECC_word_t t4[NUM_ECC_WORDS];
698 uECC_word_t t5[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +0100699 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300700
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100701 if (uECC_vli_isZero(Z1)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300702 return;
703 }
704
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100705 uECC_vli_modMult_fast(t4, Y1, Y1); /* t4 = y1^2 */
706 uECC_vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */
707 uECC_vli_modMult_fast(t4, t4, t4); /* t4 = y1^4 */
708 uECC_vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */
709 uECC_vli_modMult_fast(Z1, Z1, Z1); /* t3 = z1^2 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300710
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100711 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */
712 uECC_vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */
713 uECC_vli_modSub(Z1, X1, Z1, curve_p); /* t3 = x1 - z1^2 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100714 uECC_vli_modMult_fast(X1, X1, Z1); /* t1 = x1^2 - z1^4 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300715
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100716 uECC_vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */
717 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300718 if (uECC_vli_testBit(X1, 0)) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100719 uECC_word_t l_carry = uECC_vli_add(X1, X1, curve_p);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100720 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300721 X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
722 } else {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100723 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300724 }
725
726 /* t1 = 3/2*(x1^2 - z1^4) = B */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100727 uECC_vli_modMult_fast(Z1, X1, X1); /* t3 = B^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100728 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - A */
729 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */
730 uECC_vli_modSub(t5, t5, Z1, curve_p); /* t5 = A - x3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100731 uECC_vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300732 /* t4 = B * (A - x3) - y1^4 = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100733 uECC_vli_modSub(t4, X1, t4, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300734
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100735 uECC_vli_set(X1, Z1);
736 uECC_vli_set(Z1, Y1);
737 uECC_vli_set(Y1, t4);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300738}
739
Manuel Pégourié-Gonnard1c6f7ea2019-11-21 09:18:29 +0100740/*
741 * @brief Computes x^3 + ax + b. result must not overlap x.
742 * @param result OUT -- x^3 + ax + b
743 * @param x IN -- value of x
744 * @param curve IN -- elliptic curve
745 */
746static void x_side_default(uECC_word_t *result,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100747 const uECC_word_t *x)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300748{
749 uECC_word_t _3[NUM_ECC_WORDS] = {3}; /* -a = 3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300750
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100751 uECC_vli_modMult_fast(result, x, x); /* r = x^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100752 uECC_vli_modSub(result, result, _3, curve_p); /* r = x^2 - 3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100753 uECC_vli_modMult_fast(result, result, x); /* r = x^3 - 3x */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300754 /* r = x^3 - 3x + b: */
Manuel Pégourié-Gonnardffd13992019-11-21 10:39:06 +0100755 uECC_vli_modAdd(result, result, curve_b, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300756}
757
Jarno Lamsa18987a42019-04-24 15:40:43 +0300758void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int*product)
759{
760 unsigned int tmp[NUM_ECC_WORDS];
761 int carry;
762
763 /* t */
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100764 uECC_vli_set(result, product);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300765
766 /* s1 */
767 tmp[0] = tmp[1] = tmp[2] = 0;
768 tmp[3] = product[11];
769 tmp[4] = product[12];
770 tmp[5] = product[13];
771 tmp[6] = product[14];
772 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100773 carry = uECC_vli_add(tmp, tmp, tmp);
774 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300775
776 /* s2 */
777 tmp[3] = product[12];
778 tmp[4] = product[13];
779 tmp[5] = product[14];
780 tmp[6] = product[15];
781 tmp[7] = 0;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100782 carry += uECC_vli_add(tmp, tmp, tmp);
783 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300784
785 /* s3 */
786 tmp[0] = product[8];
787 tmp[1] = product[9];
788 tmp[2] = product[10];
789 tmp[3] = tmp[4] = tmp[5] = 0;
790 tmp[6] = product[14];
791 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100792 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300793
794 /* s4 */
795 tmp[0] = product[9];
796 tmp[1] = product[10];
797 tmp[2] = product[11];
798 tmp[3] = product[13];
799 tmp[4] = product[14];
800 tmp[5] = product[15];
801 tmp[6] = product[13];
802 tmp[7] = product[8];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100803 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300804
805 /* d1 */
806 tmp[0] = product[11];
807 tmp[1] = product[12];
808 tmp[2] = product[13];
809 tmp[3] = tmp[4] = tmp[5] = 0;
810 tmp[6] = product[8];
811 tmp[7] = product[10];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100812 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300813
814 /* d2 */
815 tmp[0] = product[12];
816 tmp[1] = product[13];
817 tmp[2] = product[14];
818 tmp[3] = product[15];
819 tmp[4] = tmp[5] = 0;
820 tmp[6] = product[9];
821 tmp[7] = product[11];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100822 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300823
824 /* d3 */
825 tmp[0] = product[13];
826 tmp[1] = product[14];
827 tmp[2] = product[15];
828 tmp[3] = product[8];
829 tmp[4] = product[9];
830 tmp[5] = product[10];
831 tmp[6] = 0;
832 tmp[7] = product[12];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100833 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300834
835 /* d4 */
836 tmp[0] = product[14];
837 tmp[1] = product[15];
838 tmp[2] = 0;
839 tmp[3] = product[9];
840 tmp[4] = product[10];
841 tmp[5] = product[11];
842 tmp[6] = 0;
843 tmp[7] = product[13];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100844 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300845
846 if (carry < 0) {
847 do {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100848 carry += uECC_vli_add(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300849 }
850 while (carry < 0);
851 } else {
852 while (carry ||
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100853 uECC_vli_cmp_unsafe(curve_p, result) != 1) {
854 carry -= uECC_vli_sub(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300855 }
856 }
857}
858
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100859uECC_word_t EccPoint_isZero(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300860{
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100861 return uECC_vli_isZero(point);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300862}
863
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100864void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300865{
866 uECC_word_t t1[NUM_ECC_WORDS];
867
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100868 uECC_vli_modMult_fast(t1, Z, Z); /* z^2 */
869 uECC_vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */
870 uECC_vli_modMult_fast(t1, t1, Z); /* z^3 */
871 uECC_vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300872}
873
874/* P = (x1, y1) => 2P, (x2, y2) => P' */
875static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1,
876 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100877 const uECC_word_t * const initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300878{
879 uECC_word_t z[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +0300880 if (initial_Z) {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100881 uECC_vli_set(z, initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300882 } else {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100883 uECC_vli_clear(z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300884 z[0] = 1;
885 }
886
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100887 uECC_vli_set(X2, X1);
888 uECC_vli_set(Y2, Y1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300889
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100890 apply_z(X1, Y1, z);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100891 double_jacobian_default(X1, Y1, z);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100892 apply_z(X2, Y2, z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300893}
894
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100895static void XYcZ_add_rnd(uECC_word_t * X1, uECC_word_t * Y1,
896 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100897 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300898{
899 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
900 uECC_word_t t5[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100901
902 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100903 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100904 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
905 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100906 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100907 uECC_vli_modMult_rnd(t5, Y2, Y2, s); /* t5 = (y2 - y1)^2 = D */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300908
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100909 uECC_vli_modSub(t5, t5, X1, curve_p); /* t5 = D - B */
910 uECC_vli_modSub(t5, t5, X2, curve_p); /* t5 = D - B - C = x3 */
911 uECC_vli_modSub(X2, X2, X1, curve_p); /* t3 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100912 uECC_vli_modMult_rnd(Y1, Y1, X2, s); /* t2 = y1*(C - B) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100913 uECC_vli_modSub(X2, X1, t5, curve_p); /* t3 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100914 uECC_vli_modMult_rnd(Y2, Y2, X2, s); /* t4 = (y2 - y1)*(B - x3) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100915 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300916
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100917 uECC_vli_set(X2, t5);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300918}
919
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100920void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100921 uECC_word_t * X2, uECC_word_t * Y2)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100922{
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100923 XYcZ_add_rnd(X1, Y1, X2, Y2, NULL);
924}
925
Jarno Lamsa18987a42019-04-24 15:40:43 +0300926/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
927 Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
928 or P => P - Q, Q => P + Q
929 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100930static void XYcZ_addC_rnd(uECC_word_t * X1, uECC_word_t * Y1,
931 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100932 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300933{
934 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
935 uECC_word_t t5[NUM_ECC_WORDS];
936 uECC_word_t t6[NUM_ECC_WORDS];
937 uECC_word_t t7[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100938
939 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100940 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100941 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
942 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100943 uECC_vli_modAdd(t5, Y2, Y1, curve_p); /* t5 = y2 + y1 */
944 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300945
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100946 uECC_vli_modSub(t6, X2, X1, curve_p); /* t6 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100947 uECC_vli_modMult_rnd(Y1, Y1, t6, s); /* t2 = y1 * (C - B) = E */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100948 uECC_vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100949 uECC_vli_modMult_rnd(X2, Y2, Y2, s); /* t3 = (y2 - y1)^2 = D */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100950 uECC_vli_modSub(X2, X2, t6, curve_p); /* t3 = D - (B + C) = x3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300951
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100952 uECC_vli_modSub(t7, X1, X2, curve_p); /* t7 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100953 uECC_vli_modMult_rnd(Y2, Y2, t7, s); /* t4 = (y2 - y1)*(B - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300954 /* t4 = (y2 - y1)*(B - x3) - E = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100955 uECC_vli_modSub(Y2, Y2, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300956
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100957 uECC_vli_modMult_rnd(t7, t5, t5, s); /* t7 = (y2 + y1)^2 = F */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100958 uECC_vli_modSub(t7, t7, t6, curve_p); /* t7 = F - (B + C) = x3' */
959 uECC_vli_modSub(t6, t7, X1, curve_p); /* t6 = x3' - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100960 uECC_vli_modMult_rnd(t6, t6, t5, s); /* t6 = (y2+y1)*(x3' - B) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300961 /* t2 = (y2+y1)*(x3' - B) - E = y3': */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100962 uECC_vli_modSub(Y1, t6, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300963
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100964 uECC_vli_set(X1, t7);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300965}
966
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +0100967static void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point,
Jarno Lamsa18987a42019-04-24 15:40:43 +0300968 const uECC_word_t * scalar,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +0100969 const uECC_word_t * initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300970{
971 /* R0 and R1 */
972 uECC_word_t Rx[2][NUM_ECC_WORDS];
973 uECC_word_t Ry[2][NUM_ECC_WORDS];
974 uECC_word_t z[NUM_ECC_WORDS];
975 bitcount_t i;
976 uECC_word_t nb;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100977 const wordcount_t num_words = NUM_ECC_WORDS;
978 const bitcount_t num_bits = NUM_ECC_BITS + 1; /* from regularize_k */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100979 ecc_wait_state_t wait_state;
980 ecc_wait_state_t * const ws = g_rng_function ? &wait_state : NULL;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300981
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100982 uECC_vli_set(Rx[1], point);
983 uECC_vli_set(Ry[1], point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300984
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +0100985 XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300986
987 for (i = num_bits - 2; i > 0; --i) {
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100988 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300989 nb = !uECC_vli_testBit(scalar, i);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100990 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
991 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300992 }
993
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100994 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300995 nb = !uECC_vli_testBit(scalar, 0);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100996 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300997
998 /* Find final 1/Z value. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100999 uECC_vli_modSub(z, Rx[1], Rx[0], curve_p); /* X1 - X0 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001000 uECC_vli_modMult_fast(z, z, Ry[1 - nb]); /* Yb * (X1 - X0) */
1001 uECC_vli_modMult_fast(z, z, point); /* xP * Yb * (X1 - X0) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001002 uECC_vli_modInv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0))*/
Jarno Lamsa18987a42019-04-24 15:40:43 +03001003 /* yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001004 uECC_vli_modMult_fast(z, z, point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001005 /* Xb * yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001006 uECC_vli_modMult_fast(z, z, Rx[1 - nb]);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001007 /* End 1/Z calculation */
1008
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001009 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001010 apply_z(Rx[0], Ry[0], z);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001011
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +01001012 uECC_vli_set(result, Rx[0]);
1013 uECC_vli_set(result + num_words, Ry[0]);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001014}
1015
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +01001016static uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001017 uECC_word_t *k1)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001018{
1019
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001020 wordcount_t num_n_words = NUM_ECC_WORDS;
1021 bitcount_t num_n_bits = NUM_ECC_BITS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001022
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001023 uECC_word_t carry = uECC_vli_add(k0, k, curve_n) ||
Jarno Lamsa18987a42019-04-24 15:40:43 +03001024 (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) &&
1025 uECC_vli_testBit(k0, num_n_bits));
1026
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001027 uECC_vli_add(k1, k0, curve_n);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001028
1029 return carry;
1030}
1031
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001032int EccPoint_mult_safer(uECC_word_t * result, const uECC_word_t * point,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001033 const uECC_word_t * scalar)
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001034{
1035 uECC_word_t tmp[NUM_ECC_WORDS];
1036 uECC_word_t s[NUM_ECC_WORDS];
1037 uECC_word_t *k2[2] = {tmp, s};
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001038 wordcount_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001039 uECC_word_t carry;
1040 uECC_word_t *initial_Z = 0;
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001041 int r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001042 volatile int problem;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001043
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001044 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001045 problem = -1;
1046 problem = uECC_check_curve_integrity();
1047 if (problem != 0) {
1048 return UECC_FAULT_DETECTED;
1049 }
1050 mbedtls_platform_enforce_volatile_reads();
1051 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001052 return UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001053 }
1054
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001055 /* Protects against invalid curve attacks */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001056 problem = -1;
1057 problem = uECC_valid_point(point);
1058 if (problem != 0) {
1059 /* invalid input, can happen without fault */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001060 return UECC_FAILURE;
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001061 }
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001062 mbedtls_platform_enforce_volatile_reads();
1063 if (problem != 0) {
1064 /* failure on second check means fault, though */
1065 return UECC_FAULT_DETECTED;
1066 }
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001067
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001068 /* Regularize the bitcount for the private key so that attackers cannot use a
1069 * side channel attack to learn the number of leading zeros. */
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001070 carry = regularize_k(scalar, tmp, s);
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001071
1072 /* If an RNG function was specified, get a random initial Z value to
1073 * protect against side-channel attacks such as Template SPA */
1074 if (g_rng_function) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001075 if (!uECC_generate_random_int(k2[carry], curve_p, num_words)) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001076 r = UECC_FAILURE;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001077 goto clear_and_out;
1078 }
1079 initial_Z = k2[carry];
1080 }
1081
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001082 EccPoint_mult(result, point, k2[!carry], initial_Z);
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001083
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001084 /* Protect against fault injections that would make the resulting
1085 * point not lie on the intended curve */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001086 problem = -1;
1087 problem = uECC_valid_point(result);
1088 if (problem != 0) {
1089 r = UECC_FAULT_DETECTED;
1090 goto clear_and_out;
1091 }
1092 mbedtls_platform_enforce_volatile_reads();
1093 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001094 r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001095 goto clear_and_out;
1096 }
1097
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001098 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001099 problem = -1;
1100 problem = uECC_check_curve_integrity();
1101 if (problem != 0) {
1102 r = UECC_FAULT_DETECTED;
1103 goto clear_and_out;
1104 }
1105 mbedtls_platform_enforce_volatile_reads();
1106 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001107 r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001108 goto clear_and_out;
1109 }
1110
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001111 r = UECC_SUCCESS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001112
1113clear_and_out:
1114 /* erasing temporary buffer used to store secret: */
1115 mbedtls_platform_zeroize(k2, sizeof(k2));
1116 mbedtls_platform_zeroize(tmp, sizeof(tmp));
1117 mbedtls_platform_zeroize(s, sizeof(s));
1118
1119 return r;
1120}
1121
Jarno Lamsa18987a42019-04-24 15:40:43 +03001122uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001123 uECC_word_t *private_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001124{
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001125 return EccPoint_mult_safer(result, curve_G, private_key);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001126}
1127
1128/* Converts an integer in uECC native format to big-endian bytes. */
1129void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
1130 const unsigned int *native)
1131{
1132 wordcount_t i;
1133 for (i = 0; i < num_bytes; ++i) {
1134 unsigned b = num_bytes - 1 - i;
1135 bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE));
1136 }
1137}
1138
1139/* Converts big-endian bytes to an integer in uECC native format. */
1140void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes,
1141 int num_bytes)
1142{
1143 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +01001144 uECC_vli_clear(native);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001145 for (i = 0; i < num_bytes; ++i) {
1146 unsigned b = num_bytes - 1 - i;
1147 native[b / uECC_WORD_SIZE] |=
1148 (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE));
1149 }
1150}
1151
1152int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
1153 wordcount_t num_words)
1154{
1155 uECC_word_t mask = (uECC_word_t)-1;
1156 uECC_word_t tries;
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +01001157 bitcount_t num_bits = uECC_vli_numBits(top);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001158
1159 if (!g_rng_function) {
1160 return 0;
1161 }
1162
1163 for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
1164 if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) {
1165 return 0;
1166 }
1167 random[num_words - 1] &=
1168 mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits));
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001169 if (!uECC_vli_isZero(random) &&
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +01001170 uECC_vli_cmp(top, random) == 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001171 return 1;
1172 }
1173 }
1174 return 0;
1175}
1176
1177
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001178int uECC_valid_point(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001179{
1180 uECC_word_t tmp1[NUM_ECC_WORDS];
1181 uECC_word_t tmp2[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001182 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa83d78812019-12-04 14:40:57 +02001183 volatile uECC_word_t diff = 0xffffffff;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001184
1185 /* The point at infinity is invalid. */
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001186 if (EccPoint_isZero(point)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001187 return -1;
1188 }
1189
1190 /* x and y must be smaller than p. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001191 if (uECC_vli_cmp_unsafe(curve_p, point) != 1 ||
1192 uECC_vli_cmp_unsafe(curve_p, point + num_words) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001193 return -2;
1194 }
1195
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001196 uECC_vli_modMult_fast(tmp1, point + num_words, point + num_words);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001197 x_side_default(tmp2, point); /* tmp2 = x^3 + ax + b */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001198
1199 /* Make sure that y^2 == x^3 + ax + b */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001200 diff = uECC_vli_equal(tmp1, tmp2);
1201 if (diff == 0) {
1202 mbedtls_platform_enforce_volatile_reads();
1203 if (diff == 0) {
1204 return 0;
1205 }
1206 }
Jarno Lamsa18987a42019-04-24 15:40:43 +03001207
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001208 return -3;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001209}
1210
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001211int uECC_valid_public_key(const uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001212{
1213
1214 uECC_word_t _public[NUM_ECC_WORDS * 2];
1215
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001216 uECC_vli_bytesToNative(_public, public_key, NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001217 uECC_vli_bytesToNative(
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001218 _public + NUM_ECC_WORDS,
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001219 public_key + NUM_ECC_BYTES,
1220 NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001221
Manuel Pégourié-Gonnarda6115082019-11-21 10:29:14 +01001222 if (memcmp(_public, curve_G, NUM_ECC_WORDS * 2) == 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001223 return -4;
1224 }
1225
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001226 return uECC_valid_point(_public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001227}
1228
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001229int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001230{
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001231 int ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001232 uECC_word_t _private[NUM_ECC_WORDS];
1233 uECC_word_t _public[NUM_ECC_WORDS * 2];
1234
1235 uECC_vli_bytesToNative(
1236 _private,
1237 private_key,
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +01001238 BITS_TO_BYTES(NUM_ECC_BITS));
Jarno Lamsa18987a42019-04-24 15:40:43 +03001239
1240 /* Make sure the private key is in the range [1, n-1]. */
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001241 if (uECC_vli_isZero(_private)) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001242 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001243 }
1244
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001245 if (uECC_vli_cmp(curve_n, _private) != 1) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001246 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001247 }
1248
1249 /* Compute public key. */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001250 ret = EccPoint_compute_public_key(_public, _private);
1251 if (ret != UECC_SUCCESS) {
1252 return ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001253 }
1254
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001255 uECC_vli_nativeToBytes(public_key, NUM_ECC_BYTES, _public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001256 uECC_vli_nativeToBytes(
1257 public_key +
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001258 NUM_ECC_BYTES, NUM_ECC_BYTES, _public + NUM_ECC_WORDS);
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001259 return UECC_SUCCESS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001260}
Jarno Lamsa46132202019-04-29 14:29:52 +03001261#else
Manuel Pégourié-Gonnardafdc1b52019-05-09 11:24:11 +02001262typedef int mbedtls_dummy_tinycrypt_def;
1263#endif /* MBEDTLS_USE_TINYCRYPT */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001264