mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-06-07 16:49:04 +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;
|
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 bx[2*32];
|
||||||
uint8_t buf[32 + 1 + 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));
|
MEMSET_BZERO(buf, sizeof(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate K in a deterministic way, according to RFC6979
|
// generate next number from deterministic random number generator
|
||||||
// http://tools.ietf.org/html/rfc6979
|
void generate_rfc6979(uint8_t rand[32], rfc6979_state *state)
|
||||||
void generate_k_rfc6979(bignum256 *k, rfc6979_state *state)
|
|
||||||
{
|
{
|
||||||
uint8_t buf[32 + 1];
|
uint8_t buf[32 + 1];
|
||||||
|
|
||||||
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
|
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));
|
memcpy(buf, state->v, sizeof(state->v));
|
||||||
buf[sizeof(state->v)] = 0x00;
|
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), buf, sizeof(state->v) + 1, state->k);
|
||||||
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
|
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));
|
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
|
#if USE_RFC6979
|
||||||
rfc6979_state rng;
|
rfc6979_state rng;
|
||||||
init_k_rfc6979(priv_key, digest, &rng);
|
init_rfc6979(priv_key, digest, &rng);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bn_read_be(digest, &z);
|
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);
|
int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der);
|
||||||
|
|
||||||
// Private
|
// 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_rfc6979(bignum256 *k, rfc6979_state *rng);
|
||||||
void generate_k_random(bignum256 *k, const bignum256 *prime);
|
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);
|
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
|
void
|
||||||
ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS) {
|
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;
|
ed25519_hash_context ctx;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned char ed25519_cosi_signature[32];
|
||||||
typedef unsigned char ed25519_signature[64];
|
typedef unsigned char ed25519_signature[64];
|
||||||
typedef unsigned char ed25519_public_key[32];
|
typedef unsigned char ed25519_public_key[32];
|
||||||
typedef unsigned char ed25519_secret_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];
|
typedef unsigned char curve25519_key[32];
|
||||||
|
|
||||||
void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk);
|
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);
|
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);
|
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 { \
|
#define test_deterministic(KEY, MSG, K) do { \
|
||||||
sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \
|
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); \
|
generate_k_rfc6979(&k, &rng); \
|
||||||
bn_write_be(&k, buf); \
|
bn_write_be(&k, buf); \
|
||||||
ck_assert_mem_eq(buf, fromhex(K), 32); \
|
ck_assert_mem_eq(buf, fromhex(K), 32); \
|
||||||
@ -2650,6 +2650,56 @@ START_TEST(test_ed25519) {
|
|||||||
}
|
}
|
||||||
END_TEST
|
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) {
|
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_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, node);
|
||||||
hdnode_fill_public_key(node);
|
hdnode_fill_public_key(node);
|
||||||
@ -3040,6 +3090,10 @@ Suite *test_suite(void)
|
|||||||
tcase_add_test(tc, test_ed25519);
|
tcase_add_test(tc, test_ed25519);
|
||||||
suite_add_tcase(s, tc);
|
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");
|
tc = tcase_create("script");
|
||||||
tcase_add_test(tc, test_output_script);
|
tcase_add_test(tc, test_output_script);
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
Loading…
Reference in New Issue
Block a user