1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-14 03:30:02 +00:00

New function ecdsa_verify_recover

Moved the code from Trezor firmware to here for recovering the public key
when verifying a bitcoin message.  Fixed the signing and verification for
the unlikely case the r value overflows.
This commit is contained in:
Jochen Hoenicke 2016-04-25 13:12:53 +02:00
parent a90257c422
commit 409783ba64
No known key found for this signature in database
GPG Key ID: EB17C6B5E51193F5
2 changed files with 57 additions and 2 deletions

58
ecdsa.c
View File

@ -735,7 +735,12 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u
*pby = R.y.val[0] & 1;
}
// r = (rx mod n)
bn_mod(&R.x, &curve->order);
if (!bn_is_less(&R.x, &curve->order)) {
bn_subtract(&R.x, &curve->order, &R.x);
if (pby) {
*pby |= 2;
}
}
// if r is zero, we fail
if (bn_is_zero(&R.x))
{
@ -766,7 +771,7 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const u
if (bn_is_less(&curve->order_half, &k)) {
bn_subtract(&curve->order, &k, &k);
if (pby) {
*pby = !*pby;
*pby ^= 1;
}
}
// we are done, R.x and k is the result signature
@ -950,6 +955,55 @@ int ecdsa_verify_double(const ecdsa_curve *curve, const uint8_t *pub_key, const
return res;
}
// Compute public key from signature and recovery id.
// returns 0 if verification succeeded
int ecdsa_verify_digest_recover(const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid)
{
bignum256 r, s, e;
curve_point cp, cp2;
// read r and s
bn_read_be(sig, &r);
bn_read_be(sig + 32, &s);
if (!bn_is_less(&r, &curve->order) || bn_is_zero(&r)) {
return 1;
}
if (!bn_is_less(&s, &curve->order) || bn_is_zero(&s)) {
return 1;
}
// cp = R = k * G (k is secret nonce when signing)
memcpy(&cp.x, &r, sizeof(bignum256));
if (recid & 2) {
bn_add(&cp.x, &curve->order);
if (!bn_is_less(&cp.x, &curve->prime)) {
return 1;
}
}
// compute y from x
uncompress_coords(curve, recid & 1, &cp.x, &cp.y);
if (!ecdsa_validate_pubkey(curve, &cp)) {
return 1;
}
// e = -digest
bn_read_be(digest, &e);
bn_mod(&e, &curve->order);
bn_subtract(&curve->order, &e, &e);
// r := r^-1
bn_inverse(&r, &curve->order);
// cp := s * R = s * k *G
point_multiply(curve, &s, &cp, &cp);
// cp2 := -digest * G
scalar_multiply(curve, &e, &cp2);
// cp := (s * k - digest) * G = (r*priv) * G = r * Pub
point_add(curve, &cp2, &cp);
// cp := r^{-1} * r * Pub = Pub
point_multiply(curve, &r, &cp, &cp);
pub_key[0] = 0x04;
bn_write_be(&cp.x, pub_key + 1);
bn_write_be(&cp.y, pub_key + 33);
return 0;
}
// returns 0 if verification succeeded
int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest)
{

View File

@ -75,6 +75,7 @@ int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub);
int ecdsa_verify(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len);
int ecdsa_verify_double(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len);
int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest);
int ecdsa_verify_digest_recover(const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid);
int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der);
// Private