1
0
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:
Jochen Hoenicke 2017-04-02 00:08:04 +02:00 committed by Pavol Rusnak
parent 12af9b262b
commit d3d88591d0
5 changed files with 147 additions and 9 deletions

21
ecdsa.c
View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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
View File

@ -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);