Skip to content

Commit

Permalink
chore(crypto): Clean up BIP340 signature processing (#1233)
Browse files Browse the repository at this point in the history
A somewhat confusing k256 API led me to believe it did not correctly
handle the situation where the y coordinate of the public key was odd.
This is not the case, and the code to explicitly flip the public or
private keys during signature generation/verification is not required.
  • Loading branch information
randombit authored Oct 2, 2024
1 parent 83cb52d commit 9fe63e2
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 22 deletions.
26 changes: 5 additions & 21 deletions rs/crypto/secp256k1/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -500,16 +500,7 @@ impl PrivateKey {
message: &[u8; 32],
aux_rand: &[u8; 32],
) -> Option<[u8; 64]> {
let need_flip = self.public_key().serialize_sec1(true)[0] == 0x03;

let bip340 = if need_flip {
let ns = self.key.to_nonzero_scalar().negate();
let nz_ns =
k256::NonZeroScalar::new(ns).expect("Negation of non-zero is always non-zero");
k256::schnorr::SigningKey::from(nz_ns)
} else {
k256::schnorr::SigningKey::from(&self.key)
};
let bip340 = k256::schnorr::SigningKey::from(&self.key);

bip340
.sign_prehash_with_aux_rand(message, aux_rand)
Expand Down Expand Up @@ -833,25 +824,18 @@ impl PublicKey {

/// Verify a BIP340 (message,signature) pair
pub fn verify_bip340_signature(&self, message: &[u8], signature: &[u8]) -> bool {
use k256::elliptic_curve::point::AffineCoordinates;
use k256::schnorr::signature::hazmat::PrehashVerifier;
use std::ops::Neg;

let signature = match k256::schnorr::Signature::try_from(signature) {
Ok(sig) => sig,
Err(_) => return false,
};

let pt = self.key.to_projective().to_affine();
let pt = self.serialize_sec1(true);

let pt = if pt.y_is_odd().into() { pt.neg() } else { pt };

if let Ok(pk) = k256::PublicKey::from_affine(pt) {
if let Ok(bip340) = k256::schnorr::VerifyingKey::try_from(pk) {
bip340.verify_prehash(message, &signature).is_ok()
} else {
false
}
// from_bytes takes just the x coordinate encoding:
if let Ok(bip340) = k256::schnorr::VerifyingKey::from_bytes(&pt[1..]) {
bip340.verify_prehash(message, &signature).is_ok()
} else {
false
}
Expand Down
1 change: 0 additions & 1 deletion rs/crypto/secp256k1/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ fn should_accept_bip340_signatures_that_we_generate() {
let sk = PrivateKey::generate_using_rng(&mut rng);

let pk = sk.public_key();
println!("{}", hex::encode(pk.serialize_sec1(true)));

let mut msg = rng.gen::<[u8; 32]>();
rng.fill_bytes(&mut msg);
Expand Down

0 comments on commit 9fe63e2

Please sign in to comment.