Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
cx_eddsa.c
Go to the documentation of this file.
1
2/*******************************************************************************
3 * Ledger Nano S - Secure firmware
4 * (c) 2022 Ledger
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 ********************************************************************************/
18
19#ifdef HAVE_ECC_TWISTED_EDWARDS
20
21#include "cx_hash.h"
22#include "cx_ecfp.h"
23#include "cx_eddsa.h"
24#include "cx_selftests.h"
25#include "cx_utils.h"
26#include "cx_ram.h"
27
28#include <string.h>
29
30#define EDDSA_ED448_DOMAIN_LEN (57)
31
32static void cx_encode_int(uint8_t *v, int len)
33{
34 uint8_t t;
35 int i, j;
36 i = 0;
37 j = len - 1;
38 len = len / 2;
39 while (len--) {
40 t = v[i];
41 v[i] = v[j];
42 v[j] = t;
43 i++;
44 j--;
45 }
46}
47
48#define cx_decode_int(v, l) cx_encode_int(v, l)
49
50int cx_decode_coord(uint8_t *coord, int len)
51{
52 int sign;
53 cx_encode_int(coord, len); // little endian
54 sign = coord[0] & 0x80; // x_0
55 coord[0] &= 0x7F; // y-coordinate
56 return sign;
57}
58
59void cx_encode_coord(uint8_t *coord, int len, int sign)
60{
61 coord[0] |= sign ? 0x80 : 0x00;
62 cx_encode_int(coord, len);
63}
64
65/* ----------------------------------------------------------------------- */
66/* */
67/* ----------------------------------------------------------------------- */
68cx_err_t cx_eddsa_get_public_key_internal(const cx_ecfp_private_key_t *pv_key,
69 cx_md_t hashID,
70 cx_ecfp_public_key_t *pu_key,
71 uint8_t *a,
72 size_t a_len,
73 uint8_t *h,
74 size_t h_len,
75 uint8_t *scal /*tmp*/)
76{
77 size_t size;
78 cx_err_t error;
79
80 CX_CHECK(cx_ecdomain_parameters_length(pv_key->curve, &size));
81
82 if (!CX_CURVE_RANGE(pv_key->curve, TWISTED_EDWARDS)) {
83 return CX_INVALID_PARAMETER;
84 }
85 if (!((pv_key->d_len == size) || (pv_key->d_len == (2 * size)))) {
86 return CX_INVALID_PARAMETER;
87 }
88 if (!(((a == NULL) && (a_len == 0)) || ((a_len) && (a_len >= size)))) {
89 return CX_INVALID_PARAMETER;
90 }
91 if (!(((h == NULL) && (h_len == 0)) || ((h_len) && (h_len >= size)))) {
92 return CX_INVALID_PARAMETER;
93 }
94
95 switch (hashID) {
96#if defined(HAVE_SHA512)
97 case CX_SHA512:
98#endif // HAVE_SHA512
99
100#if defined(HAVE_SHA3)
101 case CX_SHAKE256:
102 case CX_KECCAK:
103 case CX_SHA3:
104#endif // HAVE_SHA3
105
106#if defined(HAVE_BLAKE2)
107 case CX_BLAKE2B:
108 if (cx_hash_init_ex(&G_cx.hash_ctx, hashID, size * 2) != CX_OK) {
109 return CX_INVALID_PARAMETER;
110 }
111 break;
112#endif // HAVE_BLAKE2
113
114 default:
115 return CX_INVALID_PARAMETER;
116 }
117
118 if (pv_key->d_len == size) {
119 /* 1. Hash the 32/57-byte private key using SHA-512/shak256-114, storing the digest in
120 * a 32/114 bytes large buffer, denoted h. Only the lower [CME: first] 32/57 bytes are
121 * used for generating the public key.
122 */
123 CX_CHECK(cx_hash_update(&G_cx.hash_ctx, pv_key->d, pv_key->d_len));
124 CX_CHECK(cx_hash_final(&G_cx.hash_ctx, scal));
125 cx_hash_destroy(&G_cx.hash_ctx);
126 if (pv_key->curve == CX_CURVE_Ed25519) {
127 /* 2. Prune the buffer: The lowest 3 bits of the first octet are
128 * cleared, the highest bit of the last octet is cleared, and the
129 * second highest bit of the last octet is set.
130 */
131 scal[0] &= 0xF8;
132 scal[31] = (scal[31] & 0x7F) | 0x40;
133 }
134 else /* CX_CURVE_Ed448 */ {
135 /* 2. Prune the buffer: The two least significant bits of the first
136 * octet are cleared, all eight bits the last octet are cleared, and
137 * the highest bit of the second to last octet is set.
138 */
139 scal[0] &= 0xFC;
140 scal[56] = 0;
141 scal[55] |= 0x80;
142 }
143 }
144 else {
145 memmove(scal, pv_key->d, pv_key->d_len);
146 }
147
148 /* 3. Interpret the buffer as the little-endian integer, forming a
149 * secret scalar a. Perform a fixed-base scalar multiplication
150 * [a]B.
151 */
152 cx_decode_int(scal, size);
153 if (a) {
154 memmove(a, scal, size);
155 }
156 if (h) {
157 memmove(h, scal + size, size);
158 }
159 if (pu_key) {
160 cx_ecpoint_t W;
161 CX_CHECK(cx_ecpoint_alloc(&W, pv_key->curve));
162 CX_CHECK(cx_ecdomain_generator_bn(pv_key->curve, &W));
163 CX_CHECK(cx_ecpoint_rnd_scalarmul(&W, scal, size));
164 pu_key->curve = pv_key->curve;
165 pu_key->W_len = 1 + 2 * size;
166 pu_key->W[0] = 0x04;
167 CX_CHECK(cx_ecpoint_export(&W, pu_key->W + 1, size, pu_key->W + 1 + size, size));
168 CX_CHECK(cx_ecpoint_destroy(&W));
169 }
170
171end:
172 return error;
173}
174
175cx_err_t cx_eddsa_get_public_key_no_throw(const cx_ecfp_private_key_t *pv_key,
176 cx_md_t hashID,
177 cx_ecfp_public_key_t *pu_key,
178 uint8_t *a,
179 size_t a_len,
180 uint8_t *h,
181 size_t h_len)
182{
183 uint8_t scal[EDDSA_ED448_DOMAIN_LEN * 2];
184 size_t size;
185 cx_err_t error;
186
187 CX_CHECK(cx_ecdomain_parameters_length(pv_key->curve, &size));
188 CX_CHECK(cx_bn_lock(size, 0));
189 CX_CHECK(cx_eddsa_get_public_key_internal(pv_key, hashID, pu_key, a, a_len, h, h_len, scal));
190
191end:
192 cx_bn_unlock();
193 return error;
194}
195
196#ifdef HAVE_EDDSA
197
198static uint8_t const C_cx_siged448[] = {'S', 'i', 'g', 'E', 'd', '4', '4', '8'};
199
200static cx_err_t cx_eddsa_check_params(cx_curve_t curve, size_t domain_len, cx_md_t hash_id)
201{
202 if (!CX_CURVE_RANGE(curve, TWISTED_EDWARDS)) {
203 return CX_INVALID_PARAMETER;
204 }
205
206 // The hash digest must be 2 * domain_len bytes
207 // Typically SHA512 for Ed25519 and SHAKE-256
208 // with 114 bytes for Ed448
209 switch (hash_id) {
210#if (defined(HAVE_SHA512) || defined(HAVE_SHA3))
211#if defined(HAVE_SHA512)
212 case CX_SHA512:
213#endif // HAVE_SHA512
214
215#if defined(HAVE_SHA3)
216 case CX_KECCAK:
217 case CX_SHA3:
218#endif // HAVE_SHA3
219 if (domain_len * 2 != 512 / 8) {
220 return INVALID_PARAMETER;
221 }
222 break;
223#endif // (defined(HAVE_SHA512) || defined(HAVE_SHA3))
224
225#if (defined(HAVE_SHA3) || defined(HAVE_BLAKE2))
226#if defined(HAVE_SHA3)
227 case CX_SHAKE256:
228#endif // HAVE_SHA3
229
230#if defined(HAVE_BLAKE2)
231 case CX_BLAKE2B:
232#endif // HAVE_BLAKE2
233 break;
234#endif // (defined(HAVE_SHA3) || defined(HAVE_BLAKE2))
235
236 default:
237 return INVALID_PARAMETER;
238 }
239
240 return CX_OK;
241}
242
243/* ----------------------------------------------------------------------- */
244/* */
245/* ----------------------------------------------------------------------- */
246
247cx_err_t cx_eddsa_sign_init_first_hash(cx_hash_t *hash_context,
248 const cx_ecfp_private_key_t *private_key,
249 cx_md_t hash_id)
250{
251 size_t domain_len, hash_len;
252 cx_err_t error;
253 uint8_t prefix[EDDSA_ED448_DOMAIN_LEN];
254 uint8_t private_hash[EDDSA_ED448_DOMAIN_LEN * 2];
255
256 CX_CHECK(cx_ecdomain_parameters_length(private_key->curve, &domain_len));
257 CX_CHECK(cx_eddsa_check_params(private_key->curve, domain_len, hash_id));
258
259 if (!((private_key->d_len == domain_len) || (private_key->d_len == 2 * domain_len))) {
260 return CX_INVALID_PARAMETER;
261 }
262
263 hash_len = 2 * domain_len;
264
265 // retrieve the prefix from private key hash
266 CX_CHECK(cx_eddsa_get_public_key_internal(
267 private_key, hash_id, NULL, NULL, 0, prefix, sizeof(prefix), private_hash));
268
269 CX_CHECK(cx_hash_init_ex(hash_context, hash_id, hash_len));
270
271 // Hash dom4 for Ed448
272 if (private_key->curve == CX_CURVE_Ed448) {
273 CX_CHECK(cx_hash_update(hash_context, C_cx_siged448, sizeof(C_cx_siged448)));
274 private_hash[0] = 0;
275 private_hash[1] = 0;
276 CX_CHECK(cx_hash_update(hash_context, private_hash, 2));
277 }
278 // Hash the prefix
279 CX_CHECK(cx_hash_update(hash_context, prefix, domain_len));
280
281end:
282 return error;
283}
284
285cx_err_t cx_eddsa_sign_init_second_hash(cx_hash_t *hash_context,
286 const cx_ecfp_private_key_t *private_key,
287 cx_md_t hash_id,
288 uint8_t *hash,
289 size_t hash_len,
290 uint8_t *sig,
291 size_t sig_len)
292{
293 size_t domain_len;
294 cx_bn_t bn_h, bn_r, bn_n;
295 cx_ecpoint_t Q;
296 cx_err_t error;
297 uint8_t secret_scalar[EDDSA_ED448_DOMAIN_LEN];
298 uint8_t private_hash[EDDSA_ED448_DOMAIN_LEN * 2];
299 uint32_t sign;
300
301 CX_CHECK(cx_ecdomain_parameters_length(private_key->curve, &domain_len));
302
303 if (sig_len < 2 * domain_len) {
304 return CX_INVALID_PARAMETER;
305 }
306
307 // Retrieve the secret scalar from the private key hash
308 CX_CHECK(cx_eddsa_get_public_key_internal(
309 private_key, hash_id, NULL, secret_scalar, sizeof(secret_scalar), NULL, 0, private_hash));
310 // Encode the digest as little-endian
311 cx_encode_int(hash, hash_len);
312
313 CX_CHECK(cx_bn_lock(domain_len, 0));
314 CX_CHECK(cx_bn_alloc_init(&bn_h, hash_len, hash, hash_len));
315 CX_CHECK(cx_bn_alloc(&bn_r, domain_len));
316 CX_CHECK(cx_bn_alloc(&bn_n, domain_len));
317 CX_CHECK(cx_ecpoint_alloc(&Q, private_key->curve));
318 CX_CHECK(cx_ecdomain_parameter_bn(private_key->curve, CX_CURVE_PARAM_Order, bn_n));
319 CX_CHECK(cx_bn_reduce(bn_r, bn_h, bn_n));
320 CX_CHECK(cx_bn_destroy(&bn_h));
321
322 // Compute A = a.B (B group generator)
323 CX_CHECK(cx_ecdomain_generator_bn(private_key->curve, &Q));
324 CX_CHECK(cx_ecpoint_rnd_scalarmul(&Q, secret_scalar, domain_len));
325 CX_CHECK(cx_ecpoint_compress(&Q, sig + domain_len, domain_len, &sign));
326 // Temporary store compressed A into sig + domain_len
327 cx_encode_coord(sig + domain_len, domain_len, sign);
328
329 // Compute R = r.B
330 // Use secret_scalar to temporary store r = hash mod n
331 CX_CHECK(cx_bn_export(bn_r, secret_scalar, domain_len));
332 CX_CHECK(cx_ecdomain_generator_bn(private_key->curve, &Q));
333 CX_CHECK(cx_ecpoint_rnd_scalarmul(&Q, secret_scalar, domain_len));
334 // Temporary store compressed R into sig
335 CX_CHECK(cx_ecpoint_compress(&Q, sig, domain_len, &sign));
336 cx_encode_coord(sig, domain_len, sign);
337
338 // Compute H(dom || R || A) and update the message M to the hash context later
339 CX_CHECK(cx_hash_init_ex(hash_context, hash_id, hash_len));
340 // Ed448 dom4
341 if (private_key->curve == CX_CURVE_Ed448) {
342 CX_CHECK(cx_hash_update(hash_context, C_cx_siged448, sizeof(C_cx_siged448)));
343 private_hash[0] = 0;
344 private_hash[1] = 0;
345 CX_CHECK(cx_hash_update(hash_context, private_hash, 2));
346 }
347 CX_CHECK(cx_hash_update(hash_context, sig, domain_len));
348 CX_CHECK(cx_hash_update(hash_context, sig + domain_len, domain_len));
349
350 // Temporary store r into sig + domain_len
351 memcpy(sig + domain_len, secret_scalar, domain_len);
352
353end:
354 cx_bn_unlock();
355 return error;
356}
357
358cx_err_t cx_eddsa_sign_hash(const cx_ecfp_private_key_t *pv_key,
359 cx_md_t hash_id,
360 const uint8_t *hash,
361 size_t hash_len,
362 uint8_t *sig,
363 size_t sig_len)
364{
365 size_t domain_len;
366 uint8_t secret_scalar[EDDSA_ED448_DOMAIN_LEN];
367 uint8_t hash_in[EDDSA_ED448_DOMAIN_LEN * 2];
368 cx_bn_t bn_h, bn_a, bn_r, bn_s, bn_n;
369 cx_err_t error;
370
371 CX_CHECK(cx_ecdomain_parameters_length(pv_key->curve, &domain_len));
372
373 if (sig_len < 2 * domain_len) {
374 return CX_INVALID_PARAMETER;
375 }
376
377 if (hash_len > EDDSA_ED448_DOMAIN_LEN * 2) {
378 return CX_INVALID_PARAMETER;
379 }
380 memcpy(hash_in, hash, hash_len);
381 // Encode the digest as little-endian
382 cx_encode_int(hash_in, hash_len);
383
384 CX_CHECK(cx_bn_lock(domain_len, 0));
385 CX_CHECK(cx_bn_alloc(&bn_s, domain_len));
386 CX_CHECK(cx_bn_alloc_init(&bn_h, hash_len, hash_in, hash_len));
387 CX_CHECK(cx_bn_alloc(&bn_n, domain_len));
388 CX_CHECK(cx_bn_alloc(&bn_r, domain_len));
389 CX_CHECK(cx_ecdomain_parameter_bn(pv_key->curve, CX_CURVE_PARAM_Order, bn_n));
390 CX_CHECK(cx_bn_reduce(bn_r, bn_h, bn_n));
391 CX_CHECK(cx_eddsa_get_public_key_internal(
392 pv_key, hash_id, NULL, secret_scalar, sizeof(secret_scalar), NULL, 0, hash_in));
393 CX_CHECK(cx_bn_alloc_init(&bn_a, domain_len, secret_scalar, domain_len));
394 // k * s mod n
395 CX_CHECK(cx_bn_mod_mul(bn_s, bn_r, bn_a, bn_n));
396 // Get previously computed r from sig buffer
397 CX_CHECK(cx_bn_init(bn_r, sig + domain_len, domain_len));
398 // S = r + k *s mod n
399 CX_CHECK(cx_bn_mod_add(bn_s, bn_s, bn_r, bn_n));
400 CX_CHECK(cx_bn_set_u32(bn_r, 0));
401 CX_CHECK(cx_bn_mod_sub(bn_s, bn_s, bn_r, bn_n));
402 CX_CHECK(cx_bn_export(bn_s, sig + domain_len, domain_len));
403 cx_encode_int(sig + domain_len, domain_len);
404
405end:
406 cx_bn_unlock();
407 return error;
408}
409
410cx_err_t cx_eddsa_update_hash(cx_hash_t *hash_context, const uint8_t *msg, size_t msg_len)
411{
412 return cx_hash_update(hash_context, msg, msg_len);
413}
414
415cx_err_t cx_eddsa_final_hash(cx_hash_t *hash_context, uint8_t *hash, size_t hash_len)
416{
417 if (hash_len != cx_hash_get_size(hash_context)) {
418 return CX_INVALID_PARAMETER;
419 }
420 return cx_hash_final(hash_context, hash);
421}
422
423cx_err_t cx_eddsa_sign_no_throw(const cx_ecfp_private_key_t *pv_key,
424 cx_md_t hashID,
425 const uint8_t *hash,
426 size_t hash_len,
427 uint8_t *sig,
428 size_t sig_len)
429{
430 uint8_t out_hash[EDDSA_ED448_DOMAIN_LEN * 2] = {0};
431 size_t out_hash_len = 0;
432 cx_err_t error;
433 cx_hash_t *hash_context = &G_cx.hash_ctx;
434
435 CX_CHECK(cx_eddsa_sign_init_first_hash(hash_context, pv_key, hashID));
436 CX_CHECK(cx_eddsa_update_hash(hash_context, hash, hash_len));
437 out_hash_len = cx_hash_get_size(hash_context);
438 CX_CHECK(cx_eddsa_final_hash(hash_context, out_hash, out_hash_len));
439 explicit_bzero(hash_context, sizeof(cx_hash_t));
440 CX_CHECK(cx_eddsa_sign_init_second_hash(
441 hash_context, pv_key, hashID, out_hash, out_hash_len, sig, sig_len));
442 CX_CHECK(cx_eddsa_update_hash(hash_context, hash, hash_len));
443 CX_CHECK(cx_eddsa_final_hash(hash_context, out_hash, out_hash_len));
444 CX_CHECK(cx_eddsa_sign_hash(pv_key, hashID, out_hash, out_hash_len, sig, sig_len));
445
446end:
447 explicit_bzero(hash_context, sizeof(cx_hash_t));
448 return error;
449}
450
451/* ----------------------------------------------------------------------- */
452/* */
453/* ----------------------------------------------------------------------- */
454
455cx_err_t cx_eddsa_verify_init_hash(cx_hash_t *hash_context,
456 const cx_ecfp_public_key_t *public_key,
457 cx_md_t hash_id,
458 const uint8_t *sig_r,
459 size_t sig_r_len)
460{
461 size_t domain_len, hash_len;
462 uint8_t scal[EDDSA_ED448_DOMAIN_LEN] = {0};
463 uint32_t sign;
464 cx_ecpoint_t P;
465 cx_err_t error;
466
467 CX_CHECK(cx_ecdomain_parameters_length(public_key->curve, &domain_len));
468
469 CX_CHECK(cx_eddsa_check_params(public_key->curve, domain_len, hash_id));
470
471 if (!((public_key->W_len == 1 + domain_len) || (public_key->W_len == 1 + 2 * domain_len))) {
472 return CX_INVALID_PARAMETER;
473 }
474
475 if (sig_r_len != domain_len) {
476 return CX_INVALID_PARAMETER;
477 }
478
479 hash_len = 2 * domain_len;
480
481 CX_CHECK(cx_bn_lock(domain_len, 0));
482 CX_CHECK(cx_ecpoint_alloc(&P, public_key->curve));
483 CX_CHECK(cx_hash_init_ex(hash_context, hash_id, hash_len));
484 if (CX_CURVE_Ed448 == public_key->curve) {
485 CX_CHECK(cx_hash_update(hash_context, C_cx_siged448, sizeof(C_cx_siged448)));
486 scal[0] = 0;
487 scal[1] = 0;
488 CX_CHECK(cx_hash_update(hash_context, scal, 2));
489 }
490 CX_CHECK(cx_hash_update(hash_context, sig_r, sig_r_len));
491 if (public_key->W[0] == 0x04) {
492 CX_CHECK(cx_ecpoint_init(
493 &P, &public_key->W[1], domain_len, &public_key->W[1 + domain_len], domain_len));
494 CX_CHECK(cx_ecpoint_compress(&P, scal, domain_len, &sign));
495 cx_encode_coord(scal, domain_len, sign);
496 }
497 else {
498 memmove(scal, &public_key->W[1], domain_len);
499 }
500 CX_CHECK(cx_hash_update(hash_context, scal, domain_len));
501
502end:
503 cx_bn_unlock();
504 return error;
505}
506
507bool cx_eddsa_verify_hash(const cx_ecfp_public_key_t *public_key,
508 uint8_t *hash,
509 size_t hash_len,
510 const uint8_t *signature,
511 size_t signature_len)
512{
513 size_t domain_len;
514 uint8_t scal[EDDSA_ED448_DOMAIN_LEN];
515 uint8_t scal_left[EDDSA_ED448_DOMAIN_LEN];
516 int diff;
517 bool are_equal = false;
518 bool verified = false;
519 uint32_t sign;
520 cx_bn_t bn_h, bn_rs, bn_n;
521 cx_bn_t bn_p, bn_y;
522 cx_ecpoint_t P, R, right_point, left_point;
523 cx_err_t error;
524
525 CX_CHECK(cx_ecdomain_parameters_length(public_key->curve, &domain_len));
526
527 if (signature_len != 2 * domain_len) {
528 return false;
529 }
530
531 cx_encode_int(hash, hash_len);
532
533 CX_CHECK(cx_bn_lock(domain_len, 0));
534 CX_CHECK(cx_bn_alloc(&bn_n, domain_len));
535 CX_CHECK(cx_ecdomain_parameter_bn(public_key->curve, CX_CURVE_PARAM_Order, bn_n));
536 CX_CHECK(cx_bn_alloc(&bn_rs, domain_len));
537 CX_CHECK(cx_bn_alloc_init(&bn_h, hash_len, hash, hash_len));
538 CX_CHECK(cx_bn_reduce(bn_rs, bn_h, bn_n));
539 CX_CHECK(cx_bn_export(bn_rs, scal, domain_len));
540 CX_CHECK(cx_ecpoint_alloc(&P, public_key->curve));
541 CX_CHECK(cx_ecpoint_init(
542 &P, &public_key->W[1], domain_len, &public_key->W[1 + domain_len], domain_len));
543 CX_CHECK(cx_ecpoint_neg(&P));
544
545 memmove(scal_left, signature + domain_len, domain_len);
546 cx_decode_int(scal_left, domain_len);
547
548 // The second half of the signature s must be in range 0 <= s < L to prevent
549 // signature malleability.
550 CX_CHECK(cx_bn_alloc_init(&bn_rs, domain_len, scal_left, domain_len));
551 CX_CHECK(cx_bn_cmp(bn_rs, bn_n, &diff));
552 if (diff >= 0) {
553 goto end;
554 }
555
556 CX_CHECK(cx_ecpoint_alloc(&left_point, public_key->curve));
557 CX_CHECK(cx_ecdomain_generator_bn(public_key->curve, &left_point));
558 CX_CHECK(cx_ecpoint_alloc(&right_point, public_key->curve));
559 CX_CHECK(cx_ecpoint_cmp(&left_point, &P, &are_equal));
560
561 if (are_equal) {
562 CX_CHECK(cx_ecpoint_scalarmul(&left_point, scal_left, domain_len));
563 CX_CHECK(cx_ecpoint_scalarmul(&P, scal, domain_len));
564 CX_CHECK(cx_ecpoint_add(&right_point, &left_point, &P));
565 }
566 else {
567 CX_CHECK(cx_ecpoint_double_scalarmul(
568 &right_point, &left_point, &P, scal_left, domain_len, scal, domain_len));
569 }
570
571 CX_CHECK(cx_ecpoint_alloc(&R, public_key->curve));
572 memmove(scal, signature, domain_len);
573 sign = cx_decode_coord(scal, domain_len);
574
575 CX_CHECK(cx_bn_alloc(&bn_p, domain_len));
576 CX_CHECK(cx_ecdomain_parameter_bn(public_key->curve, CX_CURVE_PARAM_Field, bn_p));
577
578 // If the y coordinate is >= p then the decoding fails
579 CX_CHECK(cx_bn_alloc(&bn_y, domain_len));
580 CX_CHECK(cx_bn_init(bn_y, scal, domain_len));
581
582 CX_CHECK(cx_bn_cmp(bn_y, bn_p, &diff));
583 if (diff >= 0) {
584 goto end;
585 }
586
587 CX_CHECK(cx_ecpoint_decompress(&R, scal, domain_len, sign));
588 CX_CHECK(cx_ecpoint_destroy(&left_point));
589 CX_CHECK(cx_ecpoint_destroy(&P));
590
591 // Check the signature
592 CX_CHECK(cx_ecpoint_cmp(&R, &right_point, &verified));
593
594end:
595 cx_bn_unlock();
596 return error == CX_OK && verified;
597}
598
599bool cx_eddsa_verify_no_throw(const cx_ecfp_public_key_t *pu_key,
600 cx_md_t hashID,
601 const uint8_t *hash,
602 size_t hash_len,
603 const uint8_t *sig,
604 size_t sig_len)
605{
606 uint8_t out_hash[EDDSA_ED448_DOMAIN_LEN * 2] = {0};
607 size_t out_hash_len = 0;
608 cx_hash_t *hash_context = &G_cx.hash_ctx;
609 bool verified = false;
610 cx_err_t error = CX_INTERNAL_ERROR;
611
612 CX_CHECK(cx_eddsa_verify_init_hash(hash_context, pu_key, hashID, sig, sig_len / 2));
613 out_hash_len = cx_hash_get_size(hash_context);
614 CX_CHECK(cx_eddsa_update_hash(hash_context, hash, hash_len));
615 CX_CHECK(cx_eddsa_final_hash(hash_context, out_hash, out_hash_len));
616 verified = cx_eddsa_verify_hash(pu_key, out_hash, out_hash_len, sig, sig_len);
617
618end:
619 explicit_bzero(&G_cx.hash_ctx, sizeof(G_cx.hash_ctx));
620 return verified;
621}
622
623#endif // HAVE_EDDSA
624#endif // HAVE_ECC_TWISTED_EDWARDS
union cx_u G_cx
Definition cx_ram.c:21
unsigned char uint8_t
Definition usbd_conf.h:53