From 0f674bd0646e34ce7d72ac7b06dd898ad389fec0 Mon Sep 17 00:00:00 2001 From: jocover Date: Sun, 21 Jan 2024 14:57:40 +0800 Subject: [PATCH] update ed25519 code for mbedtls version --- 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/include/mbedtls_ed25519.h | 25 + main/crypto/mbedtls_ed25519.c | 669 ++++++++++++++++++++++++++ 12 files changed, 699 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/include/mbedtls_ed25519.h create mode 100644 main/crypto/mbedtls_ed25519.c diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 479172e..1d0fefa 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/mbedtls_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..a3f6518 100644 --- a/main/crypto/ecc.c +++ b/main/crypto/ecc.c @@ -4,7 +4,7 @@ #include #include #include -#include "edsign.h" +#include "mbedtls_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); + mbedtls_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) { - edsign_sign(rs,pk,sk,m,mlen); + mbedtls_edsign_sign(rs,pk,sk,m,mlen); } diff --git a/main/crypto/include/mbedtls_ed25519.h b/main/crypto/include/mbedtls_ed25519.h new file mode 100644 index 0000000..5b94223 --- /dev/null +++ b/main/crypto/include/mbedtls_ed25519.h @@ -0,0 +1,25 @@ +#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 new file mode 100644 index 0000000..09aae9d --- /dev/null +++ b/main/crypto/mbedtls_ed25519.c @@ -0,0 +1,669 @@ +#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; + mbedtls_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; + mbedtls_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