1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-22 12:32:02 +00:00

Reworked rfc6979 signing. (#72)

This adds an is_canonic parameter to all sign functions.  This is a
callback that determines if a signature corresponds to some coin
specific rules.  It is used, e. g., by ethereum (where the recovery
byte must be 0 or 1, and not 2 or 3) and or steem signatures (which
require both r and s to be between 2^248 and 2^255).

This also separates the initialization and the step function of the
random number generator, making it easy to restart the signature
process with the next random number.
This commit is contained in:
Jochen Hoenicke 2016-10-06 16:54:07 +02:00 committed by Pavol Rusnak
parent 00413c0b6e
commit 133c068f37
8 changed files with 134 additions and 135 deletions

View File

@ -415,25 +415,25 @@ int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash)
// msg is a data to be signed
// msg_len is the message length
int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby)
int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]))
{
if (node->curve == &ed25519_info) {
hdnode_fill_public_key(node);
ed25519_sign(msg, msg_len, node->private_key, node->public_key + 1, sig);
return 0;
} else {
return ecdsa_sign(node->curve->params, node->private_key, msg, msg_len, sig, pby);
return ecdsa_sign(node->curve->params, node->private_key, msg, msg_len, sig, pby, is_canonical);
}
}
int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby)
int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]))
{
if (node->curve == &ed25519_info) {
hdnode_fill_public_key(node);
ed25519_sign(digest, 32, node->private_key, node->public_key + 1, sig);
return 0;
} else {
return ecdsa_sign_digest(node->curve->params, node->private_key, digest, sig, pby);
return ecdsa_sign_digest(node->curve->params, node->private_key, digest, sig, pby, is_canonical);
}
}

View File

@ -71,8 +71,8 @@ void hdnode_fill_public_key(HDNode *node);
int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash);
#endif
int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby);
int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby);
int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]));
int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]));
int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, char *str, int strsize);

218
ecdsa.c
View File

