diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 1d0fefa..479172e 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,8 +1,9 @@ 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/mbedtls_ed25519.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" "littlefs/lfs.c" "littlefs/lfs_util.c" - INCLUDE_DIRS "." "crypto/include" "littlefs" + "c25519/edsign.c" "c25519/ed25519.c" "c25519/f25519.c" "c25519/fprime.c" + INCLUDE_DIRS "." "crypto/include" "littlefs" "c25519" 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 new file mode 100644 index 0000000..51ac462 --- /dev/null +++ b/main/c25519/ed25519.c @@ -0,0 +1,320 @@ +/* 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 new file mode 100644 index 0000000..62f0120 --- /dev/null +++ b/main/c25519/ed25519.h @@ -0,0 +1,82 @@ +/* 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 new file mode 100644 index 0000000..8b61be1 --- /dev/null +++ b/main/c25519/edsign.c @@ -0,0 +1,172 @@ +/* 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 new file mode 100644 index 0000000..85e2208 --- /dev/null +++ b/main/c25519/edsign.h @@ -0,0 +1,51 @@ +/* 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 new file mode 100644 index 0000000..3b06fa6 --- /dev/null +++ b/main/c25519/f25519.c @@ -0,0 +1,324 @@ +/* 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 new file mode 100644 index 0000000..4cfa5ec --- /dev/null +++ b/main/c25519/f25519.h @@ -0,0 +1,92 @@ +/* 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 new file mode 100644 index 0000000..4b934ad --- /dev/null +++ b/main/c25519/fprime.c @@ -0,0 +1,215 @@ +/* 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 new file mode 100644 index 0000000..fd5df27 --- /dev/null +++ b/main/c25519/fprime.h @@ -0,0 +1,70 @@ +/* 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 a3f6518..faf5f31 100644 --- a/main/crypto/ecc.c +++ b/main/crypto/ecc.c @@ -4,7 +4,7 @@ #include #include #include -#include "mbedtls_ed25519.h" +#include "edsign.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) { - mbedtls_edsign_sec_to_pub(pk,sk); + edsign_sec_to_pub(pk,sk); } __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) { - mbedtls_edsign_sign(rs,pk,sk,m,mlen); + edsign_sign(rs,pk,sk,m,mlen); } diff --git a/main/crypto/include/mbedtls_ed25519.h b/main/crypto/include/mbedtls_ed25519.h deleted file mode 100644 index 5b94223..0000000 --- a/main/crypto/include/mbedtls_ed25519.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef MBEDTLS_ED25519_H_ -#define MBEDTLS_ED25519_H_ - -#include - -#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 mbedtls_edsign_sec_to_pub(uint8_t *pub, const uint8_t *secret); - -/* Produce a signature for a message. */ -#define EDSIGN_SIGNATURE_SIZE 64 - -void mbedtls_edsign_sign(uint8_t *signature, const uint8_t *pub, - const uint8_t *secret, - const uint8_t *message, size_t len); - - -#endif \ No newline at end of file diff --git a/main/crypto/mbedtls_ed25519.c b/main/crypto/mbedtls_ed25519.c deleted file mode 100644 index a86d895..0000000 --- a/main/crypto/mbedtls_ed25519.c +++ /dev/null @@ -1,669 +0,0 @@ -#include "mbedtls/error.h" -#include "mbedtls/private_access.h" -#include "mbedtls/ecp.h" -#include "bn_mul.h" -#include -#include "mbedtls_ed25519.h" -#include "sha.h" -#include "rand.h" - -#define EDSIGN_SECRET_KEY_SIZE 32 -#define EDSIGN_PUBLIC_KEY_SIZE 32 -#define EDSIGN_SIGNATURE_SIZE 64 - -static int ecp_use_ed25519(mbedtls_ecp_group *grp) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - - /* P = 2^255 - 19 */ - MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->P, 1)); - MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&grp->P, 255)); - MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&grp->P, &grp->P, 19)); - grp->pbits = mbedtls_mpi_bitlen(&grp->P); - - /* N = 2^252 + 27742317777372353535851937790883648493 */ - MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&grp->N, 16, - "14DEF9DEA2F79CD65812631A5CF5D3ED")); - MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&grp->N, 252, 1)); - - /* A = -1 */ - MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&grp->A, &grp->P, 1)); - - /* B = -121665/121666 (actually d of edwards25519) */ - MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&grp->B, 16, - "52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3")); - - /* (X(P),Y(P)) of edwards25519 in RFC7748. Also set Z so that - * projective coordinates can be used. */ - MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&grp->G.MBEDTLS_PRIVATE(X), 16, - "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A")); - MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&grp->G.MBEDTLS_PRIVATE(Y), 16, - "6666666666666666666666666666666666666666666666666666666666666658")); - MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&grp->G.MBEDTLS_PRIVATE(Z), 1)); - -cleanup: - if (ret != 0) - mbedtls_ecp_group_free(grp); - - return (ret); -} - -/* Size of p255 in terms of mbedtls_mpi_uint */ -#define P255_WIDTH (255 / 8 / sizeof(mbedtls_mpi_uint) + 1) - -/* - * Fast quasi-reduction modulo p255 = 2^255 - 19 - * Write N as A0 + 2^255 A1, return A0 + 19 * A1 - */ -static int ecp_mod_p255(mbedtls_mpi *N) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t i; - mbedtls_mpi M; - mbedtls_mpi_uint Mp[P255_WIDTH + 2]; - - if (N->MBEDTLS_PRIVATE(n) < P255_WIDTH) - return (0); - - /* M = A1 */ - M.MBEDTLS_PRIVATE(s) = 1; - M.MBEDTLS_PRIVATE(n) = N->MBEDTLS_PRIVATE(n) - (P255_WIDTH - 1); - if (M.MBEDTLS_PRIVATE(n) > P255_WIDTH + 1) - return (MBEDTLS_ERR_ECP_BAD_INPUT_DATA); - M.MBEDTLS_PRIVATE(p) = Mp; - memset(Mp, 0, sizeof Mp); - memcpy(Mp, N->MBEDTLS_PRIVATE(p) + P255_WIDTH - 1, M.MBEDTLS_PRIVATE(n) * sizeof(mbedtls_mpi_uint)); - MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&M, 255 % (8 * sizeof(mbedtls_mpi_uint)))); - M.MBEDTLS_PRIVATE(n)++; /* Make room for multiplication by 19 */ - - /* N = A0 */ - MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(N, 255, 0)); - for (i = P255_WIDTH; i < N->MBEDTLS_PRIVATE(n); i++) - N->MBEDTLS_PRIVATE(p)[i] = 0; - - /* N = A0 + 19 * A1 */ - MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&M, &M, 19)); - MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(N, N, &M)); - -cleanup: - return (ret); -} - -/* - * For Edwards curves, we do all the internal arithmetic in projective - * coordinates. Import/export of points uses only the x and y coordinates, - * which are internally represented as X/Z and Y/Z. - * - * For scalar multiplication, we'll use a Montgomery ladder. - */ - -/* - - * Normalize Edwards x/y/z coordinates: X = X/Z, Y = Y/Z, Z = 1 - - * Cost: 2M + 1I - - */ - -/* - * Wrapper around fast quasi-modp functions, with fall-back to mbedtls_mpi_mod_mpi. - * See the documentation of struct mbedtls_ecp_group. - * - * This function is in the critial loop for mbedtls_ecp_mul, so pay attention to perf. - */ -static int ecp_modp(mbedtls_mpi *N, const mbedtls_ecp_group *grp) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - - if (grp->MBEDTLS_PRIVATE(modp) == NULL) - return (mbedtls_mpi_mod_mpi(N, N, &grp->P)); - - /* N->s < 0 is a much faster test, which fails only if N is 0 */ - if ((N->MBEDTLS_PRIVATE(s) < 0 && mbedtls_mpi_cmp_int(N, 0) != 0) || - mbedtls_mpi_bitlen(N) > 2 * grp->pbits) - { - return (MBEDTLS_ERR_ECP_BAD_INPUT_DATA); - } - - MBEDTLS_MPI_CHK(grp->MBEDTLS_PRIVATE(modp(N))); - - /* N->s < 0 is a much faster test, which fails only if N is 0 */ - while (N->MBEDTLS_PRIVATE(s) < 0 && mbedtls_mpi_cmp_int(N, 0) != 0) - MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(N, N, &grp->P)); - - while (mbedtls_mpi_cmp_mpi(N, &grp->P) >= 0) - /* we known P, N and the result are positive */ - MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(N, N, &grp->P)); - -cleanup: - return (ret); -} - -#define MOD_MUL(N) \ - do \ - { \ - MBEDTLS_MPI_CHK(ecp_modp(&(N), grp)); \ - } while (0) - -static inline int ed25519_mpi_mul_mod(const mbedtls_ecp_group *grp, - mbedtls_mpi *X, - const mbedtls_mpi *A, - const mbedtls_mpi *B) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(X, A, B)); - MOD_MUL(*X); -cleanup: - return ret; -} - -#define MOD_ADD(N) \ - while (mbedtls_mpi_cmp_mpi(&(N), &grp->P) >= 0) \ - MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&(N), &(N), &grp->P)) - - -static inline int ed25519_mpi_add_mod( const mbedtls_ecp_group *grp, - mbedtls_mpi *X, - const mbedtls_mpi *A, - const mbedtls_mpi *B ) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, A, B ) ); - MOD_ADD( *X ); -cleanup: - return( ret ); -} - -static inline int ed25519_mpi_shift_l_mod(const mbedtls_ecp_group *grp, - mbedtls_mpi *X, - size_t count) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(X, count)); - MOD_ADD(*X); -cleanup: - return (ret); -} - -#define MOD_SUB(N) \ - while ((N).MBEDTLS_PRIVATE(s) < 0 && mbedtls_mpi_cmp_int(&(N), 0) != 0) \ - MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&(N), &(N), &grp->P)) - -static inline int ed25519_mpi_sub_mod(const mbedtls_ecp_group *grp, - mbedtls_mpi *X, - const mbedtls_mpi *A, - const mbedtls_mpi *B) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(X, A, B)); - MOD_SUB(*X); -cleanup: - return (ret); -} - - - - -static int ecp_normalize_edxyz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *P) - -{ - - mbedtls_mpi Zi; - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - mbedtls_mpi_init(&Zi); - MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&Zi, &P->MBEDTLS_PRIVATE(Z), &grp->P)); - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &P->MBEDTLS_PRIVATE(X), &P->MBEDTLS_PRIVATE(X), &Zi)); - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &P->MBEDTLS_PRIVATE(Y), &P->MBEDTLS_PRIVATE(Y), &Zi)); - MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&P->MBEDTLS_PRIVATE(Z), 1)); -cleanup: - mbedtls_mpi_free(&Zi); - return (ret); -} - -/* - * Randomize projective x/y/z coordinates: - * (X, Y, Z) -> (l X, l Y, l Z) for random l - * This is sort of the reverse operation of ecp_normalize_edxyz(). - * - * This countermeasure was first suggested in [2]. - * Cost: 3M - */ -static int ecp_randomize_edxyz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, - int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - mbedtls_mpi l; - size_t p_size; - int count = 0; - - p_size = (grp->pbits + 7) / 8; - mbedtls_mpi_init(&l); - - /* Generate l such that 1 < l < p */ - do - { - MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&l, p_size, f_rng, p_rng)); - - while (mbedtls_mpi_cmp_mpi(&l, &grp->P) >= 0) - MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&l, 1)); - - if (count++ > 10) - return (MBEDTLS_ERR_ECP_RANDOM_FAILED); - } while (mbedtls_mpi_cmp_int(&l, 1) <= 0); - - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &P->MBEDTLS_PRIVATE(X), &P->MBEDTLS_PRIVATE(X), &l)); - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &P->MBEDTLS_PRIVATE(Y), &P->MBEDTLS_PRIVATE(Y), &l)); - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &P->MBEDTLS_PRIVATE(Z), &P->MBEDTLS_PRIVATE(Z), &l)); - -cleanup: - mbedtls_mpi_free(&l); - - return (ret); -} - -/* - * Add for: R = P + Q for both Edwards and Twisted Edwards curves in projective - * coordinates. - * - * https://hyperelliptic.org/EFD/g1p/auto-code/twisted/projective/addition/add-2008-bbjlp.op3 - * with - * P = (X1, Z1) - * Q = (X2, Z2) - * R = (X3, Z3) - * and eliminating temporary variables t0, t3, ..., t9. - * - * Cost: 10M + 1S - */ -static int ecp_add_edxyz(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, - const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - mbedtls_mpi A, B, C, D, E, F, G, t1, t2; - - mbedtls_mpi_init(&A); - mbedtls_mpi_init(&B); - mbedtls_mpi_init(&C); - mbedtls_mpi_init(&D); - mbedtls_mpi_init(&E); - mbedtls_mpi_init(&F); - mbedtls_mpi_init(&G); - mbedtls_mpi_init(&t1); - mbedtls_mpi_init(&t2); - - /* A = Z1*Z2 */ - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &A, &P->MBEDTLS_PRIVATE(Z), &Q->MBEDTLS_PRIVATE(Z))); - /* B = A^2 */ - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &B, &A, &A)); - /* C = X1*X2 */ - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &C, &P->MBEDTLS_PRIVATE(X), &Q->MBEDTLS_PRIVATE(X))); - /* D = Y1*Y2 */ - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &D, &P->MBEDTLS_PRIVATE(Y), &Q->MBEDTLS_PRIVATE(Y))); - /* E = d*C*D */ - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &E, &C, &D)); - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &E, &E, &grp->B)); - /* F = B-E */ - MBEDTLS_MPI_CHK(ed25519_mpi_sub_mod(grp, &F, &B, &E)); - /* G = B+E */ - MBEDTLS_MPI_CHK(ed25519_mpi_add_mod(grp, &G, &B, &E)); - /* X3 = A*F*((X1+Y1)*(X2+Y2)-C-D) */ - MBEDTLS_MPI_CHK(ed25519_mpi_add_mod(grp, &t1, &P->MBEDTLS_PRIVATE(X), &P->MBEDTLS_PRIVATE(Y))); - MBEDTLS_MPI_CHK(ed25519_mpi_add_mod(grp, &t2, &Q->MBEDTLS_PRIVATE(X), &Q->MBEDTLS_PRIVATE(Y))); - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &R->MBEDTLS_PRIVATE(X), &t1, &t2)); - MBEDTLS_MPI_CHK(ed25519_mpi_sub_mod(grp, &R->MBEDTLS_PRIVATE(X), &R->MBEDTLS_PRIVATE(X), &C)); - MBEDTLS_MPI_CHK(ed25519_mpi_sub_mod(grp, &R->MBEDTLS_PRIVATE(X), &R->MBEDTLS_PRIVATE(X), &D)); - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &R->MBEDTLS_PRIVATE(X), &R->MBEDTLS_PRIVATE(X), &F)); - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &R->MBEDTLS_PRIVATE(X), &R->MBEDTLS_PRIVATE(X), &A)); - /* Y3 = A*G*(D-a*C) */ - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &R->MBEDTLS_PRIVATE(Y), &grp->A, &C)); - MBEDTLS_MPI_CHK(ed25519_mpi_sub_mod(grp, &R->MBEDTLS_PRIVATE(Y), &D, &R->MBEDTLS_PRIVATE(Y))); - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &R->MBEDTLS_PRIVATE(Y), &R->MBEDTLS_PRIVATE(Y), &G)); - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &R->MBEDTLS_PRIVATE(Y), &R->MBEDTLS_PRIVATE(Y), &A)); - /* Z3 = F*G */ - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &R->MBEDTLS_PRIVATE(Z), &F, &G)); - -cleanup: - mbedtls_mpi_free(&A); - mbedtls_mpi_free(&B); - mbedtls_mpi_free(&C); - mbedtls_mpi_free(&D); - mbedtls_mpi_free(&E); - mbedtls_mpi_free(&F); - mbedtls_mpi_free(&G); - mbedtls_mpi_free(&t1); - mbedtls_mpi_free(&t2); - - return (ret); -} - -/* - * Double for: R = 2 * P for both Edwards and Twisted Edwards curves in projective - * coordinates. - * - * https://hyperelliptic.org/EFD/g1p/auto-code/twisted/projective/doubling/dbl-2008-bbjlp.op3 - * with - * P = (X1, Z1) - * R = (X3, Z3) - * and eliminating H and temporary variables t0, ..., t4. - * - * Cost: 3M + 4S - */ -static int ecp_double_edxyz(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, - const mbedtls_ecp_point *P) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - mbedtls_mpi A, B, C, D, E, F, J; - - mbedtls_mpi_init(&A); - mbedtls_mpi_init(&B); - mbedtls_mpi_init(&C); - mbedtls_mpi_init(&D); - mbedtls_mpi_init(&E); - mbedtls_mpi_init(&F); - mbedtls_mpi_init(&J); - - /* B = (X1+Y1)^2 */ - MBEDTLS_MPI_CHK(ed25519_mpi_add_mod(grp, &B, &P->MBEDTLS_PRIVATE(X), &P->MBEDTLS_PRIVATE(Y))); - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &B, &B, &B)); - /* C = X1^2 */ - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &C, &P->MBEDTLS_PRIVATE(X), &P->MBEDTLS_PRIVATE(X))); - /* D = Y1^2 */ - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &D, &P->MBEDTLS_PRIVATE(Y), &P->MBEDTLS_PRIVATE(Y))); - /* E = a*C */ - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &E, &grp->A, &C)); - /* F = E+D */ - MBEDTLS_MPI_CHK(ed25519_mpi_add_mod(grp, &F, &E, &D)); - /* J = F-2*(Z1^2) */ - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &J, &P->MBEDTLS_PRIVATE(Z), &P->MBEDTLS_PRIVATE(Z))); - MBEDTLS_MPI_CHK(ed25519_mpi_shift_l_mod(grp, &J, 1)); - MBEDTLS_MPI_CHK(ed25519_mpi_sub_mod(grp, &J, &F, &J)); - /* X3 = (B-C-D)*J */ - MBEDTLS_MPI_CHK(ed25519_mpi_sub_mod(grp, &R->MBEDTLS_PRIVATE(X), &B, &C)); - MBEDTLS_MPI_CHK(ed25519_mpi_sub_mod(grp, &R->MBEDTLS_PRIVATE(X), &R->MBEDTLS_PRIVATE(X), &D)); - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &R->MBEDTLS_PRIVATE(X), &R->MBEDTLS_PRIVATE(X), &J)); - /* Y3 = F*(E-D) */ - MBEDTLS_MPI_CHK(ed25519_mpi_sub_mod(grp, &R->MBEDTLS_PRIVATE(Y), &E, &D)); - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &R->MBEDTLS_PRIVATE(Y), &R->MBEDTLS_PRIVATE(Y), &F)); - /* Z3 = F*J */ - MBEDTLS_MPI_CHK(ed25519_mpi_mul_mod(grp, &R->MBEDTLS_PRIVATE(Z), &F, &J)); - -cleanup: - mbedtls_mpi_free(&A); - mbedtls_mpi_free(&B); - mbedtls_mpi_free(&C); - mbedtls_mpi_free(&D); - mbedtls_mpi_free(&E); - mbedtls_mpi_free(&F); - mbedtls_mpi_free(&J); - - return (ret); -} - -/* - * Multiplication with Montgomery ladder in x/y/z coordinates, - * for curves in Edwards form. - */ -static int ecp_mul_edxyz(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, - const mbedtls_mpi *m, const mbedtls_ecp_point *P, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t i; - unsigned char b; - mbedtls_ecp_point RP; - - mbedtls_ecp_point_init(&RP); - - /* Read from P before writing to R, in case P == R */ - MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&RP, P)); - - /* Set R to zero in projective coordinates */ - MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->MBEDTLS_PRIVATE(X), 0)); - MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->MBEDTLS_PRIVATE(Y), 1)); - MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->MBEDTLS_PRIVATE(Z), 1)); - - /* RP.X and RP.Y might be slightly larger than P, so reduce them */ - MOD_ADD(RP.MBEDTLS_PRIVATE(X)); - MOD_ADD(RP.MBEDTLS_PRIVATE(Y)); - - /* Randomize coordinates of the starting point */ - if (f_rng != NULL) - MBEDTLS_MPI_CHK(ecp_randomize_edxyz(grp, &RP, f_rng, p_rng)); - - /* Loop invariant: R = result so far, RP = R + P */ - i = mbedtls_mpi_bitlen(m); /* one past the (zero-based) most significant bit */ - while (i-- > 0) - { - b = mbedtls_mpi_get_bit(m, i); - /* - * if (b) R = 2R + P else R = 2R, - * which is: - * if (b) add( R, R, RP ) - * add( RP, RP, RP ) - * else add( RP, RP, R ) - * add( R, R, R ) - * but using safe conditional swaps to avoid leaks - */ - MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->MBEDTLS_PRIVATE(X), &RP.MBEDTLS_PRIVATE(X), b)); - MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->MBEDTLS_PRIVATE(Y), &RP.MBEDTLS_PRIVATE(Y), b)); - MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->MBEDTLS_PRIVATE(Z), &RP.MBEDTLS_PRIVATE(Z), b)); - MBEDTLS_MPI_CHK(ecp_add_edxyz(grp, &RP, &RP, R)); - MBEDTLS_MPI_CHK(ecp_double_edxyz(grp, R, R)); - MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->MBEDTLS_PRIVATE(X), &RP.MBEDTLS_PRIVATE(X), b)); - MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->MBEDTLS_PRIVATE(Y), &RP.MBEDTLS_PRIVATE(Y), b)); - MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->MBEDTLS_PRIVATE(Z), &RP.MBEDTLS_PRIVATE(Z), b)); - } - - /* - * Knowledge of the projective coordinates may leak the last few bits of the - * scalar [1], and since our MPI implementation isn't constant-flow, - * inversion (used for coordinate normalization) may leak the full value - * of its input via side-channels [2]. - * - * [1] https://eprint.iacr.org/2003/191 - * [2] https://eprint.iacr.org/2020/055 - * - * Avoid the leak by randomizing coordinates before we normalize them. - */ - if (f_rng != NULL) - MBEDTLS_MPI_CHK(ecp_randomize_edxyz(grp, R, f_rng, p_rng)); - - MBEDTLS_MPI_CHK(ecp_normalize_edxyz(grp, R)); - -cleanup: - mbedtls_ecp_point_free(&RP); - - return (ret); -} - -/* - - * Point addition R = P + Q - - */ - -int mbedtls_ecp_add(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, - - const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q) - -{ - - int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; - - MBEDTLS_MPI_CHK(ecp_add_edxyz(grp, R, P, Q)); - MBEDTLS_MPI_CHK(ecp_normalize_edxyz(grp, R)); - -cleanup: - - return (ret); -} - -int ed25519_ecp_group_load(mbedtls_ecp_group *grp) -{ - - mbedtls_ecp_group_free(grp); - - grp->MBEDTLS_PRIVATE(modp) = ecp_mod_p255; - return ecp_use_ed25519(grp); -} - -int ed25519_ecp_mul(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, - const mbedtls_mpi *m, const mbedtls_ecp_point *P, - int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) -{ - - int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; - MBEDTLS_MPI_CHK(ecp_mul_edxyz(grp, R, m, P, f_rng, p_rng)); - -cleanup: - return (ret); -} - -int ed25519_ecp_point_write_binary(const mbedtls_ecp_group *grp, - const mbedtls_ecp_point *P, - int format, size_t *olen, - unsigned char *buf, size_t buflen) -{ - int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; - size_t plen; - - plen = mbedtls_mpi_size(&grp->P); - - /* We need to add an extra bit to store the least significant bit of X. */ - plen = (mbedtls_mpi_bitlen(&grp->P) + 1 + 7) >> 3; - - *olen = plen; - if (buflen < *olen) - return (MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL); - - if (mbedtls_mpi_cmp_int(&P->MBEDTLS_PRIVATE(Z), 1) != 0) - return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; - - MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(&P->MBEDTLS_PRIVATE(Y), buf, plen)); - - /* Store the least significant bit of X into the most significant - * bit of the final octet. */ - if (mbedtls_mpi_get_bit(&P->MBEDTLS_PRIVATE(X), 0)) - buf[plen - 1] |= 0x80; - -cleanup: - return (ret); -} - -void mbedtls_edsign_sec_to_pub(uint8_t *pk, const uint8_t *sk) -{ - - // calc sha512 of sk - uint8_t digest[SHA512_DIGEST_LENGTH]; - sha512_raw(sk, EDSIGN_SECRET_KEY_SIZE, digest); - - // normalize - digest[0] &= 248; - digest[31] &= 127; - digest[31] |= 64; - - // init ed25519 group - mbedtls_ecp_group ed25519; - mbedtls_ecp_group_init(&ed25519); - ed25519_ecp_group_load(&ed25519); - - // load digest - mbedtls_mpi s; - mbedtls_mpi_init(&s); - mbedtls_mpi_read_binary_le(&s, digest, 32); - - // P = s*B - mbedtls_ecp_point p; - mbedtls_ecp_point_init(&p); - ed25519_ecp_mul(&ed25519, &p, &s, &ed25519.G, mbedtls_rnd, NULL); - - // write result - size_t output_len; - ed25519_ecp_point_write_binary(&ed25519, &p, MBEDTLS_ECP_PF_COMPRESSED, &output_len, pk, - EDSIGN_PUBLIC_KEY_SIZE); - - // cleanup - mbedtls_ecp_group_free(&ed25519); - mbedtls_mpi_free(&s); - mbedtls_ecp_point_free(&p); -} - -void mbedtls_edsign_sign(uint8_t *rs, const uint8_t *pk, - const uint8_t *sk, - const uint8_t *m, size_t mlen) -{ - - // calc sha512 of sk - uint8_t digest[SHA512_DIGEST_LENGTH]; - sha512_raw(sk, EDSIGN_SECRET_KEY_SIZE, digest); - // normalize - digest[0] &= 248; - digest[31] &= 127; - digest[31] |= 64; - - // digest[0..32] is s, digest[32..64] is prefix - - // sha512(prefix || m) - uint8_t digest_m[SHA512_DIGEST_LENGTH]; - sha512_init(); - sha512_update(digest + 32, 32); - sha512_update(m, mlen); - sha512_final(digest_m); - - // init ed25519 group - mbedtls_ecp_group ed25519; - mbedtls_ecp_group_init(&ed25519); - ed25519_ecp_group_load(&ed25519); - - // load digest_m into r - mbedtls_mpi r; - mbedtls_mpi_init(&r); - mbedtls_mpi_read_binary_le(&r, digest_m, SHA512_DIGEST_LENGTH); - - // P = r*B - mbedtls_ecp_point p; - mbedtls_ecp_point_init(&p); - ed25519_ecp_mul(&ed25519, &p, &r, &ed25519.G, mbedtls_rnd, NULL); - - // write result to RS[0..32] - size_t output_len; - ed25519_ecp_point_write_binary(&ed25519, &p, MBEDTLS_ECP_PF_COMPRESSED, &output_len, rs, - EDSIGN_PUBLIC_KEY_SIZE); - - // k = sha512(R, pk, m) - uint8_t digest_k[SHA512_DIGEST_LENGTH]; - sha512_init(); - sha512_update(rs, 32); - sha512_update(pk, EDSIGN_PUBLIC_KEY_SIZE); - sha512_update(m, mlen); - sha512_final(digest_k); - - mbedtls_mpi k; - mbedtls_mpi_init(&k); - mbedtls_mpi_read_binary_le(&k, digest_k, SHA512_DIGEST_LENGTH); - mbedtls_mpi_mod_mpi(&k, &k, &ed25519.N); - - // s - mbedtls_mpi s; - mbedtls_mpi_init(&s); - mbedtls_mpi_read_binary_le(&s, digest, 32); - mbedtls_mpi_mod_mpi(&s, &s, &ed25519.N); - - // k * s - mbedtls_mpi_mul_mpi(&k, &k, &s); - mbedtls_mpi_mod_mpi(&k, &k, &ed25519.N); - - // r + k * s - mbedtls_mpi_add_mpi(&k, &k, &r); - mbedtls_mpi_mod_mpi(&k, &k, &ed25519.N); - - // write result to RS[32..64] - mbedtls_mpi_write_binary_le(&k, rs + 32, 32); - - // cleanup - mbedtls_ecp_group_free(&ed25519); - mbedtls_mpi_free(&r); - mbedtls_ecp_point_free(&p); - mbedtls_mpi_free(&k); - mbedtls_mpi_free(&s); -} \ No newline at end of file