53#if defined(ARDUINO) && defined(CONFIG_IDF_TARGET_ESP32S3) && CONFIG_IDF_TARGET_ESP32S3
54#define PC_ECDSA_MPI_HW 1
59#if defined(ARDUINO) && !defined(PC_ECDSA_MPI_HW)
60#include <esp_random.h>
61#include <mbedtls/ecdh.h>
62#include <mbedtls/ecdsa.h>
63#include <mbedtls/ecp.h>
75#if defined(CONFIG_IDF_TARGET_ESP32S3) && CONFIG_IDF_TARGET_ESP32S3
85#if defined(ARDUINO) && !defined(PC_ECDSA_MPI_HW)
90int ecdsa_rng(
void *ctx,
unsigned char *buf,
size_t len)
93 esp_fill_random(buf, len);
100 mbedtls_ecp_group grp;
103 mbedtls_ecp_group_init(&grp);
104 mbedtls_ecp_point_init(&Q);
105 mbedtls_mpi_init(&d);
108 if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1) == 0 &&
110 mbedtls_ecp_mul(&grp, &Q, &d, &grp.G, ecdsa_rng,
nullptr) == 0)
113 if (mbedtls_ecp_point_write_binary(&grp, &Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, pub,
PC_ECDSA_P256_PUB_LEN) ==
121 mbedtls_mpi_free(&d);
122 mbedtls_ecp_point_free(&Q);
123 mbedtls_ecp_group_free(&grp);
133 mbedtls_ecp_group grp;
137 mbedtls_ecp_group_init(&grp);
138 mbedtls_mpi_init(&d);
139 mbedtls_mpi_init(&r);
140 mbedtls_mpi_init(&s);
143 if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1) == 0 &&
152 mbedtls_mpi_free(&s);
153 mbedtls_mpi_free(&r);
154 mbedtls_mpi_free(&d);
155 mbedtls_ecp_group_free(&grp);
165 mbedtls_ecp_group grp;
169 mbedtls_ecp_group_init(&grp);
170 mbedtls_ecp_point_init(&Q);
171 mbedtls_mpi_init(&r);
172 mbedtls_mpi_init(&s);
175 if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1) == 0 &&
184 mbedtls_mpi_free(&s);
185 mbedtls_mpi_free(&r);
186 mbedtls_ecp_point_free(&Q);
187 mbedtls_ecp_group_free(&grp);
194 mbedtls_ecp_group grp;
198 mbedtls_ecp_group_init(&grp);
199 mbedtls_ecp_point_init(&Q);
200 mbedtls_mpi_init(&d);
201 mbedtls_mpi_init(&z);
204 if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1) == 0 &&
206 mbedtls_ecp_check_pubkey(&grp, &Q) == 0 && mbedtls_mpi_read_binary(&d, priv,
PC_ECDSA_P256_PRIV_LEN) == 0 &&
207 mbedtls_ecdh_compute_shared(&grp, &z, &Q, &d, ecdsa_rng,
nullptr) == 0 &&
213 mbedtls_mpi_free(&z);
214 mbedtls_mpi_free(&d);
215 mbedtls_ecp_point_free(&Q);
216 mbedtls_ecp_group_free(&grp);
228const uint32_t P256_P[8] = {0xffffffffu, 0xffffffffu, 0xffffffffu, 0x00000000u,
229 0x00000000u, 0x00000000u, 0x00000001u, 0xffffffffu};
230const uint32_t P256_N[8] = {0xfc632551u, 0xf3b9cac2u, 0xa7179e84u, 0xbce6faadu,
231 0xffffffffu, 0xffffffffu, 0x00000000u, 0xffffffffu};
232const uint32_t P256_B[8] = {0x27d2604bu, 0x3bce3c3eu, 0xcc53b0f6u, 0x651d06b0u,
233 0x769886bcu, 0xb3ebbd55u, 0xaa3a93e7u, 0x5ac635d8u};
234const uint32_t P256_B3[8] = {0x777720e2u, 0xb36ab4bau, 0x64fb12e2u, 0x2f571411u,
235 0x63c99435u, 0x1bc33800u, 0xfeafbbb6u, 0x1052a18au};
238const uint32_t P256_P_R2[8] = {0x00000003u, 0x00000000u, 0xffffffffu, 0xfffffffbu,
239 0xfffffffeu, 0xffffffffu, 0xfffffffdu, 0x00000004u};
240const uint32_t P256_N_R2[8] = {0xbe79eea2u, 0x83244c95u, 0x49bd6fa6u, 0x4699799cu,
241 0x2b6bec59u, 0x2845b239u, 0xf3d95620u, 0x66e12d94u};
250const Fp FP = {P256_P, 0x00000001u, P256_P_R2};
251const Fp FN = {P256_N, 0xee00bc4fu, P256_N_R2};
253void fp_set(uint32_t r[8],
const uint32_t a[8])
255 for (
int i = 0; i < 8; i++)
260void fp_zero(uint32_t r[8])
262 for (
int i = 0; i < 8; i++)
267bool fp_is_zero(
const uint32_t a[8])
270 for (
int i = 0; i < 8; i++)
277int fp_cmp(
const uint32_t a[8],
const uint32_t b[8])
279 for (
int i = 7; i >= 0; i--)
283 return a[i] > b[i] ? 1 : -1;
289uint32_t sub_raw(uint32_t r[8],
const uint32_t a[8],
const uint32_t b[8])
292 for (
int i = 0; i < 8; i++)
294 uint64_t t = (uint64_t)a[i] - b[i] - brw;
296 brw = (t >> 32) & 1u;
298 return (uint32_t)brw;
301void fp_add(uint32_t r[8],
const uint32_t a[8],
const uint32_t b[8],
const Fp *F)
305 for (
int i = 0; i < 8; i++)
307 c += (uint64_t)a[i] + b[i];
311 uint32_t carry = (uint32_t)c;
314 for (
int i = 0; i < 8; i++)
316 uint64_t v = (uint64_t)s[i] - F->m[i] - b2;
321 uint32_t take_t = carry | (uint32_t)(1u - b2);
322 uint32_t
mask = (uint32_t)(-(int32_t)take_t);
323 for (
int i = 0; i < 8; i++)
325 r[i] = (t[i] &
mask) | (s[i] & ~mask);
329void fp_sub(uint32_t r[8],
const uint32_t a[8],
const uint32_t b[8],
const Fp *F)
332 uint32_t borrow = sub_raw(t, a, b);
333 uint32_t
mask = (uint32_t)(-(int32_t)borrow);
335 for (
int i = 0; i < 8; i++)
337 c += (uint64_t)t[i] + (F->m[i] & mask);
343void fp_reduce_once(uint32_t r[8],
const uint32_t a[8],
const uint32_t m[8])
346 uint32_t borrow = sub_raw(t, a, m);
347 uint32_t
mask = (uint32_t)(-(int32_t)borrow);
348 for (
int i = 0; i < 8; i++)
350 r[i] = (a[i] &
mask) | (t[i] & ~mask);
354#ifdef PC_ECDSA_MPI_HW
357void fp_mul(uint32_t z[8],
const uint32_t x[8],
const uint32_t y[8],
const Fp *F)
361 pc_rsa_modmul(z, x, y, F->m, F->mprime, F->r2, 8);
381bool reduce_low8_ge(
const uint32_t acc[8],
const uint32_t m[8])
383 for (
int k = 7; k >= 0; k--)
387 return acc[k] > m[k];
393void reduce_mod(uint32_t r[8],
const uint32_t prod[16],
const uint32_t m[8])
396 for (
int k = 0; k < 9; k++)
400 for (
int bit = 511; bit >= 0; bit--)
408 for (
int k = 0; k < 9; k++)
410 uint32_t nc = acc[k] >> 31;
411 acc[k] = (acc[k] << 1) | carry;
415 acc[0] |= (prod[bit >> 5] >> (bit & 31)) & 1u;
416 bool ge = acc[8] != 0;
419 ge = reduce_low8_ge(acc, m);
424 for (
int k = 0; k < 8; k++)
426 uint64_t t = (uint64_t)acc[k] - m[k] - brw;
427 acc[k] = (uint32_t)t;
428 brw = (t >> 32) & 1u;
430 acc[8] -= (uint32_t)brw;
433 for (
int k = 0; k < 8; k++)
439void fp_mul(uint32_t z[8],
const uint32_t x[8],
const uint32_t y[8],
const Fp *F)
442 for (
int k = 0; k < 16; k++)
446 for (
int i = 0; i < 8; i++)
449 for (
int j = 0; j < 8; j++)
451 uint64_t t = (uint64_t)prod[i + j] + (uint64_t)x[i] * y[j] + carry;
452 prod[i + j] = (uint32_t)t;
458 uint64_t t = (uint64_t)prod[k] + carry;
459 prod[k] = (uint32_t)t;
464 reduce_mod(z, prod, F->m);
477void fp_sqr(uint32_t r[8],
const uint32_t a[8],
const Fp *F)
483void fp_mul_by_a(uint32_t r[8],
const uint32_t x[8])
486 fp_add(tx, x, x, &FP);
487 fp_add(tx, tx, x, &FP);
488 static const uint32_t zero[8] = {0, 0, 0, 0, 0, 0, 0, 0};
489 fp_sub(r, zero, tx, &FP);
492void fp_inv(uint32_t r[8],
const uint32_t a[8],
const Fp *F)
494 static const uint32_t two[8] = {2, 0, 0, 0, 0, 0, 0, 0};
496 sub_raw(e, F->m, two);
497 uint32_t res[8] = {1, 0, 0, 0, 0, 0, 0, 0};
500 for (
int i = 0; i < 256; i++)
502 if ((e[i >> 5] >> (i & 31)) & 1u)
504 fp_mul(res, res, base, F);
506 fp_mul(base, base, base, F);
511void load_be(uint32_t r[8],
const uint8_t b[32])
513 for (
int i = 0; i < 8; i++)
515 const uint8_t *p = b + (28 - 4 * i);
516 r[i] = ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3];
519void store_be(uint8_t b[32],
const uint32_t r[8])
521 for (
int i = 0; i < 8; i++)
523 uint8_t *p = b + (28 - 4 * i);
524 p[0] = (uint8_t)(r[i] >> 24);
525 p[1] = (uint8_t)(r[i] >> 16);
526 p[2] = (uint8_t)(r[i] >> 8);
527 p[3] = (uint8_t)r[i];
544 {0xd898c296u, 0xf4a13945u, 0x2deb33a0u, 0x77037d81u, 0x63a440f2u, 0xf8bce6e5u, 0xe12c4247u, 0x6b17d1f2u},
545 {0x37bf51f5u, 0xcbb64068u, 0x6b315eceu, 0x2bce3357u, 0x7c0f9e16u, 0x8ee7eb4au, 0xfe1a7f9bu, 0x4fe342e2u},
546 {1u, 0, 0, 0, 0, 0, 0, 0}};
548bool pt_is_infinity(
const Pt *p)
550 return fp_is_zero(p->Z);
552void pt_set_infinity(Pt *p)
559void pt_from_affine(Pt *p,
const uint32_t x[8],
const uint32_t y[8])
567void pt_to_affine(uint32_t x[8], uint32_t y[8],
const Pt *p)
570 fp_inv(zi, p->Z, &FP);
571 fp_mul(x, p->X, zi, &FP);
572 fp_mul(y, p->Y, zi, &FP);
576void pt_add(Pt *r,
const Pt *a,
const Pt *b)
587 fp_mul(t0, a->X, b->X, &FP);
588 fp_mul(t1, a->Y, b->Y, &FP);
589 fp_mul(t2, a->Z, b->Z, &FP);
590 fp_add(t3, a->X, a->Y, &FP);
591 fp_add(t4, b->X, b->Y, &FP);
592 fp_mul(t3, t3, t4, &FP);
593 fp_add(t4, t0, t1, &FP);
594 fp_sub(t3, t3, t4, &FP);
595 fp_add(t4, a->X, a->Z, &FP);
596 fp_add(t5, b->X, b->Z, &FP);
597 fp_mul(t4, t4, t5, &FP);
598 fp_add(t5, t0, t2, &FP);
599 fp_sub(t4, t4, t5, &FP);
600 fp_add(t5, a->Y, a->Z, &FP);
601 fp_add(x3, b->Y, b->Z, &FP);
602 fp_mul(t5, t5, x3, &FP);
603 fp_add(x3, t1, t2, &FP);
604 fp_sub(t5, t5, x3, &FP);
606 fp_mul(x3, P256_B3, t2, &FP);
607 fp_add(z3, x3, z3, &FP);
608 fp_sub(x3, t1, z3, &FP);
609 fp_add(z3, t1, z3, &FP);
610 fp_mul(y3, x3, z3, &FP);
611 fp_add(t1, t0, t0, &FP);
612 fp_add(t1, t1, t0, &FP);
614 fp_mul(t4, P256_B3, t4, &FP);
615 fp_add(t1, t1, t2, &FP);
616 fp_sub(t2, t0, t2, &FP);
618 fp_add(t4, t4, t2, &FP);
619 fp_mul(t0, t1, t4, &FP);
620 fp_add(y3, y3, t0, &FP);
621 fp_mul(t0, t5, t4, &FP);
622 fp_mul(x3, t3, x3, &FP);
623 fp_sub(x3, x3, t0, &FP);
624 fp_mul(t0, t3, t1, &FP);
625 fp_mul(z3, t5, z3, &FP);
626 fp_add(z3, z3, t0, &FP);
633void pt_dbl(Pt *r,
const Pt *a)
642 fp_sqr(t0, a->X, &FP);
643 fp_sqr(t1, a->Y, &FP);
644 fp_sqr(t2, a->Z, &FP);
645 fp_mul(t3, a->X, a->Y, &FP);
646 fp_add(t3, t3, t3, &FP);
647 fp_mul(z3, a->X, a->Z, &FP);
648 fp_add(z3, z3, z3, &FP);
650 fp_mul(y3, P256_B3, t2, &FP);
651 fp_add(y3, x3, y3, &FP);
652 fp_sub(x3, t1, y3, &FP);
653 fp_add(y3, t1, y3, &FP);
654 fp_mul(y3, x3, y3, &FP);
655 fp_mul(x3, t3, x3, &FP);
656 fp_mul(z3, P256_B3, z3, &FP);
658 fp_sub(t3, t0, t2, &FP);
660 fp_add(t3, t3, z3, &FP);
661 fp_add(z3, t0, t0, &FP);
662 fp_add(t0, z3, t0, &FP);
663 fp_add(t0, t0, t2, &FP);
664 fp_mul(t0, t0, t3, &FP);
665 fp_add(y3, y3, t0, &FP);
666 fp_mul(t2, a->Y, a->Z, &FP);
667 fp_add(t2, t2, t2, &FP);
668 fp_mul(t0, t2, t3, &FP);
669 fp_sub(x3, x3, t0, &FP);
670 fp_mul(z3, t2, t1, &FP);
671 fp_add(z3, z3, z3, &FP);
672 fp_add(z3, z3, z3, &FP);
679void pt_table_select(Pt *dst,
const Pt table[16], uint32_t idx)
684 for (uint32_t e = 0; e < 16; e++)
686 uint32_t x = e ^ idx;
687 uint32_t nz = (x | (0u - x)) >> 31;
688 uint32_t
mask = (uint32_t)(nz - 1u);
689 for (
int i = 0; i < 8; i++)
691 dst->X[i] |= table[e].X[i] &
mask;
692 dst->Y[i] |= table[e].Y[i] &
mask;
693 dst->Z[i] |= table[e].Z[i] &
mask;
703void pt_scalarmul(Pt *r,
const uint32_t k[8],
const Pt *p)
706 pt_set_infinity(&table[0]);
708 for (
int i = 2; i < 16; i++)
712 pt_add(&table[i], &table[i - 1], p);
716 pt_dbl(&table[i], &table[i / 2]);
720 pt_set_infinity(&acc);
721 for (
int w = 63; w >= 0; w--)
727 uint32_t idx = (k[w >> 3] >> ((w & 7) * 4)) & 0xfu;
729 pt_table_select(&sel, table, idx);
730 pt_add(&acc, &acc, &sel);
736bool on_curve(
const uint32_t x[8],
const uint32_t y[8])
738 if (fp_cmp(x, P256_P) >= 0 || fp_cmp(y, P256_P) >= 0)
747 fp_mul(rhs, rhs, x, &FP);
748 fp_add(t, x, x, &FP);
749 fp_add(t, t, x, &FP);
750 fp_sub(rhs, rhs, t, &FP);
751 fp_add(rhs, rhs, P256_B, &FP);
752 return fp_cmp(lhs, rhs) == 0;
758void pc_hmac_cat(uint8_t out[32],
const uint8_t key[32],
const uint8_t *v,
size_t vlen,
const int tag,
const uint8_t *x,
763 memcpy(buf + n, v, vlen);
767 buf[n++] = (uint8_t)tag;
768 memcpy(buf + n, x, 32);
770 memcpy(buf + n, e, 32);
786bool ecdsa_try_sign(
const uint32_t k[8],
const uint32_t d[8],
const uint32_t e[8], uint8_t sig[64])
789 fp_cmp(k, P256_N) >= 0)
794 pt_scalarmul(&R, k, &P256_G);
798 if (pt_is_infinity(&R))
804 pt_to_affine(rx, ry, &R);
806 fp_reduce_once(r, rx, P256_N);
813 fp_inv(kinv, k, &FN);
814 fp_mul(s, r, d, &FN);
815 fp_add(s, s, e, &FN);
816 fp_mul(s, kinv, s, &FN);
822 store_be(sig + 32, s);
827bool ecdsa_sign_core(uint8_t sig[64],
const uint8_t h1[32],
const uint32_t d[8])
832 fp_reduce_once(e, etmp, P256_N);
843 pc_hmac_cat(K, K, V, 32, 0x00, x_oct, h_oct);
844 pc_hmac_cat(V, K, V, 32, -1,
nullptr,
nullptr);
845 pc_hmac_cat(K, K, V, 32, 0x01, x_oct, h_oct);
846 pc_hmac_cat(V, K, V, 32, -1,
nullptr,
nullptr);
848 for (
int guard = 0; guard < 64; guard++)
852 pc_hmac_cat(V, K, V, 32, -1,
nullptr,
nullptr);
855 if (ecdsa_try_sign(k, d, e, sig))
865 pc_hmac_cat(V, K, V, 32, -1,
nullptr,
nullptr);
877 if (fp_is_zero(d) || fp_cmp(d, P256_N) >= 0)
884 pt_scalarmul(&Q, d, &P256_G);
885 bool ok = !pt_is_infinity(&Q);
892 pt_to_affine(qx, qy, &Q);
894 store_be(pub + 1, qx);
895 store_be(pub + 33, qy);
906 if (fp_is_zero(d) || fp_cmp(d, P256_N) >= 0)
914 bool ok = ecdsa_sign_core(sig, h1, d);
928 load_be(qx, pub + 1);
929 load_be(qy, pub + 33);
934 load_be(s, sig + 32);
935 if (fp_is_zero(r) || fp_cmp(r, P256_N) >= 0 || fp_is_zero(s) || fp_cmp(s, P256_N) >= 0)
945 fp_reduce_once(e, etmp, P256_N);
948 bool ok = on_curve(qx, qy);
955 fp_mul(u1, e, w, &FN);
956 fp_mul(u2, r, w, &FN);
962 pt_from_affine(&Q, qx, qy);
963 pt_scalarmul(&Rg, u1, &P256_G);
964 pt_scalarmul(&Rq, u2, &Q);
965 pt_add(&R, &Rg, &Rq);
966 if (pt_is_infinity(&R))
975 pt_to_affine(rx, ry, &R);
976 fp_reduce_once(rxn, rx, P256_N);
977 ok = fp_cmp(rxn, r) == 0;
987 if (peer_pub[0] != 0x04)
993 load_be(qx, peer_pub + 1);
994 load_be(qy, peer_pub + 33);
997 if (fp_is_zero(d) || fp_cmp(d, P256_N) >= 0)
1003 bool ok = on_curve(qx, qy);
1008 pt_from_affine(&Q, qx, qy);
1009 pt_scalarmul(&R, d, &Q);
1013 if (pt_is_infinity(&R))
1021 pt_to_affine(rx, ry, &R);
1022 store_be(shared_x, rx);
Per-translation-unit optimization override for hot, pure-integer crypto.
#define PC_CRYPTO_HOT_PEEL
bool pc_ecdsa_p256_ecdh(uint8_t shared_x[PC_ECDSA_P256_COORD_LEN], const uint8_t peer_pub[PC_ECDSA_P256_PUB_LEN], const uint8_t priv[PC_ECDSA_P256_PRIV_LEN])
P-256 ECDH: the shared-secret X coordinate of d * Q_peer (RFC 5656 §4 / RFC 5903).
bool pc_ecdsa_p256_verify(const uint8_t pub[PC_ECDSA_P256_PUB_LEN], const uint8_t *msg, size_t mlen, const uint8_t sig[PC_ECDSA_P256_SIG_LEN])
Verify a P-256 ECDSA signature (SHA-256) against an uncompressed public point.
bool pc_ecdsa_p256_sign(uint8_t sig[PC_ECDSA_P256_SIG_LEN], const uint8_t *msg, size_t mlen, const uint8_t priv[PC_ECDSA_P256_PRIV_LEN])
Sign mlen bytes of msg with a P-256 private key (ECDSA, SHA-256).
bool pc_ecdsa_p256_pubkey(uint8_t pub[PC_ECDSA_P256_PUB_LEN], const uint8_t priv[PC_ECDSA_P256_PRIV_LEN])
Derive the uncompressed public point Q = d*G from a P-256 private scalar.
NIST P-256 primitives for SSH: ECDSA signatures and ECDH (RFC 5656 / FIPS 186-4).
#define PC_ECDSA_P256_COORD_LEN
P-256 coordinate length (one of X, Y).
#define PC_ECDSA_P256_SIG_LEN
Raw ECDSA signature length: r || s (32 + 32, big-endian).
#define PC_ECDSA_P256_PUB_LEN
P-256 uncompressed public point length: 0x04 || X || Y.
#define PC_ECDSA_P256_PRIV_LEN
P-256 private key (scalar d) length.
Single owner of the ESP32 RSA/MPI accelerator, by DIRECT register access - a self-contained HAL.
void pc_hmac_sha256(const uint8_t *key, size_t key_len, const uint8_t *data, size_t len, uint8_t mac[PC_HMAC_SHA256_LEN])
Compute HMAC-SHA2-256 over a single contiguous buffer.
HMAC-SHA2-256 (RFC 2104 + FIPS 198-1) - streaming context and one-shot API.
int ecdsa_rng(void *ctx, unsigned char *buf, size_t len)
uint32_t mask(uint8_t width)
Mask of width low bits (width 32 handled without a 32-bit shift, which is UB).
void pc_sha256(const uint8_t *data, size_t len, uint8_t digest[PC_SHA256_DIGEST_LEN])
One-shot SHA-256: hash len bytes of data into digest (32 bytes).
SHA-256 (FIPS 180-4) - streaming context and one-shot API.
#define PC_SHA256_DIGEST_LEN
SHA-256 digest length in bytes.