mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-12 18:49:07 +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:
parent
a90257c422
commit
409783ba64
58
ecdsa.c
58
ecdsa.c
@ -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)
|
||||
{
|
||||
|
1
ecdsa.h
1
ecdsa.h
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user