Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for BIP340 signtures where the messages are not exactly 32 bytes #1041

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions k256/src/schnorr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,69 @@ mod tests {
}
}

#[test]
fn bip340_ext_sign_vectors() {
// Test indexes 15-18 from https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv
//
// These tests all use the same key and aux
let sk = SigningKey::from_bytes(&hex!(
"0340034003400340034003400340034003400340034003400340034003400340"
))
.unwrap();

let aux_rand = [0u8; 32];

struct Bip340ExtTest {
index: usize,
msg: alloc::vec::Vec<u8>,
signature: [u8; 64],
}

let bip340_ext_sign_vectors = [
Bip340ExtTest {
index: 15,
msg: vec![],
signature: hex!(
"71535DB165ECD9FBBC046E5FFAEA61186BB6AD436732FCCC25291A55895464CF
6069CE26BF03466228F19A3A62DB8A649F2D560FAC652827D1AF0574E427AB63"
)
},
Bip340ExtTest {
index: 16,
msg: hex!("11").to_vec(),
signature: hex!("08A20A0AFEF64124649232E0693C583AB1B9934AE63B4C3511F3AE1134C6A303EA3173BFEA6683BD101FA5AA5DBC1996FE7CACFC5A577D33EC14564CEC2BACBF")
},
Bip340ExtTest {
index: 17,
msg: hex!("0102030405060708090A0B0C0D0E0F1011").to_vec(),
signature: hex!("5130F39A4059B43BC7CAC09A19ECE52B5D8699D1A71E3C52DA9AFDB6B50AC370C4A482B77BF960F8681540E25B6771ECE1E5A37FD80E5A51897C5566A97EA5A5"),
},
Bip340ExtTest {
index: 18,
msg: vec![0x99; 100],
signature: hex!("403B12B0D8555A344175EA7EC746566303321E5DBFA8BE6F091635163ECA79A8585ED3E3170807E7C03B720FC54C7B23897FCBA0E9D0B4A06894CFD249F22367"),
},
];

for vector in bip340_ext_sign_vectors {
let sig = sk
.sign_prehash_with_aux_rand(&vector.msg, &aux_rand)
.unwrap_or_else(|_| {
panic!(
"low-level Schnorr signing failure for index {}",
vector.index
)
});

assert_eq!(
vector.signature,
sig.to_bytes(),
"wrong signature for index {}",
vector.index
);
}
}

/// Verification test vector
struct VerifyVector {
/// Index of test case
Expand Down
13 changes: 5 additions & 8 deletions k256/src/schnorr/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl SigningKey {
/// The preferred interfaces are the [`Signer`] or [`RandomizedSigner`] traits.
pub fn sign_prehash_with_aux_rand(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this method should be renamed to reflect the input is no longer necessarily a prehash?

Something like sign_raw perhaps?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah makes sense, I renamed to sign_raw. I didn't know if you wanted to keep any compatability forwarding (eg a #[deprecated] sign_prehash_with_aux_rand that forwards to sign_raw), so I left it out for now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine. We can make a note in the changelog.

&self,
msg_digest: &[u8; 32],
msg_digest: &[u8],
aux_rand: &[u8; 32],
) -> Result<Signature> {
let mut t = tagged_hash(AUX_TAG).chain_update(aux_rand).finalize();
Expand Down Expand Up @@ -164,14 +164,13 @@ where
D: Digest + FixedOutput<OutputSize = U32>,
{
fn try_sign_digest(&self, digest: D) -> Result<Signature> {
self.sign_prehash_with_aux_rand(&digest.finalize_fixed().into(), &Default::default())
self.sign_prehash_with_aux_rand(&digest.finalize_fixed(), &Default::default())
}
}

impl PrehashSigner<Signature> for SigningKey {
fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature> {
let prehash = prehash.try_into().map_err(|_| Error::new())?;
self.sign_prehash_with_aux_rand(&prehash, &Default::default())
self.sign_prehash_with_aux_rand(prehash, &Default::default())
}
}

Expand All @@ -186,7 +185,7 @@ where
) -> Result<Signature> {
let mut aux_rand = [0u8; 32];
rng.fill_bytes(&mut aux_rand);
self.sign_prehash_with_aux_rand(&digest.finalize_fixed().into(), &aux_rand)
self.sign_prehash_with_aux_rand(&digest.finalize_fixed(), &aux_rand)
}
}

Expand All @@ -202,12 +201,10 @@ impl RandomizedPrehashSigner<Signature> for SigningKey {
rng: &mut impl CryptoRngCore,
prehash: &[u8],
) -> Result<Signature> {
let prehash = prehash.try_into().map_err(|_| Error::new())?;

let mut aux_rand = [0u8; 32];
rng.fill_bytes(&mut aux_rand);

self.sign_prehash_with_aux_rand(&prehash, &aux_rand)
self.sign_prehash_with_aux_rand(prehash, &aux_rand)
}
}

Expand Down
1 change: 0 additions & 1 deletion k256/src/schnorr/verifying.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ impl PrehashVerifier<Signature> for VerifyingKey {
prehash: &[u8],
tarcieri marked this conversation as resolved.
Show resolved Hide resolved
signature: &Signature,
) -> core::result::Result<(), Error> {
let prehash: [u8; 32] = prehash.try_into().map_err(|_| Error::new())?;
let (r, s) = signature.split();

let e = <Scalar as Reduce<U256>>::reduce_bytes(
Expand Down
Loading