@ -614,79 +614,62 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point *
#endif
// generate random K for signing
int generate_k_random(const ecdsa_curve *curve, bignum256 *k) {
int i, j;
for (j = 0; j < 10000; j++) {
for (i = 0; i < 8; i++) {
k->val[i] = random32() & 0x3FFFFFFF;
}
k->val[8] = random32() & 0xFFFF;
// if k is too big or too small, we don't like it
if ( !bn_is_zero(k) && bn_is_less(k, &curve->order) ) {
return 0; // good number - no error
}
void generate_k_random(bignum256 *k) {
int i;
for (i = 0; i < 8; i++) {
k->val[i] = random32() & 0x3FFFFFFF;
}
// we generated 10000 numbers, none of them is good -> fail
return 1;
k->val[8] = random32() & 0xFFFF;
}
void init_k_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];
memcpy(bx, priv_key, 32);
memcpy(bx+32, hash, 32);
memset(state->v, 1, sizeof(state->v));
memset(state->k, 0, sizeof(state->k));
memcpy(buf, state->v, sizeof(state->v));
buf[sizeof(state->v)] = 0x00;
memcpy(buf + sizeof(state->v) + 1, bx, 64);
hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k);
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
memcpy(buf, state->v, sizeof(state->v));
buf[sizeof(state->v)] = 0x01;
memcpy(buf + sizeof(state->v) + 1, bx, 64);
hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k);
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
MEMSET_BZERO(bx, sizeof(bx));
MEMSET_BZERO(buf, sizeof(buf));
}
// generate K in a deterministic way, according to RFC6979
// http://tools.ietf.org/html/rfc6979
int generate_k_rfc6979(const ecdsa_curve *curve, bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash)
void generate_k_rfc6979(bignum256 *k, rfc6979_state *state)
{
int i, error;
uint8_t v[32], k[32], bx[2*32], buf[32 + 1 + sizeof(bx)];
bignum256 z1;
uint8_t buf[32 + 1];
memcpy(bx, priv_key, 32);
bn_read_be(hash, &z1);
bn_mod(&z1, &curve->order);
bn_write_be(&z1, bx + 32);
memset(v, 1, sizeof(v));
memset(k, 0, sizeof(k));
memcpy(buf, v, sizeof(v));
buf[sizeof(v)] = 0x00;
memcpy(buf + sizeof(v) + 1, bx, 64);
hmac_sha256(k, sizeof(k), buf, sizeof(buf), k);
hmac_sha256(k, sizeof(k), v, sizeof(v), v);
memcpy(buf, v, sizeof(v));
buf[sizeof(v)] = 0x01;
memcpy(buf + sizeof(v) + 1, bx, 64);
hmac_sha256(k, sizeof(k), buf, sizeof(buf), k);
hmac_sha256(k, sizeof(k), v, sizeof(v), v);
error = 1;
for (i = 0; i < 10000; i++) {
hmac_sha256(k, sizeof(k), v, sizeof(v), v);
bn_read_be(v, secret);
if ( !bn_is_zero(secret) && bn_is_less(secret, &curve->order) ) {
error = 0; // good number -> no error
break;
}
memcpy(buf, v, sizeof(v));
buf[sizeof(v)] = 0x00;
hmac_sha256(k, sizeof(k), buf, sizeof(v) + 1, k);
hmac_sha256(k, sizeof(k), v, sizeof(v), v);
}
// we generated 10000 numbers, none of them is good -> fail
MEMSET_BZERO(v, sizeof(v));
MEMSET_BZERO(k, sizeof(k));
MEMSET_BZERO(bx, sizeof(bx));
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);
MEMSET_BZERO(buf, sizeof(buf));
return error;
}
// msg is a data to be signed
// msg_len is the message length
int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby)
int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]))
{
uint8_t hash[32];
sha256_Raw(msg, msg_len, hash);
int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby);
int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical);
MEMSET_BZERO(hash, sizeof(hash));
return res;
@ -694,12 +677,12 @@ int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t
// msg is a data to be signed
// msg_len is the message length
int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby)
int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]))
{
uint8_t hash[32];
sha256_Raw(msg, msg_len, hash);
sha256_Raw(hash, 32, hash);
int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby);
int res = ecdsa_sign_digest(curve, priv_key, hash, sig, pby, is_canonical);
MEMSET_BZERO(hash, sizeof(hash));
return res;
}
@ -708,82 +691,93 @@ int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const u
// priv_key is a 32 byte big endian stored number
// sig is 64 bytes long array for the signature
// digest is 32 bytes of digest
int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby)
// is_canonical is an optional function that checks if the signature
// conforms to additional coin-specific rules.
int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]))
{
uint32_t i;
int i;
curve_point R;
bignum256 k, z;
bignum256 *da = &R.y;
int result = 0;
bn_read_be(digest, &z);
bignum256 *s = &R.y;
uint8_t by; // signature recovery byte
#if USE_RFC6979
// generate K deterministically
if (generate_k_rfc6979(curve, &k, priv_key, digest) != 0) {
result = 1;
}
#else
// generate random number k
if (generate_k_random(curve, &k) != 0) {
result = 1;
}
rfc6979_state rng;
init_k_rfc6979(priv_key, digest, &rng);
#endif
if (result == 0) {
bn_read_be(digest, &z);
for (i = 0; i < 10000; i++) {
#if USE_RFC6979
// generate K deterministically
generate_k_rfc6979(&k, &rng);
#else
// generate random number k
generate_k_random(&k);
#endif
// if k is too big or too small, we don't like it
if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) {
continue;
}
// compute k*G
scalar_multiply(curve, &k, &R);
if (pby) {
*pby = R.y.val[0] & 1;
}
by = R.y.val[0] & 1;
// r = (rx mod n)
if (!bn_is_less(&R.x, &curve->order)) {
bn_subtract(&R.x, &curve->order, &R.x);
if (pby) {
*pby |= 2;
}
by |= 2;
}
// if r is zero, we fail
if (bn_is_zero(&R.x))
{
result = 2;
// if r is zero, we retry
if (bn_is_zero(&R.x)) {
continue;
}
}
if (result == 0) {
bn_inverse(&k, &curve->order);
bn_read_be(priv_key, da);
bn_multiply(&R.x, da, &curve->order);
for (i = 0; i < 8; i++) {
da->val[i] += z.val[i];
da->val[i + 1] += (da->val[i] >> 30);
da->val[i] &= 0x3FFFFFFF;
bn_read_be(priv_key, s);
bn_multiply(&R.x, s, &curve->order);
bn_add(s, &z);
bn_multiply(&k, s, &curve->order);
bn_mod(s, &curve->order);
// if s is zero, we retry
if (bn_is_zero(s)) {
continue;
}
da->val[8] += z.val[8];
bn_multiply(da, &k, &curve->order);
bn_mod(&k, &curve->order);
// if k is zero, we fail
if (bn_is_zero(&k)) {
result = 3;
}
}
if (result == 0) {
// if S > order/2 => S = -S
if (bn_is_less(&curve->order_half, &k)) {
bn_subtract(&curve->order, &k, &k);
if (pby) {
*pby ^= 1;
}
if (bn_is_less(&curve->order_half, s)) {
bn_subtract(&curve->order, s, s);
by ^= 1;
}
// we are done, R.x and k is the result signature
// we are done, R.x and s is the result signature
bn_write_be(&R.x, sig);
bn_write_be(&k, sig + 32);
bn_write_be(s, sig + 32);
// check if the signature is acceptable or retry
if (is_canonical && !is_canonical(by, sig)) {
continue;
}
if (pby) {
*pby = by;
}
MEMSET_BZERO(&k, sizeof(k));
#if USE_RFC6979
MEMSET_BZERO(&rng, sizeof(rng));
#endif
return 0;
}
// Too many retries without a valid signature
// -> fail with an error
MEMSET_BZERO(&k, sizeof(k));
MEMSET_BZERO(&z, sizeof(z));
MEMSET_BZERO(&R, sizeof(R));
return result;
#if USE_RFC6979
MEMSET_BZERO(&rng, sizeof(rng));
#endif
return -1;
}
void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key)

16
ecdsa.h
View File

@ -48,6 +48,11 @@ typedef struct {
} ecdsa_curve;
// rfc6979 pseudo random number generator state
typedef struct {
uint8_t v[32], k[32];
} rfc6979_state;
void point_copy(const curve_point *cp1, curve_point *cp2);
void point_add(const ecdsa_curve *curve, const curve_point *cp1, curve_point *cp2);
void point_double(const ecdsa_curve *curve, curve_point *cp);
@ -60,9 +65,9 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point *
void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y);
int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, uint8_t *uncompressed);
int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby);
int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby);
int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby);
int ecdsa_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]));
int ecdsa_sign_double(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]));
int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]));
void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key);
void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key);
void ecdsa_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash);
@ -80,7 +85,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
int generate_k_rfc6979(const ecdsa_curve *curve, bignum256 *secret, const uint8_t *priv_key, const uint8_t *hash);
int generate_k_random(const ecdsa_curve *curve, bignum256 *k);
void init_k_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *rng);
void generate_k_rfc6979(bignum256 *k, rfc6979_state *rng);
void generate_k_random(bignum256 *k);
#endif

