19 #ifdef HAVE_ECC_TWISTED_EDWARDS
30 #define EDDSA_ED448_DOMAIN_LEN (57)
32 static void cx_encode_int(
uint8_t *v,
int len)
48 #define cx_decode_int(v, l) cx_encode_int(v, l)
50 int cx_decode_coord(
uint8_t *coord,
int len)
53 cx_encode_int(coord, len);
54 sign = coord[0] & 0x80;
59 void cx_encode_coord(
uint8_t *coord,
int len,
int sign)
61 coord[0] |= sign ? 0x80 : 0x00;
62 cx_encode_int(coord, len);
68 cx_err_t cx_eddsa_get_public_key_internal(
const cx_ecfp_private_key_t *pv_key,
70 cx_ecfp_public_key_t *pu_key,
80 CX_CHECK(cx_ecdomain_parameters_length(pv_key->curve, &size));
82 if (!CX_CURVE_RANGE(pv_key->curve, TWISTED_EDWARDS)) {
83 return CX_INVALID_PARAMETER;
85 if (!((pv_key->d_len == size) || (pv_key->d_len == (2 * size)))) {
86 return CX_INVALID_PARAMETER;
88 if (!(((a == NULL) && (a_len == 0)) || ((a_len) && (a_len >= size)))) {
89 return CX_INVALID_PARAMETER;
91 if (!(((h == NULL) && (h_len == 0)) || ((h_len) && (h_len >= size)))) {
92 return CX_INVALID_PARAMETER;
96 #if defined(HAVE_SHA512)
100 #if defined(HAVE_SHA3)
106 #if defined(HAVE_BLAKE2)
108 if (cx_hash_init_ex(&
G_cx.hash_ctx, hashID, size * 2) != CX_OK) {
109 return CX_INVALID_PARAMETER;
115 return CX_INVALID_PARAMETER;
118 if (pv_key->d_len == size) {
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) {
132 scal[31] = (scal[31] & 0x7F) | 0x40;
145 memmove(scal, pv_key->d, pv_key->d_len);
152 cx_decode_int(scal, size);
154 memmove(a, scal, size);
157 memmove(h, scal + size, size);
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;
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));
175 cx_err_t cx_eddsa_get_public_key_no_throw(
const cx_ecfp_private_key_t *pv_key,
177 cx_ecfp_public_key_t *pu_key,
183 uint8_t scal[EDDSA_ED448_DOMAIN_LEN * 2];
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));
198 static uint8_t const C_cx_siged448[] = {
'S',
'i',
'g',
'E',
'd',
'4',
'4',
'8'};
200 static cx_err_t cx_eddsa_check_params(cx_curve_t curve,
size_t domain_len, cx_md_t hash_id)
202 if (!CX_CURVE_RANGE(curve, TWISTED_EDWARDS)) {
203 return CX_INVALID_PARAMETER;
210 #if (defined(HAVE_SHA512) || defined(HAVE_SHA3))
211 #if defined(HAVE_SHA512)
215 #if defined(HAVE_SHA3)
219 if (domain_len * 2 != 512 / 8) {
220 return INVALID_PARAMETER;
225 #if (defined(HAVE_SHA3) || defined(HAVE_BLAKE2))
226 #if defined(HAVE_SHA3)
230 #if defined(HAVE_BLAKE2)
237 return INVALID_PARAMETER;
247 cx_err_t cx_eddsa_sign_init_first_hash(cx_hash_t *hash_context,
248 const cx_ecfp_private_key_t *private_key,
251 size_t domain_len, hash_len;
253 uint8_t prefix[EDDSA_ED448_DOMAIN_LEN];
254 uint8_t private_hash[EDDSA_ED448_DOMAIN_LEN * 2];
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));
259 if (!((private_key->d_len == domain_len) || (private_key->d_len == 2 * domain_len))) {
260 return CX_INVALID_PARAMETER;
263 hash_len = 2 * domain_len;
266 CX_CHECK(cx_eddsa_get_public_key_internal(
267 private_key, hash_id, NULL, NULL, 0, prefix,
sizeof(prefix), private_hash));
269 CX_CHECK(cx_hash_init_ex(hash_context, hash_id, hash_len));
272 if (private_key->curve == CX_CURVE_Ed448) {
273 CX_CHECK(cx_hash_update(hash_context, C_cx_siged448,
sizeof(C_cx_siged448)));
276 CX_CHECK(cx_hash_update(hash_context, private_hash, 2));
279 CX_CHECK(cx_hash_update(hash_context, prefix, domain_len));
285 cx_err_t cx_eddsa_sign_init_second_hash(cx_hash_t *hash_context,
286 const cx_ecfp_private_key_t *private_key,
294 cx_bn_t bn_h, bn_r, bn_n;
297 uint8_t secret_scalar[EDDSA_ED448_DOMAIN_LEN];
298 uint8_t private_hash[EDDSA_ED448_DOMAIN_LEN * 2];
301 CX_CHECK(cx_ecdomain_parameters_length(private_key->curve, &domain_len));
303 if (sig_len < 2 * domain_len) {
304 return CX_INVALID_PARAMETER;
308 CX_CHECK(cx_eddsa_get_public_key_internal(
309 private_key, hash_id, NULL, secret_scalar,
sizeof(secret_scalar), NULL, 0, private_hash));
311 cx_encode_int(hash, hash_len);
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));
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));
327 cx_encode_coord(sig + domain_len, domain_len, sign);
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));
335 CX_CHECK(cx_ecpoint_compress(&Q, sig, domain_len, &sign));
336 cx_encode_coord(sig, domain_len, sign);
339 CX_CHECK(cx_hash_init_ex(hash_context, hash_id, hash_len));
341 if (private_key->curve == CX_CURVE_Ed448) {
342 CX_CHECK(cx_hash_update(hash_context, C_cx_siged448,
sizeof(C_cx_siged448)));
345 CX_CHECK(cx_hash_update(hash_context, private_hash, 2));
347 CX_CHECK(cx_hash_update(hash_context, sig, domain_len));
348 CX_CHECK(cx_hash_update(hash_context, sig + domain_len, domain_len));
351 memcpy(sig + domain_len, secret_scalar, domain_len);
358 cx_err_t cx_eddsa_sign_hash(
const cx_ecfp_private_key_t *pv_key,
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;
371 CX_CHECK(cx_ecdomain_parameters_length(pv_key->curve, &domain_len));
373 if (sig_len < 2 * domain_len) {
374 return CX_INVALID_PARAMETER;
377 if (hash_len > EDDSA_ED448_DOMAIN_LEN * 2) {
378 return CX_INVALID_PARAMETER;
380 memcpy(hash_in, hash, hash_len);
382 cx_encode_int(hash_in, hash_len);
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));
395 CX_CHECK(cx_bn_mod_mul(bn_s, bn_r, bn_a, bn_n));
397 CX_CHECK(cx_bn_init(bn_r, sig + domain_len, domain_len));
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);
410 cx_err_t cx_eddsa_update_hash(cx_hash_t *hash_context,
const uint8_t *msg,
size_t msg_len)
412 return cx_hash_update(hash_context, msg, msg_len);
415 cx_err_t cx_eddsa_final_hash(cx_hash_t *hash_context,
uint8_t *hash,
size_t hash_len)
417 if (hash_len != cx_hash_get_size(hash_context)) {
418 return CX_INVALID_PARAMETER;
420 return cx_hash_final(hash_context, hash);
423 cx_err_t cx_eddsa_sign_no_throw(
const cx_ecfp_private_key_t *pv_key,
430 uint8_t out_hash[EDDSA_ED448_DOMAIN_LEN * 2] = {0};
431 size_t out_hash_len = 0;
433 cx_hash_t *hash_context = &
G_cx.hash_ctx;
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));
447 explicit_bzero(hash_context,
sizeof(cx_hash_t));
455 cx_err_t cx_eddsa_verify_init_hash(cx_hash_t *hash_context,
456 const cx_ecfp_public_key_t *public_key,
461 size_t domain_len, hash_len;
462 uint8_t scal[EDDSA_ED448_DOMAIN_LEN] = {0};
467 CX_CHECK(cx_ecdomain_parameters_length(public_key->curve, &domain_len));
469 CX_CHECK(cx_eddsa_check_params(public_key->curve, domain_len, hash_id));
471 if (!((public_key->W_len == 1 + domain_len) || (public_key->W_len == 1 + 2 * domain_len))) {
472 return CX_INVALID_PARAMETER;
475 if (sig_r_len != domain_len) {
476 return CX_INVALID_PARAMETER;
479 hash_len = 2 * domain_len;
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)));
488 CX_CHECK(cx_hash_update(hash_context, scal, 2));
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);
498 memmove(scal, &public_key->W[1], domain_len);
500 CX_CHECK(cx_hash_update(hash_context, scal, domain_len));
507 bool cx_eddsa_verify_hash(
const cx_ecfp_public_key_t *public_key,
511 size_t signature_len)
514 uint8_t scal[EDDSA_ED448_DOMAIN_LEN];
515 uint8_t scal_left[EDDSA_ED448_DOMAIN_LEN];
517 bool are_equal =
false;
518 bool verified =
false;
520 cx_bn_t bn_h, bn_rs, bn_n;
522 cx_ecpoint_t P, R, right_point, left_point;
525 CX_CHECK(cx_ecdomain_parameters_length(public_key->curve, &domain_len));
527 if (signature_len != 2 * domain_len) {
531 cx_encode_int(hash, hash_len);
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));
545 memmove(scal_left, signature + domain_len, domain_len);
546 cx_decode_int(scal_left, domain_len);
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));
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));
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));
567 CX_CHECK(cx_ecpoint_double_scalarmul(
568 &right_point, &left_point, &P, scal_left, domain_len, scal, domain_len));
571 CX_CHECK(cx_ecpoint_alloc(&R, public_key->curve));
572 memmove(scal, signature, domain_len);
573 sign = cx_decode_coord(scal, domain_len);
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));
579 CX_CHECK(cx_bn_alloc(&bn_y, domain_len));
580 CX_CHECK(cx_bn_init(bn_y, scal, domain_len));
582 CX_CHECK(cx_bn_cmp(bn_y, bn_p, &diff));
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));
592 CX_CHECK(cx_ecpoint_cmp(&R, &right_point, &verified));
596 return error == CX_OK && verified;
599 bool cx_eddsa_verify_no_throw(
const cx_ecfp_public_key_t *pu_key,
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;
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);
619 explicit_bzero(&
G_cx.hash_ctx,
sizeof(
G_cx.hash_ctx));