mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-12 18:49:07 +00:00
Added co-signing for ed25519.
This commit is contained in:
parent
12af9b262b
commit
d3d88591d0
21
ecdsa.c
21
ecdsa.c
@ -658,7 +658,7 @@ int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8
|
||||
return 0;
|
||||
}
|
||||
|
||||
void init_k_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *state) {
|
||||
void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *state) {
|
||||
uint8_t bx[2*32];
|
||||
uint8_t buf[32 + 1 + 2*32];
|
||||
|
||||
@ -684,18 +684,27 @@ void init_k_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state
|
||||
MEMSET_BZERO(buf, sizeof(buf));
|
||||
}
|
||||
|
||||
// generate K in a deterministic way, according to RFC6979
|
||||
// http://tools.ietf.org/html/rfc6979
|
||||
void generate_k_rfc6979(bignum256 *k, rfc6979_state *state)
|
||||
// generate next number from deterministic random number generator
|
||||
void generate_rfc6979(uint8_t rand[32], rfc6979_state *state)
|
||||
{
|
||||
uint8_t buf[32 + 1];
|
||||
|
||||
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
|
||||
bn_read_be(state->v, k);
|
||||
memcpy(buf, state->v, sizeof(state->v));
|
||||
buf[sizeof(state->v)] = 0x00;
|
||||
hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k);
|
||||
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
|
||||
memcpy(rand, buf, 32);
|
||||
MEMSET_BZERO(buf, sizeof(buf));
|
||||
}
|
||||
|
||||
// generate K in a deterministic way, according to RFC6979
|
||||
// http://tools.ietf.org/html/rfc6979
|
||||
void generate_k_rfc6979(bignum256 *k, rfc6979_state *state)
|
||||
{
|
||||
uint8_t buf[32];
|
||||
generate_rfc6979(buf, state);
|
||||
bn_read_be(buf, k);
|
||||
MEMSET_BZERO(buf, sizeof(buf));
|
||||
}
|
||||
|
||||
@ -739,7 +748,7 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u
|
||||
|
||||
#if USE_RFC6979
|
||||
rfc6979_state rng;
|
||||
init_k_rfc6979(priv_key, digest, &rng);
|
||||
init_rfc6979(priv_key, digest, &rng);
|
||||
#endif
|
||||
|
||||
bn_read_be(digest, &z);
|
||||
|
3
ecdsa.h
3
ecdsa.h
@ -91,7 +91,8 @@ int ecdsa_verify_digest_recover(const ecdsa_curve *curve, uint8_t *pub_key, cons
|
||||
int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der);
|
||||
|
||||
// Private
|
||||
void init_k_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *rng);
|
||||
void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *rng);
|
||||
void generate_rfc6979(uint8_t rand[32], rfc6979_state *rng);
|
||||
void generate_k_rfc6979(bignum256 *k, rfc6979_state *rng);
|
||||
void generate_k_random(bignum256 *k, const bignum256 *prime);
|
||||
|
||||
|
@ -44,6 +44,75 @@ ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk) {
|
||||
ge25519_pack(pk, &A);
|
||||
}
|
||||
|
||||
int
|
||||
ed25519_cosi_combine_publickeys(ed25519_public_key res, const ed25519_public_key *pks, size_t n) {
|
||||
size_t i = 0;
|
||||
ge25519 P;
|
||||
ge25519_pniels sump;
|
||||
ge25519_p1p1 sump1;
|
||||
|
||||
if (n == 1) {
|
||||
memcpy(res, pks, sizeof(ed25519_public_key));
|
||||
return 0;
|
||||
}
|
||||
if (!ge25519_unpack_negative_vartime(&P, pks[i++]))
|
||||
return -1;
|
||||
ge25519_full_to_pniels(&sump, &P);
|
||||
while (i < n-1) {
|
||||
if (!ge25519_unpack_negative_vartime(&P, pks[i++]))
|
||||
return -1;
|
||||
ge25519_pnielsadd(&sump, &P, &sump);
|
||||
}
|
||||
if (!ge25519_unpack_negative_vartime(&P, pks[i++]))
|
||||
return -1;
|
||||
ge25519_pnielsadd_p1p1(&sump1, &P, &sump, 0);
|
||||
ge25519_p1p1_to_partial(&P, &sump1);
|
||||
curve25519_neg(P.x, P.x);
|
||||
ge25519_pack(res, &P);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, const ed25519_cosi_signature *sigs, size_t n) {
|
||||
bignum256modm s, t;
|
||||
size_t i;
|
||||
|
||||
i = 0;
|
||||
expand256_modm(s, sigs[i++], 32);
|
||||
while (i < n) {
|
||||
expand256_modm(t, sigs[i++], 32);
|
||||
add256_modm(s, s, t);
|
||||
}
|
||||
memcpy(res, R, 32);
|
||||
contract256_modm(res + 32, s);
|
||||
}
|
||||
|
||||
void
|
||||
ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig) {
|
||||
bignum256modm r, S, a;
|
||||
hash_512bits extsk, extnonce, hram;
|
||||
|
||||
ed25519_extsk(extsk, sk);
|
||||
ed25519_extsk(extnonce, nonce);
|
||||
|
||||
/* r = nonce */
|
||||
expand256_modm(r, extnonce, 32);
|
||||
|
||||
/* S = H(R,A,m).. */
|
||||
ed25519_hram(hram, R, pk, m, mlen);
|
||||
expand256_modm(S, hram, 64);
|
||||
|
||||
/* S = H(R,A,m)a */
|
||||
expand256_modm(a, extsk, 32);
|
||||
mul256_modm(S, S, a);
|
||||
|
||||
/* S = (r + H(R,A,m)a) */
|
||||
add256_modm(S, S, r);
|
||||
|
||||
/* S = (r + H(R,A,m)a) mod L */
|
||||
contract256_modm(sig, S);
|
||||
}
|
||||
|
||||
void
|
||||
ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS) {
|
||||
ed25519_hash_context ctx;
|
||||
@ -75,7 +144,7 @@ ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, c
|
||||
/* S = (r + H(R,A,m)a) */
|
||||
add256_modm(S, S, r);
|
||||
|
||||
/* S = (r + H(R,A,m)a) mod L */
|
||||
/* S = (r + H(R,A,m)a) mod L */
|
||||
contract256_modm(RS + 32, S);
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef unsigned char ed25519_cosi_signature[32];
|
||||
typedef unsigned char ed25519_signature[64];
|
||||
typedef unsigned char ed25519_public_key[32];
|
||||
typedef unsigned char ed25519_secret_key[32];
|
||||
@ -12,6 +13,10 @@ typedef unsigned char ed25519_secret_key[32];
|
||||
typedef unsigned char curve25519_key[32];
|
||||
|
||||
void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk);
|
||||
|
||||
int ed25519_cosi_combine_publickeys(ed25519_public_key res, const ed25519_public_key *pks, size_t n);
|
||||
void ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, const ed25519_cosi_signature *sigs, size_t n);
|
||||
void ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key key, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig);
|
||||
int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS);
|
||||
void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS);
|
||||
|
||||
|
56
tests.c
56
tests.c
@ -1287,7 +1287,7 @@ END_TEST
|
||||
|
||||
#define test_deterministic(KEY, MSG, K) do { \
|
||||
sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \
|
||||
init_k_rfc6979(fromhex(KEY), buf, &rng); \
|
||||
init_rfc6979(fromhex(KEY), buf, &rng); \
|
||||
generate_k_rfc6979(&k, &rng); \
|
||||
bn_write_be(&k, buf); \
|
||||
ck_assert_mem_eq(buf, fromhex(K), 32); \
|
||||
@ -2650,6 +2650,56 @@ START_TEST(test_ed25519) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_ed25519_cosi) {
|
||||
int MAXN=10;
|
||||
ed25519_secret_key keys[MAXN];
|
||||
ed25519_public_key pubkeys[MAXN];
|
||||
ed25519_secret_key nonces[MAXN];
|
||||
ed25519_public_key Rs[MAXN];
|
||||
ed25519_cosi_signature sigs[MAXN];
|
||||
unsigned char msg[32];
|
||||
rfc6979_state rng;
|
||||
int res;
|
||||
|
||||
init_rfc6979(fromhex("26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d36"),
|
||||
fromhex("26659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), &rng);
|
||||
|
||||
for (int N = 1; N < 11; N++) {
|
||||
ed25519_public_key pk;
|
||||
ed25519_public_key R;
|
||||
ed25519_signature sig;
|
||||
/* phase 0: create priv/pubkeys and combine pubkeys */
|
||||
for (int j = 0; j < N; j++) {
|
||||
generate_rfc6979(keys[j], &rng);
|
||||
ed25519_publickey(keys[j], pubkeys[j]);
|
||||
}
|
||||
res = ed25519_cosi_combine_publickeys(pk, pubkeys, N);
|
||||
ck_assert_int_eq(res, 0);
|
||||
|
||||
generate_rfc6979(msg, &rng);
|
||||
|
||||
/* phase 1: create nonces, commitments (R values) and combine commitments */
|
||||
for (int j = 0; j < N; j++) {
|
||||
generate_rfc6979(nonces[j], &rng);
|
||||
ed25519_publickey(nonces[j], Rs[j]);
|
||||
}
|
||||
res = ed25519_cosi_combine_publickeys(R, Rs, N);
|
||||
ck_assert_int_eq(res, 0);
|
||||
|
||||
/* phase 2: sign and combine signatures */
|
||||
for (int j = 0; j < N; j++) {
|
||||
ed25519_cosi_sign(msg, sizeof(msg), keys[j], nonces[j], R, pk, sigs[j]);
|
||||
}
|
||||
|
||||
ed25519_cosi_combine_signatures(sig, R, sigs, N);
|
||||
|
||||
/* check signature */
|
||||
res = ed25519_sign_open(msg, sizeof(msg), pk, sig);
|
||||
ck_assert_int_eq(res, 0);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static void test_bip32_ecdh_init_node(HDNode *node, const char *seed_str, const char *curve_name) {
|
||||
hdnode_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, node);
|
||||
hdnode_fill_public_key(node);
|
||||
@ -3040,6 +3090,10 @@ Suite *test_suite(void)
|
||||
tcase_add_test(tc, test_ed25519);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("ed25519_cosi");
|
||||
tcase_add_test(tc, test_ed25519_cosi);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("script");
|
||||
tcase_add_test(tc, test_output_script);
|
||||
suite_add_tcase(s, tc);
|
||||
|
Loading…
Reference in New Issue
Block a user