blob: 01db4e6eca9a0d0836328fc8476dd49f0b418cff [file] [log] [blame]
Jarno Lamsa18987a42019-04-24 15:40:43 +03001/* ecc.c - TinyCrypt implementation of common ECC functions */
2
3/*
Simon Butcher92c3d1f2019-09-09 17:25:08 +01004 * Copyright (c) 2019, Arm Limited (or its affiliates), All Rights Reserved.
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8/*
Jarno Lamsa18987a42019-04-24 15:40:43 +03009 * Copyright (c) 2014, Kenneth MacKay
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 * * Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions are met:
35 *
Andrzej Kurek0919b142020-07-06 15:28:59 -040036 * - Redistributions of source code must retain the above copyright notice,
37 * this list of conditions and the following disclaimer.
Jarno Lamsa18987a42019-04-24 15:40:43 +030038 *
Andrzej Kurek0919b142020-07-06 15:28:59 -040039 * - Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
Jarno Lamsa18987a42019-04-24 15:40:43 +030042 *
Andrzej Kurek0919b142020-07-06 15:28:59 -040043 * - Neither the name of Intel Corporation nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
Jarno Lamsa18987a42019-04-24 15:40:43 +030046 *
47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57 * POSSIBILITY OF SUCH DAMAGE.
58 */
59
Hanno Becker36ae7582019-07-23 15:52:35 +010060#if !defined(MBEDTLS_CONFIG_FILE)
61#include "mbedtls/config.h"
62#else
63#include MBEDTLS_CONFIG_FILE
64#endif
65
Jarno Lamsa18987a42019-04-24 15:40:43 +030066#include <tinycrypt/ecc.h>
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +010067#include "mbedtls/platform_util.h"
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +010068#include "mbedtls/sha256.h"
Jarno Lamsa18987a42019-04-24 15:40:43 +030069#include <string.h>
Shelly Liberman05beb9a2020-09-13 15:23:56 +030070#include "mbedtls/platform_util.h"
Jarno Lamsa18987a42019-04-24 15:40:43 +030071
Kevin Bracey1959c182020-07-16 21:03:19 +030072#ifdef __CC_ARM
73#pragma diag_suppress 667 // strict diagnostic: "asm" function is nonstandard
74#endif
75
76#if defined MBEDTLS_HAVE_ASM
77#ifndef asm
78#define asm __asm
79#endif
80#endif
81
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +010082/* Parameters for curve NIST P-256 aka secp256r1 */
83const uECC_word_t curve_p[NUM_ECC_WORDS] = {
84 BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
85 BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00),
86 BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
87 BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF)
88};
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +010089const uECC_word_t curve_n[NUM_ECC_WORDS] = {
90 BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3),
91 BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC),
92 BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
93 BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF)
94};
Manuel Pégourié-Gonnarda6115082019-11-21 10:29:14 +010095const uECC_word_t curve_G[2 * NUM_ECC_WORDS] = {
96 BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4),
97 BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77),
98 BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8),
99 BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B),
100 BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB),
101 BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B),
102 BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E),
103 BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F)
104};
Manuel Pégourié-Gonnardffd13992019-11-21 10:39:06 +0100105const uECC_word_t curve_b[NUM_ECC_WORDS] = {
106 BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B),
107 BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65),
108 BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3),
109 BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A)
110};
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100111
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100112static int uECC_update_param_sha256(mbedtls_sha256_context *ctx,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400113 const uECC_word_t val[NUM_ECC_WORDS])
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100114{
115 uint8_t bytes[NUM_ECC_BYTES];
116
117 uECC_vli_nativeToBytes(bytes, NUM_ECC_BYTES, val);
118 return mbedtls_sha256_update_ret(ctx, bytes, NUM_ECC_BYTES);
119}
120
121static int uECC_compute_param_sha256(unsigned char output[32])
122{
123 int ret = UECC_FAILURE;
124 mbedtls_sha256_context ctx;
125
126 mbedtls_sha256_init( &ctx );
127
128 if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) {
129 goto exit;
130 }
131
132 if (uECC_update_param_sha256(&ctx, curve_p) != 0 ||
Andrzej Kurek0919b142020-07-06 15:28:59 -0400133 uECC_update_param_sha256(&ctx, curve_n) != 0 ||
134 uECC_update_param_sha256(&ctx, curve_G) != 0 ||
135 uECC_update_param_sha256(&ctx, curve_G + NUM_ECC_WORDS) != 0 ||
136 uECC_update_param_sha256(&ctx, curve_b) != 0)
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100137 {
138 goto exit;
139 }
140
141 if (mbedtls_sha256_finish_ret(&ctx, output) != 0) {
142 goto exit;
143 }
144
145 ret = UECC_SUCCESS;
146
147exit:
148 mbedtls_sha256_free( &ctx );
149
150 return ret;
151}
152
153/*
154 * Check integrity of curve parameters.
155 * Return 0 if everything's OK, non-zero otherwise.
156 */
157static int uECC_check_curve_integrity(void)
158{
159 unsigned char computed[32];
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100160 static const unsigned char reference[32] = {
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100161 0x2d, 0xa1, 0xa4, 0x64, 0x45, 0x28, 0x0d, 0xe1,
162 0x93, 0xf9, 0x29, 0x2f, 0xac, 0x3e, 0xe2, 0x92,
163 0x76, 0x0a, 0xe2, 0xbc, 0xce, 0x2a, 0xa2, 0xc6,
164 0x38, 0xf2, 0x19, 0x1d, 0x76, 0x72, 0x93, 0x49,
165 };
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100166 unsigned char diff = 0;
167 unsigned char tmp1, tmp2;
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100168 volatile unsigned i;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100169
170 if (uECC_compute_param_sha256(computed) != UECC_SUCCESS) {
171 return UECC_FAILURE;
172 }
173
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100174 for (i = 0; i < 32; i++) {
175 /* make sure the order of volatile accesses is well-defined */
176 tmp1 = computed[i];
177 tmp2 = reference[i];
178 diff |= tmp1 ^ tmp2;
179 }
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100180
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100181 /* i should be 32 */
Arto Kinnunenac6d2262020-01-09 10:11:20 +0200182 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnarde1cb8842019-11-28 12:21:34 +0100183 diff |= (unsigned char) i ^ 32;
184
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +0100185 return diff;
186}
187
Jarno Lamsa18987a42019-04-24 15:40:43 +0300188/* IMPORTANT: Make sure a cryptographically-secure PRNG is set and the platform
189 * has access to enough entropy in order to feed the PRNG regularly. */
190#if default_RNG_defined
191static uECC_RNG_Function g_rng_function = &default_CSPRNG;
192#else
193static uECC_RNG_Function g_rng_function = 0;
194#endif
195
196void uECC_set_rng(uECC_RNG_Function rng_function)
197{
198 g_rng_function = rng_function;
199}
200
201uECC_RNG_Function uECC_get_rng(void)
202{
203 return g_rng_function;
204}
205
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +0100206int uECC_curve_private_key_size(void)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300207{
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +0100208 return BITS_TO_BYTES(NUM_ECC_BITS);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300209}
210
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +0100211int uECC_curve_public_key_size(void)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300212{
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +0100213 return 2 * NUM_ECC_BYTES;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300214}
215
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100216void uECC_vli_clear(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300217{
218 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100219 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300220 vli[i] = 0;
221 }
222}
223
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100224uECC_word_t uECC_vli_isZero(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300225{
226 uECC_word_t bits = 0;
227 wordcount_t i;
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100228 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300229 bits |= vli[i];
230 }
231 return (bits == 0);
232}
233
234uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit)
235{
236 return (vli[bit >> uECC_WORD_BITS_SHIFT] &
237 ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));
238}
239
240/* Counts the number of words in vli. */
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100241static wordcount_t vli_numDigits(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300242{
243
244 wordcount_t i;
245 /* Search from the end until we find a non-zero digit. We do it in reverse
246 * because we expect that most digits will be nonzero. */
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100247 for (i = NUM_ECC_WORDS - 1; i >= 0 && vli[i] == 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300248 }
249
250 return (i + 1);
251}
252
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100253bitcount_t uECC_vli_numBits(const uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300254{
255
256 uECC_word_t i;
257 uECC_word_t digit;
258
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100259 wordcount_t num_digits = vli_numDigits(vli);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300260 if (num_digits == 0) {
261 return 0;
262 }
263
264 digit = vli[num_digits - 1];
265 for (i = 0; digit; ++i) {
266 digit >>= 1;
267 }
268
269 return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);
270}
271
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100272void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300273{
274 wordcount_t i;
275
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100276 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300277 dest[i] = src[i];
278 }
279}
280
281cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100282 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300283{
284 wordcount_t i;
285
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100286 for (i = NUM_ECC_WORDS - 1; i >= 0; --i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300287 if (left[i] > right[i]) {
288 return 1;
289 } else if (left[i] < right[i]) {
290 return -1;
291 }
292 }
293 return 0;
294}
295
Manuel Pégourié-Gonnard2eca3d32019-11-04 14:33:09 +0100296uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300297{
298
299 uECC_word_t diff = 0;
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200300 uECC_word_t flow_monitor = 0;
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100301 uECC_word_t tmp1, tmp2;
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100302 volatile int i;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300303
Piotr Nowickif0ab6d62020-05-25 12:48:30 +0200304 /* Start from a random location and check the correct number of iterations */
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200305 int start_offset = mbedtls_platform_random_in_range(NUM_ECC_WORDS);
306
307 for (i = start_offset; i < NUM_ECC_WORDS; ++i) {
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100308 tmp1 = left[i];
309 tmp2 = right[i];
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200310 flow_monitor++;
Manuel Pégourié-Gonnard645896e2019-12-05 15:30:09 +0100311 diff |= (tmp1 ^ tmp2);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300312 }
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100313
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200314 for (i = 0; i < start_offset; ++i) {
315 tmp1 = left[i];
316 tmp2 = right[i];
317 flow_monitor++;
318 diff |= (tmp1 ^ tmp2);
319 }
Manuel Pégourié-Gonnard98e1fe02019-11-27 11:57:49 +0100320
Piotr Nowickif0ab6d62020-05-25 12:48:30 +0200321 /* Random delay to increase security */
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +0200322 mbedtls_platform_random_delay();
323
324 /* Return 0 only when diff is 0 and flow_counter is equal to NUM_ECC_WORDS */
325 return (diff | (flow_monitor ^ NUM_ECC_WORDS));
Jarno Lamsa18987a42019-04-24 15:40:43 +0300326}
327
328uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond)
329{
330 return (p_true*(cond)) | (p_false*(!cond));
331}
332
333/* Computes result = left - right, returning borrow, in constant time.
334 * Can modify in place. */
Kevin Bracey1959c182020-07-16 21:03:19 +0300335#if defined MBEDTLS_HAVE_ASM && defined __CC_ARM
336__asm uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
337 const uECC_word_t *right)
338{
339#if NUM_ECC_WORDS != 8
340#error adjust ARM assembly to handle NUM_ECC_WORDS != 8
341#endif
342#if defined __thumb__ && __TARGET_ARCH_THUMB < 4
343 PUSH {r4-r6,lr}
344 FRAME PUSH {r4-r6,lr}
345 LDMIA r1!,{r3,r4}
346 LDMIA r2!,{r5,r6}
347 SUBS r3,r5
348 SBCS r4,r6
349 STMIA r0!,{r3,r4}
350 LDMIA r1!,{r3,r4}
351 LDMIA r2!,{r5,r6}
352 SBCS r3,r5
353 SBCS r4,r6
354 STMIA r0!,{r3,r4}
355 LDMIA r1!,{r3,r4}
356 LDMIA r2!,{r5,r6}
357 SBCS r3,r5
358 SBCS r4,r6
359 STMIA r0!,{r3,r4}
360 LDMIA r1!,{r3,r4}
361 LDMIA r2!,{r5,r6}
362 SBCS r3,r5
363 SBCS r4,r6
364 STMIA r0!,{r3,r4}
365 SBCS r0,r0 // r0 := r0 - r0 - borrow = -borrow
366 RSBS r0,r0,#0 // r0 := borrow
367 POP {r4-r6,pc}
368#else
369 PUSH {r4-r8,lr}
370 FRAME PUSH {r4-r8,lr}
371 LDMIA r1!,{r3-r6}
372 LDMIA r2!,{r7,r8,r12,lr}
373 SUBS r3,r7
374 SBCS r4,r8
375 SBCS r5,r12
376 SBCS r6,lr
377 STMIA r0!,{r3-r6}
378 LDMIA r1!,{r3-r6}
379 LDMIA r2!,{r7,r8,r12,lr}
380 SBCS r3,r7
381 SBCS r4,r8
382 SBCS r5,r12
383 SBCS r6,lr
384 STMIA r0!,{r3-r6}
385 SBCS r0,r0 // r0 := r0 - r0 - borrow = -borrow
386 RSBS r0,r0,#0 // r0 := borrow
387 POP {r4-r8,pc}
388#endif
389}
390#else
Jarno Lamsa18987a42019-04-24 15:40:43 +0300391uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100392 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300393{
394 uECC_word_t borrow = 0;
395 wordcount_t i;
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100396 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300397 uECC_word_t diff = left[i] - right[i] - borrow;
398 uECC_word_t val = (diff > left[i]);
399 borrow = cond_set(val, borrow, (diff != left[i]));
400
401 result[i] = diff;
402 }
403 return borrow;
404}
Kevin Bracey1959c182020-07-16 21:03:19 +0300405#endif
Jarno Lamsa18987a42019-04-24 15:40:43 +0300406
407/* Computes result = left + right, returning carry, in constant time.
408 * Can modify in place. */
Kevin Bracey1959c182020-07-16 21:03:19 +0300409#if defined MBEDTLS_HAVE_ASM && defined __CC_ARM
410static __asm uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
411 const uECC_word_t *right)
412{
413#if NUM_ECC_WORDS != 8
414#error adjust ARM assembly to handle NUM_ECC_WORDS != 8
415#endif
416#if defined __thumb__ && __TARGET_ARCH_THUMB < 4
417 PUSH {r4-r6,lr}
418 FRAME PUSH {r4-r6,lr}
419 LDMIA r1!,{r3,r4}
420 LDMIA r2!,{r5,r6}
421 ADDS r3,r5
422 ADCS r4,r6
423 STMIA r0!,{r3,r4}
424 LDMIA r1!,{r3,r4}
425 LDMIA r2!,{r5,r6}
426 ADCS r3,r5
427 ADCS r4,r6
428 STMIA r0!,{r3,r4}
429 LDMIA r1!,{r3,r4}
430 LDMIA r2!,{r5,r6}
431 ADCS r3,r5
432 ADCS r4,r6
433 STMIA r0!,{r3,r4}
434 LDMIA r1!,{r3,r4}
435 LDMIA r2!,{r5,r6}
436 ADCS r3,r5
437 ADCS r4,r6
438 STMIA r0!,{r3,r4}
439 MOVS r0,#0 // does not affect C flag
440 ADCS r0,r0 // r0 := 0 + 0 + C = carry
441 POP {r4-r6,pc}
442#else
443 PUSH {r4-r8,lr}
444 FRAME PUSH {r4-r8,lr}
445 LDMIA r1!,{r3-r6}
446 LDMIA r2!,{r7,r8,r12,lr}
447 ADDS r3,r7
448 ADCS r4,r8
449 ADCS r5,r12
450 ADCS r6,lr
451 STMIA r0!,{r3-r6}
452 LDMIA r1!,{r3-r6}
453 LDMIA r2!,{r7,r8,r12,lr}
454 ADCS r3,r7
455 ADCS r4,r8
456 ADCS r5,r12
457 ADCS r6,lr
458 STMIA r0!,{r3-r6}
459 MOVS r0,#0 // does not affect C flag
460 ADCS r0,r0 // r0 := 0 + 0 + C = carry
461 POP {r4-r8,pc}
462#endif
463}
464#else
Jarno Lamsa18987a42019-04-24 15:40:43 +0300465static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100466 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300467{
468 uECC_word_t carry = 0;
469 wordcount_t i;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100470 for (i = 0; i < NUM_ECC_WORDS; ++i) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300471 uECC_word_t sum = left[i] + right[i] + carry;
472 uECC_word_t val = (sum < left[i]);
473 carry = cond_set(val, carry, (sum != left[i]));
474 result[i] = sum;
475 }
476 return carry;
477}
Kevin Bracey1959c182020-07-16 21:03:19 +0300478#endif
Jarno Lamsa18987a42019-04-24 15:40:43 +0300479
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +0100480cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300481{
482 uECC_word_t tmp[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100483 uECC_word_t neg = !!uECC_vli_sub(tmp, left, right);
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100484 uECC_word_t equal = uECC_vli_isZero(tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300485 return (!equal - 2 * neg);
486}
487
488/* Computes vli = vli >> 1. */
Kevin Bracey1959c182020-07-16 21:03:19 +0300489#if defined MBEDTLS_HAVE_ASM && defined __CC_ARM
490static __asm void uECC_vli_rshift1(uECC_word_t *vli)
491{
492#if defined __thumb__ && __TARGET_ARCH_THUMB < 4
493// RRX instruction is not available, so although we
494// can use C flag, it's not that effective. Does at
495// least save one working register, meaning we don't need stack
496 MOVS r3,#0 // initial carry = 0
497 MOVS r2,#__cpp(4 * (NUM_ECC_WORDS - 1))
49801 LDR r1,[r0,r2]
499 LSRS r1,r1,#1 // r2 = word >> 1
500 ORRS r1,r3 // merge in the previous carry
501 STR r1,[r0,r2]
502 ADCS r3,r3 // put C into bottom bit of r3
503 LSLS r3,r3,#31 // shift it up to the top ready for next word
504 SUBS r2,r2,#4
505 BPL %B01
506 BX lr
507#else
508#if NUM_ECC_WORDS != 8
509#error adjust ARM assembly to handle NUM_ECC_WORDS != 8
510#endif
511// Smooth multiword operation, lots of 32-bit instructions
512 ADDS r0,#32
513 LDMDB r0,{r1-r3,ip}
514 LSRS ip,ip,#1
515 RRXS r3,r3
516 RRXS r2,r2
517 RRXS r1,r1
518 STMDB r0!,{r1-r3,ip}
519 LDMDB r0,{r1-r3,ip}
520 RRXS ip,ip
521 RRXS r3,r3
522 RRXS r2,r2
523 RRX r1,r1
524 STMDB r0!,{r1-r3,ip}
525 BX lr
526#endif
527}
528#else
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100529static void uECC_vli_rshift1(uECC_word_t *vli)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300530{
531 uECC_word_t *end = vli;
532 uECC_word_t carry = 0;
533
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100534 vli += NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300535 while (vli-- > end) {
536 uECC_word_t temp = *vli;
537 *vli = (temp >> 1) | carry;
538 carry = temp << (uECC_WORD_BITS - 1);
539 }
540}
Kevin Bracey1959c182020-07-16 21:03:19 +0300541#endif
Jarno Lamsa18987a42019-04-24 15:40:43 +0300542
Manuel Pégourié-Gonnard86c4f812019-10-31 13:02:03 +0100543/* Compute a * b + r, where r is a double-word with high-order word r1 and
544 * low-order word r0, and store the result in the same double-word (r1, r0),
545 * with the carry bit stored in r2.
546 *
547 * (r2, r1, r0) = a * b + (r1, r0):
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200548 * [in] a, b: operands to be multiplied
549 * [in] r0, r1: low and high-order words of operand to add
550 * [out] r0, r1: low and high-order words of the result
551 * [out] r2: carry
552 */
Kevin Bracey1959c182020-07-16 21:03:19 +0300553#if defined MBEDTLS_HAVE_ASM && defined __CC_ARM
554static __asm void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0,
555 uECC_word_t *r1, uECC_word_t *r2)
556{
557#if defined __thumb__ && __TARGET_ARCH_THUMB < 4
558 IMPORT __ARM_common_ll_muluu
559 PRESERVE8
560 // have to save r4 to keep stack 8-byte aligned, but then
561 // may as well make use of it - helps a bit having it
562 PUSH {r2,r3,r4,lr}
563 FRAME SAVE {r4,lr},-8
564 FRAME ADDRESS sp,16
565 BL __ARM_common_ll_muluu
566 POP {r2,r3}
567 FRAME ADDRESS sp,8
568 LDR r4,[r2]
569 ADDS r4,r0
570 STR r4,[r2]
571 LDR r4,[r3]
572 ADCS r4,r1
573 STR r4,[r3]
574 LDR r3,[sp,#8]
575 LDR r4,[r3]
576 MOVS r0,#0
577 ADCS r4,r0
578 STR r4,[r3]
579 POP {r4,pc}
580#else
581 UMULL r0,r1,r0,r1
582 LDR ip,[r2]
583 ADDS r0,r0,ip
584 STR r0,[r2]
585 LDR r0,[r3]
586 ADCS r0,r1
587 STR r0,[r3]
588 LDR r3,[sp,#0]
589 LDR r0,[r3]
590 ADC r0,r0,#0
591 STR r0,[r3]
592 BX lr
593#endif
594
595}
596#else
Jarno Lamsa18987a42019-04-24 15:40:43 +0300597static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0,
598 uECC_word_t *r1, uECC_word_t *r2)
599{
600
601 uECC_dword_t p = (uECC_dword_t)a * b;
602 uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
603 r01 += p;
604 *r2 += (r01 < p);
605 *r1 = r01 >> uECC_WORD_BITS;
606 *r0 = (uECC_word_t)r01;
607
608}
Kevin Bracey1959c182020-07-16 21:03:19 +0300609#endif
Jarno Lamsa18987a42019-04-24 15:40:43 +0300610
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200611/* State for implementing random delays in uECC_vli_mult_rnd().
612 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100613 * The state is initialized by randomizing delays and setting i = 0.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200614 * Each call to uECC_vli_mult_rnd() uses one byte of delays and increments i.
615 *
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100616 * Randomized vli multiplication is used only for point operations
617 * (XYcZ_add_rnd() * and XYcZ_addC_rnd()) in scalar multiplication
618 * (ECCPoint_mult()). Those go in pair, and each pair does 14 calls to
619 * uECC_vli_mult_rnd() (6 in XYcZ_add_rnd() and 8 in XYcZ_addC_rnd(),
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100620 * indirectly through uECC_vli_modMult_rnd().
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100621 *
622 * Considering this, in order to minimize the number of calls to the RNG
623 * (which impact performance) while keeping the size of the structure low,
624 * make room for 14 randomized vli mults, which corresponds to one step in the
625 * scalar multiplication routine.
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200626 */
627typedef struct {
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100628 uint8_t i;
629 uint8_t delays[14];
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100630} ecc_wait_state_t;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200631
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100632/*
633 * Reset wait_state so that it's ready to be used.
634 */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100635void ecc_wait_state_reset(ecc_wait_state_t *ws)
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100636{
637 if (ws == NULL)
638 return;
639
640 ws->i = 0;
Shelly Liberman05beb9a2020-09-13 15:23:56 +0300641 mbedtls_platform_random_buf(ws->delays, sizeof(ws->delays));
Manuel Pégourié-Gonnardd4671162019-10-31 11:26:26 +0100642}
643
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200644/* Computes result = left * right. Result must be 2 * num_words long.
645 *
646 * As a counter-measure against horizontal attacks, add noise by performing
647 * a random number of extra computations performing random additional accesses
648 * to limbs of the input.
649 *
650 * Each of the two actual computation loops is surrounded by two
651 * similar-looking waiting loops, to make the beginning and end of the actual
652 * computation harder to spot.
653 *
654 * We add 4 waiting loops of between 0 and 3 calls to muladd() each. That
655 * makes an average of 6 extra calls. Compared to the main computation which
656 * makes 64 such calls, this represents an average performance degradation of
657 * less than 10%.
658 *
659 * Compared to the original uECC_vli_mult(), loose the num_words argument as we
660 * know it's always 8. This saves a bit of code size and execution speed.
661 */
662static void uECC_vli_mult_rnd(uECC_word_t *result, const uECC_word_t *left,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400663 const uECC_word_t *right, ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300664{
665
666 uECC_word_t r0 = 0;
667 uECC_word_t r1 = 0;
668 uECC_word_t r2 = 0;
669 wordcount_t i, k;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +0100670 const uint8_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200671
672 /* Fetch 8 bit worth of delay from the state; 0 if we have no state */
673 uint8_t delays = s ? s->delays[s->i++] : 0;
674 uECC_word_t rr0 = 0, rr1 = 0;
675 volatile uECC_word_t r;
676
677 /* Mimic start of next loop: k in [0, 3] */
678 k = 0 + (delays & 0x03);
679 delays >>= 2;
680 /* k = 0 -> i in [1, 0] -> 0 extra muladd;
681 * k = 3 -> i in [1, 3] -> 3 extra muladd */
Manuel Pégourié-Gonnardc8814862019-11-05 10:32:37 +0100682 for (i = 1; i <= k; ++i) {
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200683 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
684 }
685 r = rr0;
686 rr0 = rr1;
687 rr1 = r2;
688 r2 = 0;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300689
690 /* Compute each digit of result in sequence, maintaining the carries. */
691 for (k = 0; k < num_words; ++k) {
692
693 for (i = 0; i <= k; ++i) {
694 muladd(left[i], right[k - i], &r0, &r1, &r2);
695 }
696
697 result[k] = r0;
698 r0 = r1;
699 r1 = r2;
700 r2 = 0;
701 }
702
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200703 /* Mimic end of previous loop: k in [4, 7] */
704 k = 4 + (delays & 0x03);
705 delays >>= 2;
706 /* k = 4 -> i in [5, 4] -> 0 extra muladd;
707 * k = 7 -> i in [5, 7] -> 3 extra muladd */
708 for (i = 5; i <= k; ++i) {
709 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
710 }
711 r = rr0;
712 rr0 = rr1;
713 rr1 = r2;
714 r2 = 0;
715
716 /* Mimic start of next loop: k in [8, 11] */
717 k = 11 - (delays & 0x03);
718 delays >>= 2;
719 /* k = 8 -> i in [5, 7] -> 3 extra muladd;
720 * k = 11 -> i in [8, 7] -> 0 extra muladd */
721 for (i = (k + 5) - num_words; i < num_words; ++i) {
722 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
723 }
724 r = rr0;
725 rr0 = rr1;
726 rr1 = r2;
727 r2 = 0;
728
Jarno Lamsa18987a42019-04-24 15:40:43 +0300729 for (k = num_words; k < num_words * 2 - 1; ++k) {
730
731 for (i = (k + 1) - num_words; i < num_words; ++i) {
732 muladd(left[i], right[k - i], &r0, &r1, &r2);
733 }
734 result[k] = r0;
735 r0 = r1;
736 r1 = r2;
737 r2 = 0;
738 }
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200739
Jarno Lamsa18987a42019-04-24 15:40:43 +0300740 result[num_words * 2 - 1] = r0;
Manuel Pégourié-Gonnard14ab9c22019-10-22 09:49:53 +0200741
742 /* Mimic end of previous loop: k in [12, 15] */
743 k = 15 - (delays & 0x03);
744 delays >>= 2;
745 /* k = 12 -> i in [5, 7] -> 3 extra muladd;
746 * k = 15 -> i in [8, 7] -> 0 extra muladd */
747 for (i = (k + 1) - num_words; i < num_words; ++i) {
748 muladd(left[i], right[k - i], &rr0, &rr1, &r2);
749 }
750 r = rr0;
751 rr0 = rr1;
752 rr1 = r2;
753 r2 = 0;
754
755 /* avoid warning that r is set but not used */
756 (void) r;
757}
758
Jarno Lamsa18987a42019-04-24 15:40:43 +0300759void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400760 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300761{
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100762 uECC_word_t carry = uECC_vli_add(result, left, right);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100763 if (carry || uECC_vli_cmp_unsafe(mod, result) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300764 /* result > mod (result = mod + remainder), so subtract mod to get
765 * remainder. */
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100766 uECC_vli_sub(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300767 }
768}
769
770void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400771 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300772{
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100773 uECC_word_t l_borrow = uECC_vli_sub(result, left, right);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300774 if (l_borrow) {
775 /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
776 * we can get the correct result from result + mod (with overflow). */
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100777 uECC_vli_add(result, result, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300778 }
779}
780
781/* Computes result = product % mod, where product is 2N words long. */
782/* Currently only designed to work for curve_p or curve_n. */
783void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400784 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300785{
786 uECC_word_t mod_multiple[2 * NUM_ECC_WORDS];
787 uECC_word_t tmp[2 * NUM_ECC_WORDS];
788 uECC_word_t *v[2] = {tmp, product};
789 uECC_word_t index;
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100790 const wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300791
792 /* Shift mod so its highest set bit is at the maximum position. */
793 bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) -
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +0100794 uECC_vli_numBits(mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300795 wordcount_t word_shift = shift / uECC_WORD_BITS;
796 wordcount_t bit_shift = shift % uECC_WORD_BITS;
797 uECC_word_t carry = 0;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100798 uECC_vli_clear(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300799 if (bit_shift > 0) {
800 for(index = 0; index < (uECC_word_t)num_words; ++index) {
801 mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;
802 carry = mod[index] >> (uECC_WORD_BITS - bit_shift);
803 }
804 } else {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100805 uECC_vli_set(mod_multiple + word_shift, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300806 }
807
808 for (index = 1; shift >= 0; --shift) {
809 uECC_word_t borrow = 0;
810 wordcount_t i;
811 for (i = 0; i < num_words * 2; ++i) {
812 uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;
813 if (diff != v[index][i]) {
814 borrow = (diff > v[index][i]);
815 }
816 v[1 - index][i] = diff;
817 }
818 /* Swap the index if there was no borrow */
819 index = !(index ^ borrow);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100820 uECC_vli_rshift1(mod_multiple);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300821 mod_multiple[num_words - 1] |= mod_multiple[num_words] <<
Andrzej Kurek0919b142020-07-06 15:28:59 -0400822 (uECC_WORD_BITS - 1);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100823 uECC_vli_rshift1(mod_multiple + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300824 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100825 uECC_vli_set(result, v[index]);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300826}
827
828void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400829 const uECC_word_t *right, const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300830{
831 uECC_word_t product[2 * NUM_ECC_WORDS];
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +0100832 uECC_vli_mult_rnd(product, left, right, NULL);
Manuel Pégourié-Gonnard10349e42019-11-04 14:57:53 +0100833 uECC_vli_mmod(result, product, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300834}
835
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100836static void uECC_vli_modMult_rnd(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +0100837 const uECC_word_t *right, ecc_wait_state_t *s)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +0100838{
839 uECC_word_t product[2 * NUM_ECC_WORDS];
840 uECC_vli_mult_rnd(product, left, right, s);
841
842 vli_mmod_fast_secp256r1(result, product);
843}
844
Jarno Lamsa18987a42019-04-24 15:40:43 +0300845void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100846 const uECC_word_t *right)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300847{
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100848 uECC_vli_modMult_rnd(result, left, right, NULL);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300849}
850
Jarno Lamsa18987a42019-04-24 15:40:43 +0300851#define EVEN(vli) (!(vli[0] & 1))
852
853static void vli_modInv_update(uECC_word_t *uv,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400854 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300855{
856
857 uECC_word_t carry = 0;
858
859 if (!EVEN(uv)) {
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100860 carry = uECC_vli_add(uv, uv, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300861 }
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100862 uECC_vli_rshift1(uv);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300863 if (carry) {
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100864 uv[NUM_ECC_WORDS - 1] |= HIGH_BIT_SET;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300865 }
866}
867
868void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400869 const uECC_word_t *mod)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300870{
871 uECC_word_t a[NUM_ECC_WORDS], b[NUM_ECC_WORDS];
872 uECC_word_t u[NUM_ECC_WORDS], v[NUM_ECC_WORDS];
873 cmpresult_t cmpResult;
874
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100875 if (uECC_vli_isZero(input)) {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100876 uECC_vli_clear(result);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300877 return;
878 }
879
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100880 uECC_vli_set(a, input);
881 uECC_vli_set(b, mod);
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100882 uECC_vli_clear(u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300883 u[0] = 1;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +0100884 uECC_vli_clear(v);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100885 while ((cmpResult = uECC_vli_cmp_unsafe(a, b)) != 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300886 if (EVEN(a)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100887 uECC_vli_rshift1(a);
Andrzej Kurek0919b142020-07-06 15:28:59 -0400888 vli_modInv_update(u, mod);
889 } else if (EVEN(b)) {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100890 uECC_vli_rshift1(b);
Manuel Pégourié-Gonnard91353482019-11-04 15:04:20 +0100891 vli_modInv_update(v, mod);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300892 } else if (cmpResult > 0) {
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +0100893 uECC_vli_sub(a, a, b);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100894 uECC_vli_rshift1(a);
Manuel Pégourié-Gonnarda7521912019-11-04 14:31:35 +0100895 if (uECC_vli_cmp_unsafe(u, v) < 0) {
Andrzej Kurek0919b142020-07-06 15:28:59 -0400896 uECC_vli_add(u, u, mod);
897 }
898 uECC_vli_sub(u, u, v);
899 vli_modInv_update(u, mod);
900 } else {
901 uECC_vli_sub(b, b, a);
902 uECC_vli_rshift1(b);
903 if (uECC_vli_cmp_unsafe(v, u) < 0) {
904 uECC_vli_add(v, v, mod);
905 }
906 uECC_vli_sub(v, v, u);
907 vli_modInv_update(v, mod);
908 }
Jarno Lamsa18987a42019-04-24 15:40:43 +0300909 }
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100910 uECC_vli_set(result, u);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300911}
912
913/* ------ Point operations ------ */
914
915void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400916 uECC_word_t * Z1)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300917{
918 /* t1 = X, t2 = Y, t3 = Z */
919 uECC_word_t t4[NUM_ECC_WORDS];
920 uECC_word_t t5[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +0100921 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa18987a42019-04-24 15:40:43 +0300922
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +0100923 if (uECC_vli_isZero(Z1)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +0300924 return;
925 }
926
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100927 uECC_vli_modMult_fast(t4, Y1, Y1); /* t4 = y1^2 */
928 uECC_vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */
929 uECC_vli_modMult_fast(t4, t4, t4); /* t4 = y1^4 */
930 uECC_vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */
931 uECC_vli_modMult_fast(Z1, Z1, Z1); /* t3 = z1^2 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300932
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100933 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */
934 uECC_vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */
935 uECC_vli_modSub(Z1, X1, Z1, curve_p); /* t3 = x1 - z1^2 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100936 uECC_vli_modMult_fast(X1, X1, Z1); /* t1 = x1^2 - z1^4 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300937
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100938 uECC_vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */
939 uECC_vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300940 if (uECC_vli_testBit(X1, 0)) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100941 uECC_word_t l_carry = uECC_vli_add(X1, X1, curve_p);
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100942 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300943 X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
944 } else {
Manuel Pégourié-Gonnard5e3baf22019-11-04 14:46:10 +0100945 uECC_vli_rshift1(X1);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300946 }
947
948 /* t1 = 3/2*(x1^2 - z1^4) = B */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100949 uECC_vli_modMult_fast(Z1, X1, X1); /* t3 = B^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100950 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - A */
951 uECC_vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */
952 uECC_vli_modSub(t5, t5, Z1, curve_p); /* t5 = A - x3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100953 uECC_vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300954 /* t4 = B * (A - x3) - y1^4 = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100955 uECC_vli_modSub(t4, X1, t4, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300956
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100957 uECC_vli_set(X1, Z1);
958 uECC_vli_set(Z1, Y1);
959 uECC_vli_set(Y1, t4);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300960}
961
Manuel Pégourié-Gonnard1c6f7ea2019-11-21 09:18:29 +0100962/*
963 * @brief Computes x^3 + ax + b. result must not overlap x.
964 * @param result OUT -- x^3 + ax + b
965 * @param x IN -- value of x
966 * @param curve IN -- elliptic curve
967 */
968static void x_side_default(uECC_word_t *result,
Andrzej Kurek0919b142020-07-06 15:28:59 -0400969 const uECC_word_t *x)
Jarno Lamsa18987a42019-04-24 15:40:43 +0300970{
971 uECC_word_t _3[NUM_ECC_WORDS] = {3}; /* -a = 3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300972
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100973 uECC_vli_modMult_fast(result, x, x); /* r = x^2 */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +0100974 uECC_vli_modSub(result, result, _3, curve_p); /* r = x^2 - 3 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +0100975 uECC_vli_modMult_fast(result, result, x); /* r = x^3 - 3x */
Jarno Lamsa18987a42019-04-24 15:40:43 +0300976 /* r = x^3 - 3x + b: */
Manuel Pégourié-Gonnardffd13992019-11-21 10:39:06 +0100977 uECC_vli_modAdd(result, result, curve_b, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300978}
979
980void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int*product)
981{
982 unsigned int tmp[NUM_ECC_WORDS];
983 int carry;
984
985 /* t */
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +0100986 uECC_vli_set(result, product);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300987
988 /* s1 */
989 tmp[0] = tmp[1] = tmp[2] = 0;
990 tmp[3] = product[11];
991 tmp[4] = product[12];
992 tmp[5] = product[13];
993 tmp[6] = product[14];
994 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +0100995 carry = uECC_vli_add(tmp, tmp, tmp);
996 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +0300997
998 /* s2 */
999 tmp[3] = product[12];
1000 tmp[4] = product[13];
1001 tmp[5] = product[14];
1002 tmp[6] = product[15];
1003 tmp[7] = 0;
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +01001004 carry += uECC_vli_add(tmp, tmp, tmp);
1005 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001006
1007 /* s3 */
1008 tmp[0] = product[8];
1009 tmp[1] = product[9];
1010 tmp[2] = product[10];
1011 tmp[3] = tmp[4] = tmp[5] = 0;
1012 tmp[6] = product[14];
1013 tmp[7] = product[15];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +01001014 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001015
1016 /* s4 */
1017 tmp[0] = product[9];
1018 tmp[1] = product[10];
1019 tmp[2] = product[11];
1020 tmp[3] = product[13];
1021 tmp[4] = product[14];
1022 tmp[5] = product[15];
1023 tmp[6] = product[13];
1024 tmp[7] = product[8];
Manuel Pégourié-Gonnard02d9d212019-11-04 12:37:08 +01001025 carry += uECC_vli_add(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001026
1027 /* d1 */
1028 tmp[0] = product[11];
1029 tmp[1] = product[12];
1030 tmp[2] = product[13];
1031 tmp[3] = tmp[4] = tmp[5] = 0;
1032 tmp[6] = product[8];
1033 tmp[7] = product[10];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +01001034 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001035
1036 /* d2 */
1037 tmp[0] = product[12];
1038 tmp[1] = product[13];
1039 tmp[2] = product[14];
1040 tmp[3] = product[15];
1041 tmp[4] = tmp[5] = 0;
1042 tmp[6] = product[9];
1043 tmp[7] = product[11];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +01001044 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001045
1046 /* d3 */
1047 tmp[0] = product[13];
1048 tmp[1] = product[14];
1049 tmp[2] = product[15];
1050 tmp[3] = product[8];
1051 tmp[4] = product[9];
1052 tmp[5] = product[10];
1053 tmp[6] = 0;
1054 tmp[7] = product[12];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +01001055 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001056
1057 /* d4 */
1058 tmp[0] = product[14];
1059 tmp[1] = product[15];
1060 tmp[2] = 0;
1061 tmp[3] = product[9];
1062 tmp[4] = product[10];
1063 tmp[5] = product[11];
1064 tmp[6] = 0;
1065 tmp[7] = product[13];
Manuel Pégourié-Gonnard129b42e2019-11-04 14:41:45 +01001066 carry -= uECC_vli_sub(result, result, tmp);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001067
1068 if (carry < 0) {
1069 do {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001070 carry += uECC_vli_add(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001071 }
1072 while (carry < 0);
1073 } else {
Piotr Nowicki1a9d33e2020-05-20 22:10:14 +02001074 while (carry ||
Andrzej Kurek0919b142020-07-06 15:28:59 -04001075 uECC_vli_cmp_unsafe(curve_p, result) != 1) {
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001076 carry -= uECC_vli_sub(result, result, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001077 }
1078 }
1079}
1080
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001081uECC_word_t EccPoint_isZero(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001082{
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001083 return uECC_vli_isZero(point);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001084}
1085
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001086void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001087{
1088 uECC_word_t t1[NUM_ECC_WORDS];
1089
Andrzej Kurek0919b142020-07-06 15:28:59 -04001090 uECC_vli_modMult_fast(t1, Z, Z); /* z^2 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001091 uECC_vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */
1092 uECC_vli_modMult_fast(t1, t1, Z); /* z^3 */
1093 uECC_vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001094}
1095
1096/* P = (x1, y1) => 2P, (x2, y2) => P' */
1097static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1,
1098 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001099 const uECC_word_t * const initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001100{
1101 uECC_word_t z[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +03001102 if (initial_Z) {
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +01001103 uECC_vli_set(z, initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001104 } else {
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +01001105 uECC_vli_clear(z);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001106 z[0] = 1;
1107 }
1108
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +01001109 uECC_vli_set(X2, X1);
1110 uECC_vli_set(Y2, Y1);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001111
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001112 apply_z(X1, Y1, z);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001113 double_jacobian_default(X1, Y1, z);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001114 apply_z(X2, Y2, z);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001115}
1116
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001117static void XYcZ_add_rnd(uECC_word_t * X1, uECC_word_t * Y1,
1118 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +01001119 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001120{
1121 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
1122 uECC_word_t t5[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +03001123
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001124 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +01001125 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001126 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
1127 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001128 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +01001129 uECC_vli_modMult_rnd(t5, Y2, Y2, s); /* t5 = (y2 - y1)^2 = D */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001130
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001131 uECC_vli_modSub(t5, t5, X1, curve_p); /* t5 = D - B */
1132 uECC_vli_modSub(t5, t5, X2, curve_p); /* t5 = D - B - C = x3 */
1133 uECC_vli_modSub(X2, X2, X1, curve_p); /* t3 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001134 uECC_vli_modMult_rnd(Y1, Y1, X2, s); /* t2 = y1*(C - B) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001135 uECC_vli_modSub(X2, X1, t5, curve_p); /* t3 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001136 uECC_vli_modMult_rnd(Y2, Y2, X2, s); /* t4 = (y2 - y1)*(B - x3) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001137 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001138
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +01001139 uECC_vli_set(X2, t5);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001140}
1141
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001142void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1,
Andrzej Kurek0919b142020-07-06 15:28:59 -04001143 uECC_word_t * X2, uECC_word_t * Y2)
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001144{
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001145 XYcZ_add_rnd(X1, Y1, X2, Y2, NULL);
1146}
1147
Jarno Lamsa18987a42019-04-24 15:40:43 +03001148/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
1149 Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
1150 or P => P - Q, Q => P + Q
1151 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001152static void XYcZ_addC_rnd(uECC_word_t * X1, uECC_word_t * Y1,
1153 uECC_word_t * X2, uECC_word_t * Y2,
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +01001154 ecc_wait_state_t *s)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001155{
1156 /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
1157 uECC_word_t t5[NUM_ECC_WORDS];
1158 uECC_word_t t6[NUM_ECC_WORDS];
1159 uECC_word_t t7[NUM_ECC_WORDS];
Jarno Lamsa18987a42019-04-24 15:40:43 +03001160
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001161 uECC_vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +01001162 uECC_vli_modMult_rnd(t5, t5, t5, s); /* t5 = (x2 - x1)^2 = A */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001163 uECC_vli_modMult_rnd(X1, X1, t5, s); /* t1 = x1*A = B */
1164 uECC_vli_modMult_rnd(X2, X2, t5, s); /* t3 = x2*A = C */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001165 uECC_vli_modAdd(t5, Y2, Y1, curve_p); /* t5 = y2 + y1 */
1166 uECC_vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001167
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001168 uECC_vli_modSub(t6, X2, X1, curve_p); /* t6 = C - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001169 uECC_vli_modMult_rnd(Y1, Y1, t6, s); /* t2 = y1 * (C - B) = E */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001170 uECC_vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +01001171 uECC_vli_modMult_rnd(X2, Y2, Y2, s); /* t3 = (y2 - y1)^2 = D */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001172 uECC_vli_modSub(X2, X2, t6, curve_p); /* t3 = D - (B + C) = x3 */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001173
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001174 uECC_vli_modSub(t7, X1, X2, curve_p); /* t7 = B - x3 */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001175 uECC_vli_modMult_rnd(Y2, Y2, t7, s); /* t4 = (y2 - y1)*(B - x3) */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001176 /* t4 = (y2 - y1)*(B - x3) - E = y3: */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001177 uECC_vli_modSub(Y2, Y2, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001178
Manuel Pégourié-Gonnardc78d86b2019-11-04 10:18:42 +01001179 uECC_vli_modMult_rnd(t7, t5, t5, s); /* t7 = (y2 + y1)^2 = F */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001180 uECC_vli_modSub(t7, t7, t6, curve_p); /* t7 = F - (B + C) = x3' */
1181 uECC_vli_modSub(t6, t7, X1, curve_p); /* t6 = x3' - B */
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001182 uECC_vli_modMult_rnd(t6, t6, t5, s); /* t6 = (y2+y1)*(x3' - B) */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001183 /* t2 = (y2+y1)*(x3' - B) - E = y3': */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001184 uECC_vli_modSub(Y1, t6, Y1, curve_p);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001185
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +01001186 uECC_vli_set(X1, t7);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001187}
1188
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +01001189static void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point,
Jarno Lamsa18987a42019-04-24 15:40:43 +03001190 const uECC_word_t * scalar,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001191 const uECC_word_t * initial_Z)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001192{
1193 /* R0 and R1 */
1194 uECC_word_t Rx[2][NUM_ECC_WORDS];
1195 uECC_word_t Ry[2][NUM_ECC_WORDS];
1196 uECC_word_t z[NUM_ECC_WORDS];
1197 bitcount_t i;
1198 uECC_word_t nb;
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001199 const wordcount_t num_words = NUM_ECC_WORDS;
1200 const bitcount_t num_bits = NUM_ECC_BITS + 1; /* from regularize_k */
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +01001201 ecc_wait_state_t wait_state;
1202 ecc_wait_state_t * const ws = g_rng_function ? &wait_state : NULL;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001203
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +01001204 uECC_vli_set(Rx[1], point);
1205 uECC_vli_set(Ry[1], point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001206
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001207 XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001208
1209 for (i = num_bits - 2; i > 0; --i) {
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +01001210 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001211 nb = !uECC_vli_testBit(scalar, i);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001212 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
1213 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001214 }
1215
Manuel Pégourié-Gonnardd5e503e2019-10-31 12:53:44 +01001216 ecc_wait_state_reset(ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001217 nb = !uECC_vli_testBit(scalar, 0);
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001218 XYcZ_addC_rnd(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], ws);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001219
1220 /* Find final 1/Z value. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001221 uECC_vli_modSub(z, Rx[1], Rx[0], curve_p); /* X1 - X0 */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001222 uECC_vli_modMult_fast(z, z, Ry[1 - nb]); /* Yb * (X1 - X0) */
1223 uECC_vli_modMult_fast(z, z, point); /* xP * Yb * (X1 - X0) */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001224 uECC_vli_modInv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0))*/
Jarno Lamsa18987a42019-04-24 15:40:43 +03001225 /* yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001226 uECC_vli_modMult_fast(z, z, point + num_words);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001227 /* Xb * yP / (xP * Yb * (X1 - X0)) */
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001228 uECC_vli_modMult_fast(z, z, Rx[1 - nb]);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001229 /* End 1/Z calculation */
1230
Manuel Pégourié-Gonnard938f53f2019-10-29 11:23:43 +01001231 XYcZ_add_rnd(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], ws);
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001232 apply_z(Rx[0], Ry[0], z);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001233
Manuel Pégourié-Gonnardcbbb0f02019-11-04 13:02:04 +01001234 uECC_vli_set(result, Rx[0]);
1235 uECC_vli_set(result + num_words, Ry[0]);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001236}
1237
Manuel Pégourié-Gonnard27926d62019-11-04 11:26:46 +01001238static uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0,
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001239 uECC_word_t *k1)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001240{
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001241 bitcount_t num_n_bits = NUM_ECC_BITS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001242
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001243 uECC_word_t carry = uECC_vli_add(k0, k, curve_n) ||
Andrzej Kurek0919b142020-07-06 15:28:59 -04001244 uECC_vli_testBit(k0, num_n_bits);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001245
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001246 uECC_vli_add(k1, k0, curve_n);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001247
1248 return carry;
1249}
1250
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001251int EccPoint_mult_safer(uECC_word_t * result, const uECC_word_t * point,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001252 const uECC_word_t * scalar)
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001253{
1254 uECC_word_t tmp[NUM_ECC_WORDS];
1255 uECC_word_t s[NUM_ECC_WORDS];
1256 uECC_word_t *k2[2] = {tmp, s};
Manuel Pégourié-Gonnard78a7e352019-11-04 12:31:06 +01001257 wordcount_t num_words = NUM_ECC_WORDS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001258 uECC_word_t carry;
1259 uECC_word_t *initial_Z = 0;
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001260 int r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001261 volatile int problem;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001262
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001263 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001264 problem = -1;
1265 problem = uECC_check_curve_integrity();
1266 if (problem != 0) {
1267 return UECC_FAULT_DETECTED;
1268 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001269 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001270 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001271 return UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001272 }
1273
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001274 /* Protects against invalid curve attacks */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001275 problem = -1;
1276 problem = uECC_valid_point(point);
1277 if (problem != 0) {
1278 /* invalid input, can happen without fault */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001279 return UECC_FAILURE;
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001280 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001281 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001282 if (problem != 0) {
1283 /* failure on second check means fault, though */
1284 return UECC_FAULT_DETECTED;
1285 }
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001286
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001287 /* Regularize the bitcount for the private key so that attackers cannot use a
1288 * side channel attack to learn the number of leading zeros. */
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001289 carry = regularize_k(scalar, tmp, s);
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001290
1291 /* If an RNG function was specified, get a random initial Z value to
Andrzej Kurek0919b142020-07-06 15:28:59 -04001292 * protect against side-channel attacks such as Template SPA */
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001293 if (g_rng_function) {
Andrzej Kurek3a0df032020-06-12 06:32:13 -04001294 if (uECC_generate_random_int(k2[carry], curve_p, num_words) != UECC_SUCCESS) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001295 r = UECC_FAILURE;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001296 goto clear_and_out;
1297 }
1298 initial_Z = k2[carry];
1299 }
1300
Manuel Pégourié-Gonnard3645ac92019-11-04 11:39:18 +01001301 EccPoint_mult(result, point, k2[!carry], initial_Z);
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001302
Manuel Pégourié-Gonnarde7143322019-11-15 10:47:45 +01001303 /* Protect against fault injections that would make the resulting
1304 * point not lie on the intended curve */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001305 problem = -1;
1306 problem = uECC_valid_point(result);
1307 if (problem != 0) {
1308 r = UECC_FAULT_DETECTED;
1309 goto clear_and_out;
1310 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001311 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001312 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001313 r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard41ab8cb2019-11-14 11:59:09 +01001314 goto clear_and_out;
1315 }
1316
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001317 /* Protect against faults modifying curve paremeters in flash */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001318 problem = -1;
1319 problem = uECC_check_curve_integrity();
1320 if (problem != 0) {
1321 r = UECC_FAULT_DETECTED;
1322 goto clear_and_out;
1323 }
Arto Kinnunenac6d2262020-01-09 10:11:20 +02001324 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001325 if (problem != 0) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001326 r = UECC_FAULT_DETECTED;
Manuel Pégourié-Gonnard2b909612019-11-21 13:37:00 +01001327 goto clear_and_out;
1328 }
1329
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001330 r = UECC_SUCCESS;
Manuel Pégourié-Gonnardef238282019-11-04 11:19:30 +01001331
1332clear_and_out:
1333 /* erasing temporary buffer used to store secret: */
1334 mbedtls_platform_zeroize(k2, sizeof(k2));
1335 mbedtls_platform_zeroize(tmp, sizeof(tmp));
1336 mbedtls_platform_zeroize(s, sizeof(s));
1337
1338 return r;
1339}
1340
Jarno Lamsa18987a42019-04-24 15:40:43 +03001341uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001342 uECC_word_t *private_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001343{
Manuel Pégourié-Gonnard1a533712019-11-21 12:00:43 +01001344 return EccPoint_mult_safer(result, curve_G, private_key);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001345}
1346
1347/* Converts an integer in uECC native format to big-endian bytes. */
1348void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
Andrzej Kurek0919b142020-07-06 15:28:59 -04001349 const unsigned int *native)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001350{
1351 wordcount_t i;
1352 for (i = 0; i < num_bytes; ++i) {
1353 unsigned b = num_bytes - 1 - i;
1354 bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE));
1355 }
1356}
1357
1358/* Converts big-endian bytes to an integer in uECC native format. */
1359void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes,
Andrzej Kurek0919b142020-07-06 15:28:59 -04001360 int num_bytes)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001361{
1362 wordcount_t i;
Manuel Pégourié-Gonnard94e48492019-11-04 12:47:28 +01001363 uECC_vli_clear(native);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001364 for (i = 0; i < num_bytes; ++i) {
1365 unsigned b = num_bytes - 1 - i;
1366 native[b / uECC_WORD_SIZE] |=
1367 (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE));
1368 }
1369}
1370
1371int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
Andrzej Kurek0919b142020-07-06 15:28:59 -04001372 wordcount_t num_words)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001373{
1374 uECC_word_t mask = (uECC_word_t)-1;
1375 uECC_word_t tries;
Manuel Pégourié-Gonnard2bf5a122019-11-04 12:56:59 +01001376 bitcount_t num_bits = uECC_vli_numBits(top);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001377
1378 if (!g_rng_function) {
Andrzej Kurek3a0df032020-06-12 06:32:13 -04001379 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001380 }
1381
1382 for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
Andrzej Kurek090365f2020-06-08 11:00:51 -04001383 if (g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE) != num_words * uECC_WORD_SIZE) {
Andrzej Kurek0919b142020-07-06 15:28:59 -04001384 return UECC_FAILURE;
1385 }
Jarno Lamsa18987a42019-04-24 15:40:43 +03001386 random[num_words - 1] &=
Andrzej Kurek0919b142020-07-06 15:28:59 -04001387 mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits));
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001388 if (!uECC_vli_isZero(random) &&
Manuel Pégourié-Gonnard2cb3eea2019-11-04 14:43:35 +01001389 uECC_vli_cmp(top, random) == 1) {
Andrzej Kurek3a0df032020-06-12 06:32:13 -04001390 return UECC_SUCCESS;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001391 }
1392 }
Andrzej Kurek3a0df032020-06-12 06:32:13 -04001393 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001394}
1395
1396
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001397int uECC_valid_point(const uECC_word_t *point)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001398{
1399 uECC_word_t tmp1[NUM_ECC_WORDS];
1400 uECC_word_t tmp2[NUM_ECC_WORDS];
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001401 wordcount_t num_words = NUM_ECC_WORDS;
Jarno Lamsa83d78812019-12-04 14:40:57 +02001402 volatile uECC_word_t diff = 0xffffffff;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001403
1404 /* The point at infinity is invalid. */
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001405 if (EccPoint_isZero(point)) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001406 return -1;
1407 }
1408
1409 /* x and y must be smaller than p. */
Manuel Pégourié-Gonnard4d8777c2019-11-21 10:02:58 +01001410 if (uECC_vli_cmp_unsafe(curve_p, point) != 1 ||
1411 uECC_vli_cmp_unsafe(curve_p, point + num_words) != 1) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001412 return -2;
1413 }
1414
Manuel Pégourié-Gonnardc3ec14c2019-11-04 12:12:00 +01001415 uECC_vli_modMult_fast(tmp1, point + num_words, point + num_words);
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001416 x_side_default(tmp2, point); /* tmp2 = x^3 + ax + b */
Jarno Lamsa18987a42019-04-24 15:40:43 +03001417
1418 /* Make sure that y^2 == x^3 + ax + b */
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001419 diff = uECC_vli_equal(tmp1, tmp2);
1420 if (diff == 0) {
Andrzej Kurek0919b142020-07-06 15:28:59 -04001421 mbedtls_platform_random_delay();
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001422 if (diff == 0) {
1423 return 0;
1424 }
1425 }
Jarno Lamsa18987a42019-04-24 15:40:43 +03001426
Manuel Pégourié-Gonnard5c3066a2019-11-27 12:27:48 +01001427 return -3;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001428}
1429
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001430int uECC_valid_public_key(const uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001431{
1432
1433 uECC_word_t _public[NUM_ECC_WORDS * 2];
1434
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001435 uECC_vli_bytesToNative(_public, public_key, NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001436 uECC_vli_bytesToNative(
Manuel Pégourié-Gonnard17659332019-11-21 09:27:38 +01001437 _public + NUM_ECC_WORDS,
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001438 public_key + NUM_ECC_BYTES,
1439 NUM_ECC_BYTES);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001440
Manuel Pégourié-Gonnarda6115082019-11-21 10:29:14 +01001441 if (memcmp(_public, curve_G, NUM_ECC_WORDS * 2) == 0) {
Jarno Lamsa18987a42019-04-24 15:40:43 +03001442 return -4;
1443 }
1444
Manuel Pégourié-Gonnardbe5f8332019-11-21 11:02:38 +01001445 return uECC_valid_point(_public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001446}
1447
Andrzej Kurek0919b142020-07-06 15:28:59 -04001448int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key)
Jarno Lamsa18987a42019-04-24 15:40:43 +03001449{
Andrzej Kurekfd56f402020-05-25 11:52:05 -04001450 int ret = UECC_FAULT_DETECTED;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001451 uECC_word_t _private[NUM_ECC_WORDS];
1452 uECC_word_t _public[NUM_ECC_WORDS * 2];
1453
1454 uECC_vli_bytesToNative(
1455 _private,
1456 private_key,
Manuel Pégourié-Gonnard30833f22019-11-21 09:46:52 +01001457 BITS_TO_BYTES(NUM_ECC_BITS));
Jarno Lamsa18987a42019-04-24 15:40:43 +03001458
1459 /* Make sure the private key is in the range [1, n-1]. */
Manuel Pégourié-Gonnardf3899fc2019-11-04 12:44:43 +01001460 if (uECC_vli_isZero(_private)) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001461 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001462 }
1463
Manuel Pégourié-Gonnard356d8592019-11-21 10:23:05 +01001464 if (uECC_vli_cmp(curve_n, _private) != 1) {
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001465 return UECC_FAILURE;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001466 }
1467
1468 /* Compute public key. */
Manuel Pégourié-Gonnard9d6a5352019-11-25 13:06:05 +01001469 ret = EccPoint_compute_public_key(_public, _private);
1470 if (ret != UECC_SUCCESS) {
1471 return ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001472 }
1473
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001474 uECC_vli_nativeToBytes(public_key, NUM_ECC_BYTES, _public);
Jarno Lamsa18987a42019-04-24 15:40:43 +03001475 uECC_vli_nativeToBytes(
1476 public_key +
Manuel Pégourié-Gonnard72c17642019-11-21 09:34:09 +01001477 NUM_ECC_BYTES, NUM_ECC_BYTES, _public + NUM_ECC_WORDS);
Andrzej Kurekcf3e35c2020-07-15 22:32:08 -04001478
Andrzej Kurekfd56f402020-05-25 11:52:05 -04001479 return ret;
Jarno Lamsa18987a42019-04-24 15:40:43 +03001480}