View File

@ -88,7 +88,7 @@ int main(int argc, char *argv[])
}
// use our ECDSA signer to sign the message with the key
if (ecdsa_sign(CURVE, priv_key, msg, msg_len, sig, 0) != 0) {
if (ecdsa_sign(CURVE, priv_key, msg, msg_len, sig, NULL, NULL) != 0) {
printf("trezor-crypto signing failed\n");
break;
}

View File

@ -380,7 +380,7 @@ def test_sign(curve, r):
digest = r.randbytes(32)
sig = r.randbytes(64)
lib.ecdsa_sign_digest(curve.ptr, priv, digest, sig, c.c_void_p(0))
lib.ecdsa_sign_digest(curve.ptr, priv, digest, sig, c.c_void_p(0), c.c_void_p(0))
exp = bytes2num(priv)
sk = ecdsa.SigningKey.from_secret_exponent(exp, curve,

View File

@ -25,7 +25,7 @@ void bench_secp256k1(void) {
memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32);
ecdsa_get_public_key33(curve, priv, pub);
ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby);
ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL);
clock_t t = clock();
for (int i = 0 ; i < 500; i++) {
@ -42,7 +42,7 @@ void bench_nist256p1(void) {
memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32);
ecdsa_get_public_key33(curve, priv, pub);
ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby);
ecdsa_sign(curve, priv, msg, sizeof(msg), sig, &pby, NULL);
clock_t t = clock();
for (int i = 0 ; i < 500; i++) {

15
tests.c
View File

@ -1266,18 +1266,17 @@ END_TEST
#define test_deterministic(KEY, MSG, K) do { \
sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \
res = generate_k_rfc6979(curve, &k, fromhex(KEY), buf); \
ck_assert_int_eq(res, 0); \
init_k_rfc6979(fromhex(KEY), buf, &rng); \
generate_k_rfc6979(&k, &rng); \
bn_write_be(&k, buf); \
ck_assert_mem_eq(buf, fromhex(K), 32); \
} while (0)
START_TEST(test_rfc6979)
{
int res;
bignum256 k;
uint8_t buf[32];
const ecdsa_curve *curve = &secp256k1;
rfc6979_state rng;
test_deterministic("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", "sample", "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3");
test_deterministic("0000000000000000000000000000000000000000000000000000000000000001", "Satoshi Nakamoto", "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15");
@ -1303,13 +1302,13 @@ START_TEST(test_sign_speed)
memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32);
for (i = 0 ; i < 250; i++) {
res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, 0);
res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, NULL, NULL);
ck_assert_int_eq(res, 0);
}
memcpy(priv_key, fromhex("509a0382ff5da48e402967a671bdcde70046d07f0df52cff12e8e3883b426a0a"), 32);
for (i = 0 ; i < 250; i++) {
res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, 0);
res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, NULL, NULL);
ck_assert_int_eq(res, 0);
}
@ -1320,13 +1319,13 @@ START_TEST(test_sign_speed)
memcpy(priv_key, fromhex("c55ece858b0ddd5263f96810fe14437cd3b5e1fbd7c6a2ec1e031f05e86d8bd5"), 32);
for (i = 0 ; i < 250; i++) {
res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, 0);
res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, NULL, NULL);
ck_assert_int_eq(res, 0);
}
memcpy(priv_key, fromhex("509a0382ff5da48e402967a671bdcde70046d07f0df52cff12e8e3883b426a0a"), 32);
for (i = 0 ; i < 250; i++) {
res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, 0);
res = ecdsa_sign(curve, priv_key, msg, sizeof(msg), sig, NULL, NULL);
ck_assert_int_eq(res, 0);
}