From fbd3bd4fc7d69483707d586f28c80592144c914d Mon Sep 17 00:00:00 2001 From: jocover Date: Thu, 1 Feb 2024 19:36:48 +0800 Subject: [PATCH] add ed25519 hardware acceleration support --- main/CMakeLists.txt | 5 +- main/c25519/ed25519.c | 320 --------- main/c25519/ed25519.h | 82 --- main/c25519/edsign.c | 172 ----- main/c25519/edsign.h | 51 -- main/c25519/f25519.c | 324 --------- main/c25519/f25519.h | 92 --- main/c25519/fprime.c | 215 ------ main/c25519/fprime.h | 70 -- main/crypto/ecc.c | 6 +- main/crypto/esp32_ed25519.c | 978 ++++++++++++++++++++++++++++ main/crypto/include/esp32_ed25519.h | 54 ++ 12 files changed, 1037 insertions(+), 1332 deletions(-) delete mode 100644 main/c25519/ed25519.c delete mode 100644 main/c25519/ed25519.h delete mode 100644 main/c25519/edsign.c delete mode 100644 main/c25519/edsign.h delete mode 100644 main/c25519/f25519.c delete mode 100644 main/c25519/f25519.h delete mode 100644 main/c25519/fprime.c delete mode 100644 main/c25519/fprime.h create mode 100644 main/crypto/esp32_ed25519.c create mode 100644 main/crypto/include/esp32_ed25519.h diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 479172e..c3e301a 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,9 +1,8 @@ idf_component_register( SRCS "device.c" "ctaphid.c" "secret.c" "ctap-parser.c" "main.c" "secret.c" "u2f.c" "ctap.c" "common.c" "fs.c" - "crypto/ecc.c" "crypto/hmac.c" "crypto/algo.c" "crypto/sha.c" "crypto/sha3.c" "crypto/memzero.c" "crypto/rand.c" "crypto/sm3.c" "crypto/block-cipher.c" "crypto/aes.c" + "crypto/ecc.c" "crypto/hmac.c" "crypto/algo.c" "crypto/sha.c" "crypto/sha3.c" "crypto/memzero.c" "crypto/rand.c" "crypto/sm3.c" "crypto/block-cipher.c" "crypto/aes.c" "crypto/esp32_ed25519.c" "littlefs/lfs.c" "littlefs/lfs_util.c" - "c25519/edsign.c" "c25519/ed25519.c" "c25519/f25519.c" "c25519/fprime.c" - INCLUDE_DIRS "." "crypto/include" "littlefs" "c25519" + INCLUDE_DIRS "." "crypto/include" "littlefs" REQUIRES driver mbedtls efuse esp_partition esp_timer EMBED_FILES "cert/u2f_cert.bin" "cert/u2f_cert_key.bin" "cert/u2f_aaguid.bin" ) diff --git a/main/c25519/ed25519.c b/main/c25519/ed25519.c deleted file mode 100644 index 51ac462..0000000 --- a/main/c25519/ed25519.c +++ /dev/null @@ -1,320 +0,0 @@ -/* Edwards curve operations - * Daniel Beer , 9 Jan 2014 - * - * This file is in the public domain. - */ - -#include "ed25519.h" - -/* Base point is (numbers wrapped): - * - * x = 151122213495354007725011514095885315114 - * 54012693041857206046113283949847762202 - * y = 463168356949264781694283940034751631413 - * 07993866256225615783033603165251855960 - * - * y is derived by transforming the original Montgomery base (u=9). x - * is the corresponding positive coordinate for the new curve equation. - * t is x*y. - */ -const struct ed25519_pt ed25519_base = { - .x = { - 0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, - 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, - 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, - 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21 - }, - .y = { - 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 - }, - .t = { - 0xa3, 0xdd, 0xb7, 0xa5, 0xb3, 0x8a, 0xde, 0x6d, - 0xf5, 0x52, 0x51, 0x77, 0x80, 0x9f, 0xf0, 0x20, - 0x7d, 0xe3, 0xab, 0x64, 0x8e, 0x4e, 0xea, 0x66, - 0x65, 0x76, 0x8b, 0xd7, 0x0f, 0x5f, 0x87, 0x67 - }, - .z = {1, 0} -}; - -const struct ed25519_pt ed25519_neutral = { - .x = {0}, - .y = {1, 0}, - .t = {0}, - .z = {1, 0} -}; - -/* Conversion to and from projective coordinates */ -void ed25519_project(struct ed25519_pt *p, - const uint8_t *x, const uint8_t *y) -{ - f25519_copy(p->x, x); - f25519_copy(p->y, y); - f25519_load(p->z, 1); - f25519_mul__distinct(p->t, x, y); -} - -void ed25519_unproject(uint8_t *x, uint8_t *y, - const struct ed25519_pt *p) -{ - uint8_t z1[F25519_SIZE]; - - f25519_inv__distinct(z1, p->z); - f25519_mul__distinct(x, p->x, z1); - f25519_mul__distinct(y, p->y, z1); - - f25519_normalize(x); - f25519_normalize(y); -} - -/* Compress/uncompress points. We compress points by storing the x - * coordinate and the parity of the y coordinate. - * - * Rearranging the curve equation, we obtain explicit formulae for the - * coordinates: - * - * x = sqrt((y^2-1) / (1+dy^2)) - * y = sqrt((x^2+1) / (1-dx^2)) - * - * Where d = (-121665/121666), or: - * - * d = 370957059346694393431380835087545651895 - * 42113879843219016388785533085940283555 - */ - -static const uint8_t ed25519_d[F25519_SIZE] = { - 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, - 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00, - 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, - 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52 -}; - -void ed25519_pack(uint8_t *c, const uint8_t *x, const uint8_t *y) -{ - uint8_t tmp[F25519_SIZE]; - uint8_t parity; - - f25519_copy(tmp, x); - f25519_normalize(tmp); - parity = (tmp[0] & 1) << 7; - - f25519_copy(c, y); - f25519_normalize(c); - c[31] |= parity; -} - -uint8_t ed25519_try_unpack(uint8_t *x, uint8_t *y, const uint8_t *comp) -{ - const int parity = comp[31] >> 7; - uint8_t a[F25519_SIZE]; - uint8_t b[F25519_SIZE]; - uint8_t c[F25519_SIZE]; - - /* Unpack y */ - f25519_copy(y, comp); - y[31] &= 127; - - /* Compute c = y^2 */ - f25519_mul__distinct(c, y, y); - - /* Compute b = (1+dy^2)^-1 */ - f25519_mul__distinct(b, c, ed25519_d); - f25519_add(a, b, f25519_one); - f25519_inv__distinct(b, a); - - /* Compute a = y^2-1 */ - f25519_sub(a, c, f25519_one); - - /* Compute c = a*b = (y^2-1)/(1-dy^2) */ - f25519_mul__distinct(c, a, b); - - /* Compute a, b = +/-sqrt(c), if c is square */ - f25519_sqrt(a, c); - f25519_neg(b, a); - - /* Select one of them, based on the compressed parity bit */ - f25519_select(x, a, b, (a[0] ^ parity) & 1); - - /* Verify that x^2 = c */ - f25519_mul__distinct(a, x, x); - f25519_normalize(a); - f25519_normalize(c); - - return f25519_eq(a, c); -} - -/* k = 2d */ -static const uint8_t ed25519_k[F25519_SIZE] = { - 0x59, 0xf1, 0xb2, 0x26, 0x94, 0x9b, 0xd6, 0xeb, - 0x56, 0xb1, 0x83, 0x82, 0x9a, 0x14, 0xe0, 0x00, - 0x30, 0xd1, 0xf3, 0xee, 0xf2, 0x80, 0x8e, 0x19, - 0xe7, 0xfc, 0xdf, 0x56, 0xdc, 0xd9, 0x06, 0x24 -}; - -void ed25519_add(struct ed25519_pt *r, - const struct ed25519_pt *p1, const struct ed25519_pt *p2) -{ - /* Explicit formulas database: add-2008-hwcd-3 - * - * source 2008 Hisil--Wong--Carter--Dawson, - * http://eprint.iacr.org/2008/522, Section 3.1 - * appliesto extended-1 - * parameter k - * assume k = 2 d - * compute A = (Y1-X1)(Y2-X2) - * compute B = (Y1+X1)(Y2+X2) - * compute C = T1 k T2 - * compute D = Z1 2 Z2 - * compute E = B - A - * compute F = D - C - * compute G = D + C - * compute H = B + A - * compute X3 = E F - * compute Y3 = G H - * compute T3 = E H - * compute Z3 = F G - */ - uint8_t a[F25519_SIZE]; - uint8_t b[F25519_SIZE]; - uint8_t c[F25519_SIZE]; - uint8_t d[F25519_SIZE]; - uint8_t e[F25519_SIZE]; - uint8_t f[F25519_SIZE]; - uint8_t g[F25519_SIZE]; - uint8_t h[F25519_SIZE]; - - /* A = (Y1-X1)(Y2-X2) */ - f25519_sub(c, p1->y, p1->x); - f25519_sub(d, p2->y, p2->x); - f25519_mul__distinct(a, c, d); - - /* B = (Y1+X1)(Y2+X2) */ - f25519_add(c, p1->y, p1->x); - f25519_add(d, p2->y, p2->x); - f25519_mul__distinct(b, c, d); - - /* C = T1 k T2 */ - f25519_mul__distinct(d, p1->t, p2->t); - f25519_mul__distinct(c, d, ed25519_k); - - /* D = Z1 2 Z2 */ - f25519_mul__distinct(d, p1->z, p2->z); - f25519_add(d, d, d); - - /* E = B - A */ - f25519_sub(e, b, a); - - /* F = D - C */ - f25519_sub(f, d, c); - - /* G = D + C */ - f25519_add(g, d, c); - - /* H = B + A */ - f25519_add(h, b, a); - - /* X3 = E F */ - f25519_mul__distinct(r->x, e, f); - - /* Y3 = G H */ - f25519_mul__distinct(r->y, g, h); - - /* T3 = E H */ - f25519_mul__distinct(r->t, e, h); - - /* Z3 = F G */ - f25519_mul__distinct(r->z, f, g); -} - -void ed25519_double(struct ed25519_pt *r, const struct ed25519_pt *p) -{ - /* Explicit formulas database: dbl-2008-hwcd - * - * source 2008 Hisil--Wong--Carter--Dawson, - * http://eprint.iacr.org/2008/522, Section 3.3 - * compute A = X1^2 - * compute B = Y1^2 - * compute C = 2 Z1^2 - * compute D = a A - * compute E = (X1+Y1)^2-A-B - * compute G = D + B - * compute F = G - C - * compute H = D - B - * compute X3 = E F - * compute Y3 = G H - * compute T3 = E H - * compute Z3 = F G - */ - uint8_t a[F25519_SIZE]; - uint8_t b[F25519_SIZE]; - uint8_t c[F25519_SIZE]; - uint8_t e[F25519_SIZE]; - uint8_t f[F25519_SIZE]; - uint8_t g[F25519_SIZE]; - uint8_t h[F25519_SIZE]; - - /* A = X1^2 */ - f25519_mul__distinct(a, p->x, p->x); - - /* B = Y1^2 */ - f25519_mul__distinct(b, p->y, p->y); - - /* C = 2 Z1^2 */ - f25519_mul__distinct(c, p->z, p->z); - f25519_add(c, c, c); - - /* D = a A (alter sign) */ - /* E = (X1+Y1)^2-A-B */ - f25519_add(f, p->x, p->y); - f25519_mul__distinct(e, f, f); - f25519_sub(e, e, a); - f25519_sub(e, e, b); - - /* G = D + B */ - f25519_sub(g, b, a); - - /* F = G - C */ - f25519_sub(f, g, c); - - /* H = D - B */ - f25519_neg(h, b); - f25519_sub(h, h, a); - - /* X3 = E F */ - f25519_mul__distinct(r->x, e, f); - - /* Y3 = G H */ - f25519_mul__distinct(r->y, g, h); - - /* T3 = E H */ - f25519_mul__distinct(r->t, e, h); - - /* Z3 = F G */ - f25519_mul__distinct(r->z, f, g); -} - -void ed25519_smult(struct ed25519_pt *r_out, const struct ed25519_pt *p, - const uint8_t *e) -{ - struct ed25519_pt r; - int i; - - ed25519_copy(&r, &ed25519_neutral); - - for (i = 255; i >= 0; i--) { - const uint8_t bit = (e[i >> 3] >> (i & 7)) & 1; - struct ed25519_pt s; - - ed25519_double(&r, &r); - ed25519_add(&s, &r, p); - - f25519_select(r.x, r.x, s.x, bit); - f25519_select(r.y, r.y, s.y, bit); - f25519_select(r.z, r.z, s.z, bit); - f25519_select(r.t, r.t, s.t, bit); - } - - ed25519_copy(r_out, &r); -} diff --git a/main/c25519/ed25519.h b/main/c25519/ed25519.h deleted file mode 100644 index 62f0120..0000000 --- a/main/c25519/ed25519.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Edwards curve operations - * Daniel Beer , 9 Jan 2014 - * - * This file is in the public domain. - */ - -#ifndef ED25519_H_ -#define ED25519_H_ - -#include "f25519.h" - -/* This is not the Ed25519 signature system. Rather, we're implementing - * basic operations on the twisted Edwards curve over (Z mod 2^255-19): - * - * -x^2 + y^2 = 1 - (121665/121666)x^2y^2 - * - * With the positive-x base point y = 4/5. - * - * These functions will not leak secret data through timing. - * - * For more information, see: - * - * Bernstein, D.J. & Lange, T. (2007) "Faster addition and doubling on - * elliptic curves". Document ID: 95616567a6ba20f575c5f25e7cebaf83. - * - * Hisil, H. & Wong, K K. & Carter, G. & Dawson, E. (2008) "Twisted - * Edwards curves revisited". Advances in Cryptology, ASIACRYPT 2008, - * Vol. 5350, pp. 326-343. - */ - -/* Projective coordinates */ -struct ed25519_pt { - uint8_t x[F25519_SIZE]; - uint8_t y[F25519_SIZE]; - uint8_t t[F25519_SIZE]; - uint8_t z[F25519_SIZE]; -}; - -extern const struct ed25519_pt ed25519_base; -extern const struct ed25519_pt ed25519_neutral; - -/* Convert between projective and affine coordinates (x/y in F25519) */ -void ed25519_project(struct ed25519_pt *p, - const uint8_t *x, const uint8_t *y); - -void ed25519_unproject(uint8_t *x, uint8_t *y, - const struct ed25519_pt *p); - -/* Compress/uncompress points. try_unpack() will check that the - * compressed point is on the curve, returning 1 if the unpacked point - * is valid, and 0 otherwise. - */ -#define ED25519_PACK_SIZE F25519_SIZE - -void ed25519_pack(uint8_t *c, const uint8_t *x, const uint8_t *y); -uint8_t ed25519_try_unpack(uint8_t *x, uint8_t *y, const uint8_t *c); - -/* Add, double and scalar multiply */ -#define ED25519_EXPONENT_SIZE 32 - -/* Prepare an exponent by clamping appropriate bits */ -static inline void ed25519_prepare(uint8_t *e) -{ - e[0] &= 0xf8; - e[31] &= 0x7f; - e[31] |= 0x40; -} - -/* Order of the group generated by the base point */ -static inline void ed25519_copy(struct ed25519_pt *dst, - const struct ed25519_pt *src) -{ - memcpy(dst, src, sizeof(*dst)); -} - -void ed25519_add(struct ed25519_pt *r, - const struct ed25519_pt *a, const struct ed25519_pt *b); -void ed25519_double(struct ed25519_pt *r, const struct ed25519_pt *a); -void ed25519_smult(struct ed25519_pt *r, const struct ed25519_pt *a, - const uint8_t *e); - -#endif diff --git a/main/c25519/edsign.c b/main/c25519/edsign.c deleted file mode 100644 index 8b61be1..0000000 --- a/main/c25519/edsign.c +++ /dev/null @@ -1,172 +0,0 @@ -/* Edwards curve signature system - * Daniel Beer , 22 Apr 2014 - * - * This file is in the public domain. - */ - -#include "ed25519.h" -#include "fprime.h" -#include "edsign.h" -#include "mbedtls/sha512.h" - -#define EXPANDED_SIZE 64 - -static const uint8_t ed25519_order[FPRIME_SIZE] = { - 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, - 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 -}; - -static void expand_key(uint8_t *expanded, const uint8_t *secret) -{ - - mbedtls_sha512_context sha512; - mbedtls_sha512_init(&sha512); - mbedtls_sha512_starts(&sha512, 0); - mbedtls_sha512_update(&sha512, secret, EDSIGN_SECRET_KEY_SIZE); - mbedtls_sha512_finish(&sha512,expanded); - mbedtls_sha512_free(&sha512); - - ed25519_prepare(expanded); -} - -static uint8_t upp(struct ed25519_pt *p, const uint8_t *packed) -{ - uint8_t x[F25519_SIZE]; - uint8_t y[F25519_SIZE]; - uint8_t ok = ed25519_try_unpack(x, y, packed); - - ed25519_project(p, x, y); - return ok; -} - -static void pp(uint8_t *packed, const struct ed25519_pt *p) -{ - uint8_t x[F25519_SIZE]; - uint8_t y[F25519_SIZE]; - - ed25519_unproject(x, y, p); - ed25519_pack(packed, x, y); -} - -static void sm_pack(uint8_t *r, const uint8_t *k) -{ - struct ed25519_pt p; - - ed25519_smult(&p, &ed25519_base, k); - pp(r, &p); -} - -void edsign_sec_to_pub(uint8_t *pub, const uint8_t *secret) -{ - uint8_t expanded[EXPANDED_SIZE]; - - expand_key(expanded, secret); - sm_pack(pub, expanded); -} - -static void hash_with_prefix(uint8_t *out_fp, - uint8_t *init_block, unsigned int prefix_size, - const uint8_t *message, size_t len) -{ - mbedtls_sha512_context sha512; - - mbedtls_sha512_init(&sha512); - mbedtls_sha512_starts(&sha512, 0); - - if (len < 64 && len + prefix_size < 64) { - memcpy(init_block + prefix_size, message, len); - mbedtls_sha512_update(&sha512, init_block, len + prefix_size); - } else { - size_t i; - - memcpy(init_block + prefix_size, message, - 64 - prefix_size); - mbedtls_sha512_update(&sha512, init_block, 128); - - for (i = 64 - prefix_size; - i + 64 <= len; - i += 64) - mbedtls_sha512_update(&sha512, message + i, 128); - - mbedtls_sha512_update(&sha512, message + i,len + prefix_size); - } - mbedtls_sha512_finish(&sha512,init_block); - mbedtls_sha512_free(&sha512); - fprime_from_bytes(out_fp, init_block, 64, ed25519_order); -} - -static void generate_k(uint8_t *k, const uint8_t *kgen_key, - const uint8_t *message, size_t len) -{ - uint8_t block[64]; - - memcpy(block, kgen_key, 32); - hash_with_prefix(k, block, 32, message, len); -} - -static void hash_message(uint8_t *z, const uint8_t *r, const uint8_t *a, - const uint8_t *m, size_t len) -{ - uint8_t block[64]; - - memcpy(block, r, 32); - memcpy(block + 32, a, 32); - hash_with_prefix(z, block, 64, m, len); -} - -void edsign_sign(uint8_t *signature, const uint8_t *pub, - const uint8_t *secret, - const uint8_t *message, size_t len) -{ - uint8_t expanded[EXPANDED_SIZE]; - uint8_t e[FPRIME_SIZE]; - uint8_t s[FPRIME_SIZE]; - uint8_t k[FPRIME_SIZE]; - uint8_t z[FPRIME_SIZE]; - - expand_key(expanded, secret); - - /* Generate k and R = kB */ - generate_k(k, expanded + 32, message, len); - sm_pack(signature, k); - - /* Compute z = H(R, A, M) */ - hash_message(z, signature, pub, message, len); - - /* Obtain e */ - fprime_from_bytes(e, expanded, 32, ed25519_order); - - /* Compute s = ze + k */ - fprime_mul(s, z, e, ed25519_order); - fprime_add(s, k, ed25519_order); - memcpy(signature + 32, s, 32); -} - -uint8_t edsign_verify(const uint8_t *signature, const uint8_t *pub, - const uint8_t *message, size_t len) -{ - struct ed25519_pt p; - struct ed25519_pt q; - uint8_t lhs[F25519_SIZE]; - uint8_t rhs[F25519_SIZE]; - uint8_t z[FPRIME_SIZE]; - uint8_t ok = 1; - - /* Compute z = H(R, A, M) */ - hash_message(z, signature, pub, message, len); - - /* sB = (ze + k)B = ... */ - sm_pack(lhs, signature + 32); - - /* ... = zA + R */ - ok &= upp(&p, pub); - ed25519_smult(&p, &p, z); - ok &= upp(&q, signature); - ed25519_add(&p, &p, &q); - pp(rhs, &p); - - /* Equal? */ - return ok & f25519_eq(lhs, rhs); -} diff --git a/main/c25519/edsign.h b/main/c25519/edsign.h deleted file mode 100644 index 85e2208..0000000 --- a/main/c25519/edsign.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Edwards curve signature system - * Daniel Beer , 22 Apr 2014 - * - * This file is in the public domain. - */ - -#ifndef EDSIGN_H_ -#define EDSIGN_H_ - -#include -#include - -/* This is the Ed25519 signature system, as described in: - * - * Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, Bo-Yin - * Yang. High-speed high-security signatures. Journal of Cryptographic - * Engineering 2 (2012), 77-89. Document ID: - * a1a62a2f76d23f65d622484ddd09caf8. URL: - * http://cr.yp.to/papers.html#ed25519. Date: 2011.09.26. - * - * The format and calculation of signatures is compatible with the - * Ed25519 implementation in SUPERCOP. Note, however, that our secret - * keys are half the size: we don't store a copy of the public key in - * the secret key (we generate it on demand). - */ - -/* Any string of 32 random bytes is a valid secret key. There is no - * clamping of bits, because we don't use the key directly as an - * exponent (the exponent is derived from part of a key expansion). - */ -#define EDSIGN_SECRET_KEY_SIZE 32 - -/* Given a secret key, produce the public key (a packed Edwards-curve - * point). - */ -#define EDSIGN_PUBLIC_KEY_SIZE 32 - -void edsign_sec_to_pub(uint8_t *pub, const uint8_t *secret); - -/* Produce a signature for a message. */ -#define EDSIGN_SIGNATURE_SIZE 64 - -void edsign_sign(uint8_t *signature, const uint8_t *pub, - const uint8_t *secret, - const uint8_t *message, size_t len); - -/* Verify a message signature. Returns non-zero if ok. */ -uint8_t edsign_verify(const uint8_t *signature, const uint8_t *pub, - const uint8_t *message, size_t len); - -#endif diff --git a/main/c25519/f25519.c b/main/c25519/f25519.c deleted file mode 100644 index 3b06fa6..0000000 --- a/main/c25519/f25519.c +++ /dev/null @@ -1,324 +0,0 @@ -/* Arithmetic mod p = 2^255-19 - * Daniel Beer , 5 Jan 2014 - * - * This file is in the public domain. - */ - -#include "f25519.h" - -const uint8_t f25519_zero[F25519_SIZE] = {0}; -const uint8_t f25519_one[F25519_SIZE] = {1}; - -void f25519_load(uint8_t *x, uint32_t c) -{ - unsigned int i; - - for (i = 0; i < sizeof(c); i++) { - x[i] = c; - c >>= 8; - } - - for (; i < F25519_SIZE; i++) - x[i] = 0; -} - -void f25519_normalize(uint8_t *x) -{ - uint8_t minusp[F25519_SIZE]; - uint16_t c; - int i; - - /* Reduce using 2^255 = 19 mod p */ - c = (x[31] >> 7) * 19; - x[31] &= 127; - - for (i = 0; i < F25519_SIZE; i++) { - c += x[i]; - x[i] = c; - c >>= 8; - } - - /* The number is now less than 2^255 + 18, and therefore less than - * 2p. Try subtracting p, and conditionally load the subtracted - * value if underflow did not occur. - */ - c = 19; - - for (i = 0; i + 1 < F25519_SIZE; i++) { - c += x[i]; - minusp[i] = c; - c >>= 8; - } - - c += ((uint16_t)x[i]) - 128; - minusp[31] = c; - - /* Load x-p if no underflow */ - f25519_select(x, minusp, x, (c >> 15) & 1); -} - -uint8_t f25519_eq(const uint8_t *x, const uint8_t *y) -{ - uint8_t sum = 0; - int i; - - for (i = 0; i < F25519_SIZE; i++) - sum |= x[i] ^ y[i]; - - sum |= (sum >> 4); - sum |= (sum >> 2); - sum |= (sum >> 1); - - return (sum ^ 1) & 1; -} - -void f25519_select(uint8_t *dst, - const uint8_t *zero, const uint8_t *one, - uint8_t condition) -{ - const uint8_t mask = -condition; - int i; - - for (i = 0; i < F25519_SIZE; i++) - dst[i] = zero[i] ^ (mask & (one[i] ^ zero[i])); -} - -void f25519_add(uint8_t *r, const uint8_t *a, const uint8_t *b) -{ - uint16_t c = 0; - int i; - - /* Add */ - for (i = 0; i < F25519_SIZE; i++) { - c >>= 8; - c += ((uint16_t)a[i]) + ((uint16_t)b[i]); - r[i] = c; - } - - /* Reduce with 2^255 = 19 mod p */ - r[31] &= 127; - c = (c >> 7) * 19; - - for (i = 0; i < F25519_SIZE; i++) { - c += r[i]; - r[i] = c; - c >>= 8; - } -} - -void f25519_sub(uint8_t *r, const uint8_t *a, const uint8_t *b) -{ - uint32_t c = 0; - int i; - - /* Calculate a + 2p - b, to avoid underflow */ - c = 218; - for (i = 0; i + 1 < F25519_SIZE; i++) { - c += 65280 + ((uint32_t)a[i]) - ((uint32_t)b[i]); - r[i] = c; - c >>= 8; - } - - c += ((uint32_t)a[31]) - ((uint32_t)b[31]); - r[31] = c & 127; - c = (c >> 7) * 19; - - for (i = 0; i < F25519_SIZE; i++) { - c += r[i]; - r[i] = c; - c >>= 8; - } -} - -void f25519_neg(uint8_t *r, const uint8_t *a) -{ - uint32_t c = 0; - int i; - - /* Calculate 2p - a, to avoid underflow */ - c = 218; - for (i = 0; i + 1 < F25519_SIZE; i++) { - c += 65280 - ((uint32_t)a[i]); - r[i] = c; - c >>= 8; - } - - c -= ((uint32_t)a[31]); - r[31] = c & 127; - c = (c >> 7) * 19; - - for (i = 0; i < F25519_SIZE; i++) { - c += r[i]; - r[i] = c; - c >>= 8; - } -} - -void f25519_mul__distinct(uint8_t *r, const uint8_t *a, const uint8_t *b) -{ - uint32_t c = 0; - int i; - - for (i = 0; i < F25519_SIZE; i++) { - int j; - - c >>= 8; - for (j = 0; j <= i; j++) - c += ((uint32_t)a[j]) * ((uint32_t)b[i - j]); - - for (; j < F25519_SIZE; j++) - c += ((uint32_t)a[j]) * - ((uint32_t)b[i + F25519_SIZE - j]) * 38; - - r[i] = c; - } - - r[31] &= 127; - c = (c >> 7) * 19; - - for (i = 0; i < F25519_SIZE; i++) { - c += r[i]; - r[i] = c; - c >>= 8; - } -} - -void f25519_mul(uint8_t *r, const uint8_t *a, const uint8_t *b) -{ - uint8_t tmp[F25519_SIZE]; - - f25519_mul__distinct(tmp, a, b); - f25519_copy(r, tmp); -} - -void f25519_mul_c(uint8_t *r, const uint8_t *a, uint32_t b) -{ - uint32_t c = 0; - int i; - - for (i = 0; i < F25519_SIZE; i++) { - c >>= 8; - c += b * ((uint32_t)a[i]); - r[i] = c; - } - - r[31] &= 127; - c >>= 7; - c *= 19; - - for (i = 0; i < F25519_SIZE; i++) { - c += r[i]; - r[i] = c; - c >>= 8; - } -} - -void f25519_inv__distinct(uint8_t *r, const uint8_t *x) -{ - uint8_t s[F25519_SIZE]; - int i; - - /* This is a prime field, so by Fermat's little theorem: - * - * x^(p-1) = 1 mod p - * - * Therefore, raise to (p-2) = 2^255-21 to get a multiplicative - * inverse. - * - * This is a 255-bit binary number with the digits: - * - * 11111111... 01011 - * - * We compute the result by the usual binary chain, but - * alternate between keeping the accumulator in r and s, so as - * to avoid copying temporaries. - */ - - /* 1 1 */ - f25519_mul__distinct(s, x, x); - f25519_mul__distinct(r, s, x); - - /* 1 x 248 */ - for (i = 0; i < 248; i++) { - f25519_mul__distinct(s, r, r); - f25519_mul__distinct(r, s, x); - } - - /* 0 */ - f25519_mul__distinct(s, r, r); - - /* 1 */ - f25519_mul__distinct(r, s, s); - f25519_mul__distinct(s, r, x); - - /* 0 */ - f25519_mul__distinct(r, s, s); - - /* 1 */ - f25519_mul__distinct(s, r, r); - f25519_mul__distinct(r, s, x); - - /* 1 */ - f25519_mul__distinct(s, r, r); - f25519_mul__distinct(r, s, x); -} - -void f25519_inv(uint8_t *r, const uint8_t *x) -{ - uint8_t tmp[F25519_SIZE]; - - f25519_inv__distinct(tmp, x); - f25519_copy(r, tmp); -} - -/* Raise x to the power of (p-5)/8 = 2^252-3, using s for temporary - * storage. - */ -static void exp2523(uint8_t *r, const uint8_t *x, uint8_t *s) -{ - int i; - - /* This number is a 252-bit number with the binary expansion: - * - * 111111... 01 - */ - - /* 1 1 */ - f25519_mul__distinct(r, x, x); - f25519_mul__distinct(s, r, x); - - /* 1 x 248 */ - for (i = 0; i < 248; i++) { - f25519_mul__distinct(r, s, s); - f25519_mul__distinct(s, r, x); - } - - /* 0 */ - f25519_mul__distinct(r, s, s); - - /* 1 */ - f25519_mul__distinct(s, r, r); - f25519_mul__distinct(r, s, x); -} - -void f25519_sqrt(uint8_t *r, const uint8_t *a) -{ - uint8_t v[F25519_SIZE]; - uint8_t i[F25519_SIZE]; - uint8_t x[F25519_SIZE]; - uint8_t y[F25519_SIZE]; - - /* v = (2a)^((p-5)/8) [x = 2a] */ - f25519_mul_c(x, a, 2); - exp2523(v, x, y); - - /* i = 2av^2 - 1 */ - f25519_mul__distinct(y, v, v); - f25519_mul__distinct(i, x, y); - f25519_load(y, 1); - f25519_sub(i, i, y); - - /* r = avi */ - f25519_mul__distinct(x, v, a); - f25519_mul__distinct(r, x, i); -} diff --git a/main/c25519/f25519.h b/main/c25519/f25519.h deleted file mode 100644 index 4cfa5ec..0000000 --- a/main/c25519/f25519.h +++ /dev/null @@ -1,92 +0,0 @@ -/* Arithmetic mod p = 2^255-19 - * Daniel Beer , 8 Jan 2014 - * - * This file is in the public domain. - */ - -#ifndef F25519_H_ -#define F25519_H_ - -#include -#include - -/* Field elements are represented as little-endian byte strings. All - * operations have timings which are independent of input data, so they - * can be safely used for cryptography. - * - * Computation is performed on un-normalized elements. These are byte - * strings which fall into the range 0 <= x < 2p. Use f25519_normalize() - * to convert to a value 0 <= x < p. - * - * Elements received from the outside may greater even than 2p. - * f25519_normalize() will correctly deal with these numbers too. - */ -#define F25519_SIZE 32 - -/* Identity constants */ -extern const uint8_t f25519_zero[F25519_SIZE]; -extern const uint8_t f25519_one[F25519_SIZE]; - -/* Load a small constant */ -void f25519_load(uint8_t *x, uint32_t c); - -/* Copy two points */ -static inline void f25519_copy(uint8_t *x, const uint8_t *a) -{ - memcpy(x, a, F25519_SIZE); -} - -/* Normalize a field point x < 2*p by subtracting p if necessary */ -void f25519_normalize(uint8_t *x); - -/* Compare two field points in constant time. Return one if equal, zero - * otherwise. This should be performed only on normalized values. - */ -uint8_t f25519_eq(const uint8_t *x, const uint8_t *y); - -/* Conditional copy. If condition == 0, then zero is copied to dst. If - * condition == 1, then one is copied to dst. Any other value results in - * undefined behaviour. - */ -void f25519_select(uint8_t *dst, - const uint8_t *zero, const uint8_t *one, - uint8_t condition); - -/* Add/subtract two field points. The three pointers are not required to - * be distinct. - */ -void f25519_add(uint8_t *r, const uint8_t *a, const uint8_t *b); -void f25519_sub(uint8_t *r, const uint8_t *a, const uint8_t *b); - -/* Unary negation */ -void f25519_neg(uint8_t *r, const uint8_t *a); - -/* Multiply two field points. The __distinct variant is used when r is - * known to be in a different location to a and b. - */ -void f25519_mul(uint8_t *r, const uint8_t *a, const uint8_t *b); -void f25519_mul__distinct(uint8_t *r, const uint8_t *a, const uint8_t *b); - -/* Multiply a point by a small constant. The two pointers are not - * required to be distinct. - * - * The constant must be less than 2^24. - */ -void f25519_mul_c(uint8_t *r, const uint8_t *a, uint32_t b); - -/* Take the reciprocal of a field point. The __distinct variant is used - * when r is known to be in a different location to x. - */ -void f25519_inv(uint8_t *r, const uint8_t *x); -void f25519_inv__distinct(uint8_t *r, const uint8_t *x); - -/* Compute one of the square roots of the field element, if the element - * is square. The other square is -r. - * - * If the input is not square, the returned value is a valid field - * element, but not the correct answer. If you don't already know that - * your element is square, you should square the return value and test. - */ -void f25519_sqrt(uint8_t *r, const uint8_t *x); - -#endif diff --git a/main/c25519/fprime.c b/main/c25519/fprime.c deleted file mode 100644 index 4b934ad..0000000 --- a/main/c25519/fprime.c +++ /dev/null @@ -1,215 +0,0 @@ -/* Arithmetic in prime fields - * Daniel Beer , 10 Jan 2014 - * - * This file is in the public domain. - */ - -#include "fprime.h" - -const uint8_t fprime_zero[FPRIME_SIZE] = {0}; -const uint8_t fprime_one[FPRIME_SIZE] = {1}; - -static void raw_add(uint8_t *x, const uint8_t *p) -{ - uint16_t c = 0; - int i; - - for (i = 0; i < FPRIME_SIZE; i++) { - c += ((uint16_t)x[i]) + ((uint16_t)p[i]); - x[i] = c; - c >>= 8; - } -} - -static void raw_try_sub(uint8_t *x, const uint8_t *p) -{ - uint8_t minusp[FPRIME_SIZE]; - uint16_t c = 0; - int i; - - for (i = 0; i < FPRIME_SIZE; i++) { - c = ((uint16_t)x[i]) - ((uint16_t)p[i]) - c; - minusp[i] = c; - c = (c >> 8) & 1; - } - - fprime_select(x, minusp, x, c); -} - -/* Warning: this function is variable-time */ -static int prime_msb(const uint8_t *p) -{ - int i; - uint8_t x; - - for (i = FPRIME_SIZE - 1; i >= 0; i--) - if (p[i]) - break; - - x = p[i]; - i <<= 3; - - while (x) { - x >>= 1; - i++; - } - - return i - 1; -} - -/* Warning: this function may be variable-time in the argument n */ -static void shift_n_bits(uint8_t *x, int n) -{ - uint16_t c = 0; - int i; - - for (i = 0; i < FPRIME_SIZE; i++) { - c |= ((uint16_t)x[i]) << n; - x[i] = c; - c >>= 8; - } -} - -void fprime_load(uint8_t *x, uint32_t c) -{ - unsigned int i; - - for (i = 0; i < sizeof(c); i++) { - x[i] = c; - c >>= 8; - } - - for (; i < FPRIME_SIZE; i++) - x[i] = 0; -} - -static inline int min_int(int a, int b) -{ - return a < b ? a : b; -} - -void fprime_from_bytes(uint8_t *r, - const uint8_t *x, size_t len, - const uint8_t *modulus) -{ - const int preload_total = min_int(prime_msb(modulus) - 1, len << 3); - const int preload_bytes = preload_total >> 3; - const int preload_bits = preload_total & 7; - const int rbits = (len << 3) - preload_total; - int i; - - memset(r, 0, FPRIME_SIZE); - - for (i = 0; i < preload_bytes; i++) - r[i] = x[len - preload_bytes + i]; - - if (preload_bits) { - shift_n_bits(r, preload_bits); - r[0] |= x[len - preload_bytes - 1] >> (8 - preload_bits); - } - - for (i = rbits - 1; i >= 0; i--) { - const uint8_t bit = (x[i >> 3] >> (i & 7)) & 1; - - shift_n_bits(r, 1); - r[0] |= bit; - raw_try_sub(r, modulus); - } -} - -void fprime_normalize(uint8_t *x, const uint8_t *modulus) -{ - uint8_t r[FPRIME_SIZE]; - - fprime_from_bytes(r, x, FPRIME_SIZE, modulus); - fprime_copy(x, r); -} - -uint8_t fprime_eq(const uint8_t *x, const uint8_t *y) -{ - uint8_t sum = 0; - int i; - - for (i = 0; i < FPRIME_SIZE; i++) - sum |= x[i] ^ y[i]; - - sum |= (sum >> 4); - sum |= (sum >> 2); - sum |= (sum >> 1); - - return (sum ^ 1) & 1; -} - -void fprime_select(uint8_t *dst, - const uint8_t *zero, const uint8_t *one, - uint8_t condition) -{ - const uint8_t mask = -condition; - int i; - - for (i = 0; i < FPRIME_SIZE; i++) - dst[i] = zero[i] ^ (mask & (one[i] ^ zero[i])); -} - -void fprime_add(uint8_t *r, const uint8_t *a, const uint8_t *modulus) -{ - raw_add(r, a); - raw_try_sub(r, modulus); -} - -void fprime_sub(uint8_t *r, const uint8_t *a, const uint8_t *modulus) -{ - raw_add(r, modulus); - raw_try_sub(r, a); - raw_try_sub(r, modulus); -} - -void fprime_mul(uint8_t *r, const uint8_t *a, const uint8_t *b, - const uint8_t *modulus) -{ - int i; - - memset(r, 0, FPRIME_SIZE); - - for (i = prime_msb(modulus); i >= 0; i--) { - const uint8_t bit = (b[i >> 3] >> (i & 7)) & 1; - uint8_t plusa[FPRIME_SIZE]; - - shift_n_bits(r, 1); - raw_try_sub(r, modulus); - - fprime_copy(plusa, r); - fprime_add(plusa, a, modulus); - - fprime_select(r, r, plusa, bit); - } -} - -void fprime_inv(uint8_t *r, const uint8_t *a, const uint8_t *modulus) -{ - uint8_t pm2[FPRIME_SIZE]; - uint16_t c = 2; - int i; - - /* Compute (p-2) */ - fprime_copy(pm2, modulus); - for (i = 0; i < FPRIME_SIZE; i++) { - c = modulus[i] - c; - pm2[i] = c; - c >>= 8; - } - - /* Binary exponentiation */ - fprime_load(r, 1); - - for (i = prime_msb(modulus); i >= 0; i--) { - uint8_t r2[FPRIME_SIZE]; - - fprime_mul(r2, r, r, modulus); - - if ((pm2[i >> 3] >> (i & 7)) & 1) - fprime_mul(r, r2, a, modulus); - else - fprime_copy(r, r2); - } -} diff --git a/main/c25519/fprime.h b/main/c25519/fprime.h deleted file mode 100644 index fd5df27..0000000 --- a/main/c25519/fprime.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Arithmetic in prime fields - * Daniel Beer , 10 Jan 2014 - * - * This file is in the public domain. - */ - -#ifndef FPRIME_H_ -#define FPRIME_H_ - -#include -#include - -/* Maximum size of a field element (or a prime). Field elements are - * always manipulated and stored in normalized form, with 0 <= x < p. - * You can use normalize() to convert a denormalized bitstring to normal - * form. - * - * Operations are constant with respect to the value of field elements, - * but not with respect to the modulus. - * - * The modulus is a number p, such that 2p-1 fits in FPRIME_SIZE bytes. - */ -#define FPRIME_SIZE 32 - -/* Useful constants */ -extern const uint8_t fprime_zero[FPRIME_SIZE]; -extern const uint8_t fprime_one[FPRIME_SIZE]; - -/* Load a small constant */ -void fprime_load(uint8_t *x, uint32_t c); - -/* Load a large constant x into r */ -void fprime_from_bytes(uint8_t *r, - const uint8_t *x, size_t len, - const uint8_t *modulus); - -/* Copy an element */ -static inline void fprime_copy(uint8_t *x, const uint8_t *a) -{ - memcpy(x, a, FPRIME_SIZE); -} - -/* Normalize a field element */ -void fprime_normalize(uint8_t *x, const uint8_t *modulus); - -/* Compare two field points in constant time. Return one if equal, zero - * otherwise. This should be performed only on normalized values. - */ -uint8_t fprime_eq(const uint8_t *x, const uint8_t *y); - -/* Conditional copy. If condition == 0, then zero is copied to dst. If - * condition == 1, then one is copied to dst. Any other value results in - * undefined behaviour. - */ -void fprime_select(uint8_t *dst, - const uint8_t *zero, const uint8_t *one, - uint8_t condition); - -/* Add one value to another. The two pointers must be distinct. */ -void fprime_add(uint8_t *r, const uint8_t *a, const uint8_t *modulus); -void fprime_sub(uint8_t *r, const uint8_t *a, const uint8_t *modulus); - -/* Multiply two values to get a third. r must be distinct from a and b */ -void fprime_mul(uint8_t *r, const uint8_t *a, const uint8_t *b, - const uint8_t *modulus); - -/* Compute multiplicative inverse. r must be distinct from a */ -void fprime_inv(uint8_t *r, const uint8_t *a, const uint8_t *modulus); - -#endif diff --git a/main/crypto/ecc.c b/main/crypto/ecc.c index faf5f31..c29f06a 100644 --- a/main/crypto/ecc.c +++ b/main/crypto/ecc.c @@ -4,7 +4,7 @@ #include #include #include -#include "edsign.h" +#include "esp32_ed25519.h" const uint8_t SM2_ID_DEFAULT[] = {0x10, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}; @@ -554,13 +554,13 @@ __attribute__((weak)) int K__short_weierstrass_ecdh(key_type_t type, const uint8 } __attribute__((weak)) void K__ed25519_publickey(const K__ed25519_secret_key sk, K__ed25519_public_key pk) { - edsign_sec_to_pub(pk,sk); + ed25519GeneratePublicKey(sk,pk); } __attribute__((weak)) void K__ed25519_sign(const unsigned char *m, size_t mlen, const K__ed25519_secret_key sk, const K__ed25519_public_key pk, K__ed25519_signature rs) { - edsign_sign(rs,pk,sk,m,mlen); + ed25519GenerateSignature(sk,pk,m,mlen,NULL,0,0,rs); } diff --git a/main/crypto/esp32_ed25519.c b/main/crypto/esp32_ed25519.c new file mode 100644 index 0000000..6b49190 --- /dev/null +++ b/main/crypto/esp32_ed25519.c @@ -0,0 +1,978 @@ + +#include "soc/hwcrypto_reg.h" +#include "soc/dport_reg.h" +#include "soc/dport_access.h" +#include "esp_private/periph_ctrl.h" +#include "esp_crypto_lock.h" +#include "esp32_ed25519.h" +#include +#include "mbedtls/sha512.h" + +// Length of the elliptic curve +#define CURVE25519_BIT_LEN 255 +#define CURVE25519_BYTE_LEN 32 +#define CURVE25519_WORD_LEN 8 + +typedef struct +{ + const void *buffer; + size_t length; +} EddsaMessageChunk; + +uint32_t curve25519Sqrt(uint32_t *r, const uint32_t *a, const uint32_t *b); +void curve25519Sqr(uint32_t *r, const uint32_t *a); + +void ed25519Double(Ed25519State *state, Ed25519Point *r, const Ed25519Point *p); +void ed25519Mul(Ed25519State *state, Ed25519Point *r, const uint8_t *k, const Ed25519Point *p); + +// Square root of -1 modulo p (constant) +static const uint32_t CURVE25519_SQRT_MINUS_1[8] = + { + 0x4A0EA0B0, 0xC4EE1B27, 0xAD2FE478, 0x2F431806, + 0x3DFBD7A7, 0x2B4D0099, 0x4FC1DF0B, 0x2B832480}; + +// Base point B +static const Ed25519Point ED25519_B = + { + {0x8F25D51A, 0xC9562D60, 0x9525A7B2, 0x692CC760, + 0xFDD6DC5C, 0xC0A4E231, 0xCD6E53FE, 0x216936D3}, + {0x66666658, 0x66666666, 0x66666666, 0x66666666, + 0x66666666, 0x66666666, 0x66666666, 0x66666666}, + {0x00000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0xA5B7DDA3, 0x6DDE8AB3, 0x775152F5, 0x20F09F80, + 0x64ABE37D, 0x66EA4E8E, 0xD78B7665, 0x67875F0F}}; + +static const uint32_t ED25519_2D[8] = + { + 0x26B2F159, 0xEBD69B94, 0x8283B156, 0x00E0149A, + 0xEEF3D130, 0x198E80F2, 0x56DFFCE7, 0x2406D9DC}; + +// Order of the base point L +static const uint8_t ED25519_L[33] = + { + 0xED, + 0xD3, + 0xF5, + 0x5C, + 0x1A, + 0x63, + 0x12, + 0x58, + 0xD6, + 0x9C, + 0xF7, + 0xA2, + 0xDE, + 0xF9, + 0xDE, + 0x14, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x00, +}; + +// Pre-computed value of mu = b^(2 * k) / L with b = 2^8 and k = 32 +static const uint8_t ED25519_MU[33] = + { + 0x1B, 0x13, 0x2C, 0x0A, 0xA3, 0xE5, 0x9C, 0xED, + 0xA7, 0x29, 0x63, 0x08, 0x5D, 0x21, 0x06, 0x21, + 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x0F}; + +inline uint32_t htole32(uint32_t host_32bits) +{ + return host_32bits; +} + + +void mpi_enable_hardware_hw_op( void ) +{ + esp_crypto_mpi_lock_acquire(); + + /* Enable RSA hardware */ + periph_module_enable(PERIPH_RSA_MODULE); + +#ifdef CONFIG_IDF_TARGET_ESP32S3 + REG_CLR_BIT(SYSTEM_RSA_PD_CTRL_REG, SYSTEM_RSA_MEM_PD); +#elif CONFIG_IDF_TARGET_ESP32S2 + DPORT_REG_CLR_BIT(DPORT_RSA_PD_CTRL_REG, DPORT_RSA_MEM_PD); +#endif + + while (DPORT_REG_READ(RSA_QUERY_CLEAN_REG) != 1) { + } + // Note: from enabling RSA clock to here takes about 1.3us + + REG_WRITE(RSA_INTERRUPT_REG, 0); + +} + + +void mpi_disable_hardware_hw_op( void ) +{ +#ifdef CONFIG_IDF_TARGET_ESP32S3 + REG_SET_BIT(SYSTEM_RSA_PD_CTRL_REG, SYSTEM_RSA_MEM_PD); +#elif CONFIG_IDF_TARGET_ESP32S2 + DPORT_REG_SET_BIT(DPORT_RSA_PD_CTRL_REG, DPORT_RSA_PD); +#endif + /* Disable RSA hardware */ + periph_module_disable(PERIPH_RSA_MODULE); + + esp_crypto_mpi_lock_release(); +} + +static inline void start_op(uint32_t op_reg) +{ + /* Clear interrupt status */ + DPORT_REG_WRITE(RSA_CLEAR_INTERRUPT_REG, 1); + + /* Note: above REG_WRITE includes a memw, so we know any writes + to the memory blocks are also complete. */ + + DPORT_REG_WRITE(op_reg, 1); +} + +static inline void wait_op_complete(void) +{ + while (DPORT_REG_READ(RSA_QUERY_INTERRUPT_REG) != 1) + { } + + /* clear the interrupt */ + DPORT_REG_WRITE(RSA_CLEAR_INTERRUPT_REG, 1); +} + + + +void curve25519Mul(uint32_t *r, const uint32_t *a, const uint32_t *b) +{ + + mpi_enable_hardware_hw_op(); + + uint32_t i; + + // Set mode register + DPORT_REG_WRITE(RSA_LENGTH_REG, 7); + + // Copy the first operand to RSA_X_MEM + for (i = 0; i < 8; i++) + { + DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, a[i]); + } + + // Copy the second operand to RSA_Y_MEM + for (i = 0; i < 8; i++) + { + DPORT_REG_WRITE(RSA_MEM_Y_BLOCK_BASE + i * 4, b[i]); + } + + // Copy the modulus to RSA_M_MEM + DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE, 0xFFFFFFED); + DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 4, 0xFFFFFFFF); + DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 8, 0xFFFFFFFF); + DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 12, 0xFFFFFFFF); + DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 16, 0xFFFFFFFF); + DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 20, 0xFFFFFFFF); + DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 24, 0xFFFFFFFF); + DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 28, 0x7FFFFFFF); + + // Copy the pre-calculated value of R^2 mod M to RSA_Z_MEM + DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE, 0x000005A4); + DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 4, 0x00000000); + DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 8, 0x00000000); + DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 12, 0x00000000); + DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 16, 0x00000000); + DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 20, 0x00000000); + DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 24, 0x00000000); + DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 28, 0x00000000); + + // Write the value of M' to RSA_M_PRIME_REG + DPORT_REG_WRITE(RSA_M_DASH_REG, 0x286BCA1B); + // Start large-number modular multiplication + start_op(RSA_MOD_MULT_START_REG); + + // Wait for the operation to complete + wait_op_complete(); + + // Read the result from RSA_Z_MEM + for (i = 0; i < 8; i++) + { + r[i] = DPORT_SEQUENCE_REG_READ(RSA_MEM_Z_BLOCK_BASE + i * 4); + } + + + mpi_disable_hardware_hw_op(); +} + +void curve25519SetInt(uint32_t *a, uint32_t b) +{ + uint32_t i; + + // Set the value of the least significant word + a[0] = b; + + // Initialize the rest of the integer + for (i = 1; i < 8; i++) + { + a[i] = 0; + } +} + +void curve25519Select(uint32_t *r, const uint32_t *a, const uint32_t *b, + uint32_t c) +{ + uint32_t i; + uint32_t mask; + + // The mask is the all-1 or all-0 word + mask = c - 1; + + // Select between A and B + for (i = 0; i < 8; i++) + { + // Constant time implementation + r[i] = (a[i] & mask) | (b[i] & ~mask); + } +} + +void curve25519Sqr(uint32_t *r, const uint32_t *a) +{ + // Compute R = (A ^ 2) mod p + curve25519Mul(r, a, a); +} + +void curve25519Pwr2(uint32_t *r, const uint32_t *a, uint32_t n) +{ + uint32_t i; + + // Pre-compute (A ^ 2) mod p + curve25519Sqr(r, a); + + // Compute R = (A ^ (2^n)) mod p + for (i = 1; i < n; i++) + { + curve25519Sqr(r, r); + } +} + +uint32_t curve25519Comp(const uint32_t *a, const uint32_t *b) +{ + uint32_t i; + uint32_t mask; + + // Initialize mask + mask = 0; + + // Compare A and B + for (i = 0; i < 8; i++) + { + // Constant time implementation + mask |= a[i] ^ b[i]; + } + + // Return 0 if A = B, else 1 + return ((uint32_t)(mask | (~mask + 1))) >> 31; +} + +void curve25519Red(uint32_t *r, const uint32_t *a) +{ + uint32_t i; + uint64_t temp; + uint32_t b[8]; + + // Compute B = A + 19 + for (temp = 19, i = 0; i < 8; i++) + { + temp += a[i]; + b[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + // Compute B = A - (2^255 - 19) + b[7] -= 0x80000000; + + // If B < (2^255 - 19) then R = B, else R = A + curve25519Select(r, b, a, (b[7] & 0x80000000) >> 31); +} + +void curve25519Add(uint32_t *r, const uint32_t *a, const uint32_t *b) +{ + uint32_t i; + uint64_t temp; + + // Compute R = A + B + for (temp = 0, i = 0; i < 8; i++) + { + temp += a[i]; + temp += b[i]; + r[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + // Perform modular reduction + curve25519Red(r, r); +} + +void curve25519Sub(uint32_t *r, const uint32_t *a, const uint32_t *b) +{ + uint32_t i; + int64_t temp; + + // Compute R = A - 19 - B + for (temp = -19, i = 0; i < 8; i++) + { + temp += a[i]; + temp -= b[i]; + r[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + // Compute R = A + (2^255 - 19) - B + r[7] += 0x80000000; + + // Perform modular reduction + curve25519Red(r, r); +} + +uint32_t curve25519Sqrt(uint32_t *r, const uint32_t *a, const uint32_t *b) +{ + uint32_t res1; + uint32_t res2; + uint32_t c[8]; + uint32_t u[8]; + uint32_t v[8]; + + // Compute the candidate root (A / B)^((p + 3) / 8). This can be done + // with the following trick, using a single modular powering for both the + // inversion of B and the square root: A * B^3 * (A * B^7)^((p - 5) / 8) + curve25519Sqr(v, b); + curve25519Mul(v, v, b); + curve25519Sqr(v, v); + curve25519Mul(v, v, b); + + // Compute C = A * B^7 + curve25519Mul(c, a, v); + + // Compute U = C^((p - 5) / 8) + curve25519Sqr(u, c); + curve25519Mul(u, u, c); // C^(2^2 - 1) + curve25519Sqr(u, u); + curve25519Mul(v, u, c); // C^(2^3 - 1) + curve25519Pwr2(u, v, 3); + curve25519Mul(u, u, v); // C^(2^6 - 1) + curve25519Sqr(u, u); + curve25519Mul(v, u, c); // C^(2^7 - 1) + curve25519Pwr2(u, v, 7); + curve25519Mul(u, u, v); // C^(2^14 - 1) + curve25519Sqr(u, u); + curve25519Mul(v, u, c); // C^(2^15 - 1) + curve25519Pwr2(u, v, 15); + curve25519Mul(u, u, v); // C^(2^30 - 1) + curve25519Sqr(u, u); + curve25519Mul(v, u, c); // C^(2^31 - 1) + curve25519Pwr2(u, v, 31); + curve25519Mul(v, u, v); // C^(2^62 - 1) + curve25519Pwr2(u, v, 62); + curve25519Mul(u, u, v); // C^(2^124 - 1) + curve25519Sqr(u, u); + curve25519Mul(v, u, c); // C^(2^125 - 1) + curve25519Pwr2(u, v, 125); + curve25519Mul(u, u, v); // C^(2^250 - 1) + curve25519Sqr(u, u); + curve25519Sqr(u, u); + curve25519Mul(u, u, c); // C^(2^252 - 3) + + // The first candidate root is U = A * B^3 * (A * B^7)^((p - 5) / 8) + curve25519Mul(u, u, a); + curve25519Sqr(v, b); + curve25519Mul(v, v, b); + curve25519Mul(u, u, v); + + // The second candidate root is V = U * sqrt(-1) + curve25519Mul(v, u, CURVE25519_SQRT_MINUS_1); + + // Calculate C = B * U^2 + curve25519Sqr(c, u); + curve25519Mul(c, c, b); + + // Check whether B * U^2 = A + res1 = curve25519Comp(c, a); + + // Calculate C = B * V^2 + curve25519Sqr(c, v); + curve25519Mul(c, c, b); + + // Check whether B * V^2 = A + res2 = curve25519Comp(c, a); + + // Select the first or the second candidate root + curve25519Select(r, u, v, res1); + + // Return 0 if the square root exists + return res1 & res2; +} + +void curve25519Copy(uint32_t *a, const uint32_t *b) +{ + uint32_t i; + + // Copy the value of the integer + for (i = 0; i < 8; i++) + { + a[i] = b[i]; + } +} + +void curve25519Inv(uint32_t *r, const uint32_t *a) +{ + uint32_t u[8]; + uint32_t v[8]; + + // Since GF(p) is a prime field, the Fermat's little theorem can be + // used to find the multiplicative inverse of A modulo p + curve25519Sqr(u, a); + curve25519Mul(u, u, a); // A^(2^2 - 1) + curve25519Sqr(u, u); + curve25519Mul(v, u, a); // A^(2^3 - 1) + curve25519Pwr2(u, v, 3); + curve25519Mul(u, u, v); // A^(2^6 - 1) + curve25519Sqr(u, u); + curve25519Mul(v, u, a); // A^(2^7 - 1) + curve25519Pwr2(u, v, 7); + curve25519Mul(u, u, v); // A^(2^14 - 1) + curve25519Sqr(u, u); + curve25519Mul(v, u, a); // A^(2^15 - 1) + curve25519Pwr2(u, v, 15); + curve25519Mul(u, u, v); // A^(2^30 - 1) + curve25519Sqr(u, u); + curve25519Mul(v, u, a); // A^(2^31 - 1) + curve25519Pwr2(u, v, 31); + curve25519Mul(v, u, v); // A^(2^62 - 1) + curve25519Pwr2(u, v, 62); + curve25519Mul(u, u, v); // A^(2^124 - 1) + curve25519Sqr(u, u); + curve25519Mul(v, u, a); // A^(2^125 - 1) + curve25519Pwr2(u, v, 125); + curve25519Mul(u, u, v); // A^(2^250 - 1) + curve25519Sqr(u, u); + curve25519Sqr(u, u); + curve25519Mul(u, u, a); // A^(2^252 - 3) + curve25519Sqr(u, u); + curve25519Sqr(u, u); + curve25519Mul(u, u, a); // A^(2^254 - 11) + curve25519Sqr(u, u); + curve25519Mul(r, u, a); // A^(2^255 - 21) +} + +void curve25519Export(uint32_t *a, uint8_t *data) +{ + uint32_t i; + + // Convert from host byte order to little-endian byte order + for (i = 0; i < 8; i++) + { + a[i] = htole32(a[i]); + } + + // Export the octet string + memcpy(data, a, 32); +} + +void ed25519Add(Ed25519State *state, Ed25519Point *r, const Ed25519Point *p, + const Ed25519Point *q) +{ + // Compute A = (Y1 + X1) * (Y2 + X2) + curve25519Add(state->c, p->y, p->x); + curve25519Add(state->d, q->y, q->x); + curve25519Mul(state->a, state->c, state->d); + // Compute B = (Y1 - X1) * (Y2 - X2) + curve25519Sub(state->c, p->y, p->x); + curve25519Sub(state->d, q->y, q->x); + curve25519Mul(state->b, state->c, state->d); + // Compute C = 2 * Z1 * Z2 + curve25519Mul(state->c, p->z, q->z); + curve25519Add(state->c, state->c, state->c); + // Compute D = (2 * d) * T1 * T2 + curve25519Mul(state->d, p->t, q->t); + curve25519Mul(state->d, state->d, ED25519_2D); + // Compute E = A + B + curve25519Add(state->e, state->a, state->b); + // Compute F = A - B + curve25519Sub(state->f, state->a, state->b); + // Compute G = C + D + curve25519Add(state->g, state->c, state->d); + // Compute H = C - D + curve25519Sub(state->h, state->c, state->d); + // Compute X3 = F * H + curve25519Mul(r->x, state->f, state->h); + // Compute Y3 = E * G + curve25519Mul(r->y, state->e, state->g); + // Compute Z3 = G * H + curve25519Mul(r->z, state->g, state->h); + // Compute T3 = E * F + curve25519Mul(r->t, state->e, state->f); +} + +void ed25519Double(Ed25519State *state, Ed25519Point *r, const Ed25519Point *p) +{ + // Compute A = X1^2 + curve25519Sqr(state->a, p->x); + // Compute B = Y1^2 + curve25519Sqr(state->b, p->y); + // Compute C = 2 * Z1^2 + curve25519Sqr(state->c, p->z); + curve25519Add(state->c, state->c, state->c); + // Compute E = A + B + curve25519Add(state->e, state->a, state->b); + // Compute F = E - (X1 + Y1)^2 + curve25519Add(state->f, p->x, p->y); + curve25519Sqr(state->f, state->f); + curve25519Sub(state->f, state->e, state->f); + // Compute G = A - B + curve25519Sub(state->g, state->a, state->b); + // Compute H = C + G + curve25519Add(state->h, state->c, state->g); + // Compute X3 = F * H + curve25519Mul(r->x, state->f, state->h); + // Compute Y3 = E * G + curve25519Mul(r->y, state->e, state->g); + // Compute Z3 = G * H + curve25519Mul(r->z, state->g, state->h); + // Compute T3 = E * F + curve25519Mul(r->t, state->e, state->f); +} + +void ed25519Mul(Ed25519State *state, Ed25519Point *r, + const uint8_t *k, const Ed25519Point *p) +{ + int32_t i; + uint8_t b; + + // The neutral element is represented by (0, 1, 1, 0) + curve25519SetInt(state->u.x, 0); + curve25519SetInt(state->u.y, 1); + curve25519SetInt(state->u.z, 1); + curve25519SetInt(state->u.t, 0); + + // Perform scalar multiplication + for (i = CURVE25519_BIT_LEN - 1; i >= 0; i--) + { + // The scalar is processed in a left-to-right fashion + b = (k[i / 8] >> (i % 8)) & 1; + + // Compute U = 2 * U + ed25519Double(state, &state->u, &state->u); + // Compute V = U + P + ed25519Add(state, &state->v, &state->u, p); + + // If b is set, then U = V + curve25519Select(state->u.x, state->u.x, state->v.x, b); + curve25519Select(state->u.y, state->u.y, state->v.y, b); + curve25519Select(state->u.z, state->u.z, state->v.z, b); + curve25519Select(state->u.t, state->u.t, state->v.t, b); + } + + // Copy result + curve25519Copy(r->x, state->u.x); + curve25519Copy(r->y, state->u.y); + curve25519Copy(r->z, state->u.z); + curve25519Copy(r->t, state->u.t); +} + +void ed25519Encode(Ed25519Point *p, uint8_t *data) +{ + + // Retrieve affine representation + curve25519Inv(p->z, p->z); + curve25519Mul(p->x, p->x, p->z); + curve25519Mul(p->y, p->y, p->z); + curve25519SetInt(p->z, 1); + curve25519Mul(p->t, p->x, p->y); + + // Encode the y-coordinate as a little-endian string of 32 octets. The most + // significant bit of the final octet is always zero + curve25519Export(p->y, data); + + // Copy the least significant bit of the x-coordinate to the most significant + // bit of the final octet + data[31] |= (p->x[0] & 1) << 7; +} + +/** + * @brief Derive the public key from an EdDSA private key + * @param[in] privateKey EdDSA private key (32 bytes) + * @param[out] publicKey EdDSA public key (32 bytes) + * @return Error code + **/ + +int ed25519GeneratePublicKey(const uint8_t *privateKey, uint8_t *publicKey) +{ + + uint8_t *s; + + uint8_t digest[64]; + + Ed25519State *state; + + // Check parameters + if (privateKey == NULL || publicKey == NULL) + return -1; + + // Allocate working state + state = malloc(sizeof(Ed25519State)); + // Failed to allocate memory? + if (state == NULL) + return -1; + + memset(state, 0, sizeof(Ed25519State)); + + // Hash the 32-byte private key using SHA-512 + mbedtls_sha512_context sha512Context; + mbedtls_sha512_init(&sha512Context); + mbedtls_sha512_starts(&sha512Context, 0); + mbedtls_sha512_update(&sha512Context, privateKey, ED25519_PRIVATE_KEY_LEN); + mbedtls_sha512_finish(&sha512Context, digest); + mbedtls_sha512_free(&sha512Context); + + // Only the lower 32 bytes are used for generating the public key. Interpret + // the buffer as the little-endian integer, forming a secret scalar s + s = digest; + + // The lowest three bits of the first octet are cleared, the highest bit + // of the last octet is cleared, and the second highest bit of the last + // octet is set + s[0] &= 0xF8; + s[31] &= 0x7F; + s[31] |= 0x40; + + // Perform a fixed-base scalar multiplication s * B + ed25519Mul(state, &state->sb, s, &ED25519_B); + + // The public key A is the encoding of the point s * B + ed25519Encode(&state->sb, publicKey); + + // Erase working state + memset(state, 0, sizeof(Ed25519State)); + + // Release working state + free(state); + + // Successful processing + return 0; +} + +void ed25519CopyInt(uint8_t *a, const uint8_t *b, uint32_t n) +{ + uint32_t i; + + // Copy the value of the integer + for (i = 0; i < n; i++) + { + a[i] = b[i]; + } +} + +void ed25519SelectInt(uint8_t *r, const uint8_t *a, const uint8_t *b, + uint8_t c, uint32_t n) +{ + uint32_t i; + uint8_t mask; + + // The mask is the all-1 or all-0 word + mask = c - 1; + + // Select between A and B + for (i = 0; i < n; i++) + { + // Constant time implementation + r[i] = (a[i] & mask) | (b[i] & ~mask); + } +} + +void ed25519AddInt(uint8_t *r, const uint8_t *a, const uint8_t *b, uint32_t n) +{ + uint32_t i; + uint16_t temp; + + // Compute R = A + B + for (temp = 0, i = 0; i < n; i++) + { + temp += a[i]; + temp += b[i]; + r[i] = temp & 0xFF; + temp >>= 8; + } +} + +uint8_t ed25519SubInt(uint8_t *r, const uint8_t *a, const uint8_t *b, uint32_t n) +{ + uint32_t i; + int16_t temp; + + // Compute R = A - B + for (temp = 0, i = 0; i < n; i++) + { + temp += a[i]; + temp -= b[i]; + r[i] = temp & 0xFF; + temp >>= 8; + } + + // Return 1 if the result of the subtraction is negative + return temp & 1; +} + +void ed25519MulInt(uint8_t *rl, uint8_t *rh, const uint8_t *a, + const uint8_t *b, uint32_t n) +{ + uint32_t i; + uint32_t j; + uint32_t temp; + + // Compute the low part of the multiplication + for (temp = 0, i = 0; i < n; i++) + { + // The Comba's algorithm computes the products, column by column + for (j = 0; j <= i; j++) + { + temp += (uint16_t)a[j] * b[i - j]; + } + + // At the bottom of each column, the final result is written to memory + if (rl != NULL) + { + rl[i] = temp & 0xFF; + } + + // Propagate the carry upwards + temp >>= 8; + } + + // Check whether the high part of the multiplication should be calculated + if (rh != NULL) + { + // Compute the high part of the multiplication + for (i = n; i < (2 * n); i++) + { + // The Comba's algorithm computes the products, column by column + for (j = i + 1 - n; j < n; j++) + { + temp += (uint16_t)a[j] * b[i - j]; + } + + // At the bottom of each column, the final result is written to memory + rh[i - n] = temp & 0xFF; + + // Propagate the carry upwards + temp >>= 8; + } + } +} + +void ed25519RedInt(uint8_t *r, const uint8_t *a) +{ + uint8_t c; + uint8_t u[33]; + uint8_t v[33]; + + // Compute the estimate of the quotient u = ((a / b^(k - 1)) * mu) / b^(k + 1) + ed25519MulInt(NULL, u, a + 31, ED25519_MU, 33); + // Compute v = u * L mod b^(k + 1) + ed25519MulInt(v, NULL, u, ED25519_L, 33); + + // Compute the estimate of the remainder u = a mod b^(k + 1) - v + // If u < 0, then u = u + b^(k + 1) + ed25519SubInt(u, a, v, 33); + + // This estimation implies that at most two subtractions of L are required to + // obtain the correct remainder r + c = ed25519SubInt(v, u, ED25519_L, 33); + ed25519SelectInt(u, v, u, c, 33); + c = ed25519SubInt(v, u, ED25519_L, 33); + ed25519SelectInt(u, v, u, c, 33); + + // Copy the resulting remainder + ed25519CopyInt(r, u, 32); +} + +int ed25519GenerateSignatureEx(const uint8_t *privateKey, + const uint8_t *publicKey, const EddsaMessageChunk *messageChunks, + const void *context, uint8_t contextLen, uint8_t flag, uint8_t *signature) +{ + uint32_t i; + uint8_t c; + uint8_t digest[64]; + Ed25519State *state; + mbedtls_sha512_context sha512Scontext; + + // Check parameters + if (privateKey == NULL || signature == NULL) + return -1; + if (messageChunks == NULL) + return -1; + if (context == NULL && contextLen != 0) + return -1; + + state = malloc(sizeof(Ed25519State)); + + // Failed to allocate memory? + if (state == NULL) + return -1; + memset(state, 0, sizeof(Ed25519State)); + + // Hash the private key, 32 octets, using SHA-512. Let h denote the + // resulting digest + + mbedtls_sha512_init(&sha512Scontext); + mbedtls_sha512_starts(&sha512Scontext, 0); + mbedtls_sha512_update(&sha512Scontext, privateKey, ED25519_PRIVATE_KEY_LEN); + mbedtls_sha512_finish(&sha512Scontext, digest); + mbedtls_sha512_free(&sha512Scontext); + + // Construct the secret scalar s from the first half of the digest + memcpy(state->s, digest, 32); + + // The lowest three bits of the first octet are cleared, the highest bit + // of the last octet is cleared, and the second highest bit of the last + // octet is set + state->s[0] &= 0xF8; + state->s[31] &= 0x7F; + state->s[31] |= 0x40; + + // The public key is optional + if (publicKey == NULL) + { + // Perform a fixed-base scalar multiplication s * B + ed25519Mul(state, &state->sb, state->s, &ED25519_B); + // The public key A is the encoding of the point s * B + ed25519Encode(&state->sb, state->k); + // Point to the resulting public key + publicKey = state->k; + } + + // Let prefix denote the second half of the hash digest + memcpy(state->p, digest + 32, 32); + + // Initialize SHA-512 context + mbedtls_sha512_init(&sha512Scontext); + mbedtls_sha512_starts(&sha512Scontext, 0); + + // For Ed25519ctx and Ed25519ph schemes, dom2(x, y) is the octet string + //"SigEd25519 no Ed25519 collisions" || octet(x) || octet(OLEN(y)) || y, + // where x is in range 0-255 and y is an octet string of at most 255 octets + if (context != NULL || flag != 0) + { + mbedtls_sha512_update(&sha512Scontext, (const uint8_t *)"SigEd25519 no Ed25519 collisions", 32); + mbedtls_sha512_update(&sha512Scontext, &flag, sizeof(uint8_t)); + mbedtls_sha512_update(&sha512Scontext, &contextLen, sizeof(uint8_t)); + mbedtls_sha512_update(&sha512Scontext, context, contextLen); + } + + // Digest prefix + mbedtls_sha512_update(&sha512Scontext, state->p, 32); + + // The message is split over multiple chunks + for (i = 0; messageChunks[i].buffer != NULL; i++) + { + // Digest current chunk + mbedtls_sha512_update(&sha512Scontext, messageChunks[i].buffer, + messageChunks[i].length); + } + + // Compute SHA-512(dom2(F, C) || prefix || PH(M)) + mbedtls_sha512_finish(&sha512Scontext, digest); + mbedtls_sha512_free(&sha512Scontext); + + // Reduce the 64-octet digest as a little-endian integer r + ed25519RedInt(state->r, digest); + // Compute the point r * B + ed25519Mul(state, &state->rb, state->r, &ED25519_B); + // Let the string R be the encoding of this point + ed25519Encode(&state->rb, signature); + + // Initialize SHA-512 context + mbedtls_sha512_init(&sha512Scontext); + mbedtls_sha512_starts(&sha512Scontext, 0); + + // For Ed25519ctx and Ed25519ph schemes, dom2(x, y) is the octet string + //"SigEd25519 no Ed25519 collisions" || octet(x) || octet(OLEN(y)) || y, + // where x is in range 0-255 and y is an octet string of at most 255 octets + if (context != NULL || flag != 0) + { + mbedtls_sha512_update(&sha512Scontext, (const uint8_t *)"SigEd25519 no Ed25519 collisions", 32); + mbedtls_sha512_update(&sha512Scontext, &flag, sizeof(uint8_t)); + mbedtls_sha512_update(&sha512Scontext, &contextLen, sizeof(uint8_t)); + mbedtls_sha512_update(&sha512Scontext, context, contextLen); + } + + // Digest R || A + mbedtls_sha512_update(&sha512Scontext, signature, ED25519_SIGNATURE_LEN / 2); + mbedtls_sha512_update(&sha512Scontext, publicKey, ED25519_PUBLIC_KEY_LEN); + + // The message is split over multiple chunks + for (i = 0; messageChunks[i].buffer != NULL; i++) + { + // Digest current chunk + mbedtls_sha512_update(&sha512Scontext, messageChunks[i].buffer, + messageChunks[i].length); + } + + // Compute SHA512(dom2(F, C) || R || A || PH(M)) and interpret the 64-octet + // digest as a little-endian integer k + mbedtls_sha512_finish(&sha512Scontext, state->k); + mbedtls_sha512_free(&sha512Scontext); + + // Compute S = (r + k * s) mod L. For efficiency, reduce k modulo L first + ed25519RedInt(state->p, state->k); + ed25519MulInt(state->k, state->k + 32, state->p, state->s, 32); + ed25519RedInt(state->p, state->k); + ed25519AddInt(state->s, state->p, state->r, 32); + + // Perform modular reduction + c = ed25519SubInt(state->p, state->s, ED25519_L, 32); + ed25519SelectInt(signature + 32, state->p, state->s, c, 32); + + // Erase working state + memset(state, 0, sizeof(Ed25519State)); + + // Release working state + free(state); + + // Successful processing + return 0; +} + +int ed25519GenerateSignature(const uint8_t *privateKey, + const uint8_t *publicKey, const void *message, size_t messageLen, + const void *context, uint8_t contextLen, uint8_t flag, uint8_t *signature) +{ + int error; + EddsaMessageChunk messageChunks[2]; + + // The message fits in a single chunk + messageChunks[0].buffer = message; + messageChunks[0].length = messageLen; + messageChunks[1].buffer = NULL; + messageChunks[1].length = 0; + + // Ed25519 signature generation + error = ed25519GenerateSignatureEx(privateKey, publicKey, messageChunks, + context, contextLen, flag, signature); + + // Return status code + return error; +} \ No newline at end of file diff --git a/main/crypto/include/esp32_ed25519.h b/main/crypto/include/esp32_ed25519.h new file mode 100644 index 0000000..5ca37cf --- /dev/null +++ b/main/crypto/include/esp32_ed25519.h @@ -0,0 +1,54 @@ +#ifndef ESP32_ED25519_H_ +#define ESP32_ED25519_H_ + +#include + + +//Length of EdDSA private keys +#define ED25519_PRIVATE_KEY_LEN 32 +//Length of EdDSA public keys +#define ED25519_PUBLIC_KEY_LEN 32 +//Length of EdDSA signatures +#define ED25519_SIGNATURE_LEN 64 + +//Ed25519ph flag +#define ED25519_PH_FLAG 1 +//Prehash function output size +#define ED25519_PH_SIZE 64 + +typedef struct +{ + uint32_t x[8]; + uint32_t y[8]; + uint32_t z[8]; + uint32_t t[8]; +} Ed25519Point; + +typedef struct +{ + uint8_t k[64]; + uint8_t p[32]; + uint8_t r[32]; + uint8_t s[32]; + Ed25519Point ka; + Ed25519Point rb; + Ed25519Point sb; + Ed25519Point u; + Ed25519Point v; + uint32_t a[8]; + uint32_t b[8]; + uint32_t c[8]; + uint32_t d[8]; + uint32_t e[8]; + uint32_t f[8]; + uint32_t g[8]; + uint32_t h[8]; +} Ed25519State; + +int ed25519GeneratePublicKey(const uint8_t *privateKey, uint8_t *publicKey); + +int ed25519GenerateSignature(const uint8_t *privateKey, + const uint8_t *publicKey, const void *message, size_t messageLen, + const void *context, uint8_t contextLen, uint8_t flag, uint8_t *signature); + +#endif \ No newline at end of file