Skip to content

Commit

Permalink
Merge rust-bitcoin#3397: Implement Arbitrary for signature types
Browse files Browse the repository at this point in the history
74a992a Implement Arbitrary for signature types (Shing Him Ng)

Pull request description:

  Implementing `Arbitrary` for some signature types in preparation for rust-bitcoin#3366

ACKs for top commit:
  tcharding:
    ACK 74a992a
  apoelstra:
    ACK 74a992a successfully ran local tests

Tree-SHA512: 8bfab4d70b6c8d51374177764323fe4b2bac5c0ac25ef39162fb95040948f27465f488df2094488aab28bdb9656521269b65f8ad7952ed2c5f91589bce084560
  • Loading branch information
apoelstra committed Sep 28, 2024
2 parents 8740f0e + 74a992a commit 10f1968
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 0 deletions.
37 changes: 37 additions & 0 deletions bitcoin/src/crypto/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use core::str::FromStr;
use core::{fmt, iter};

#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
use hex::FromHex;
use internals::{impl_to_hex_from_lower_hex, write_err};
use io::Write;
Expand Down Expand Up @@ -293,6 +295,41 @@ impl From<DecodeError> for ParseSignatureError {
fn from(e: DecodeError) -> Self { Self::Decode(e) }
}

#[cfg(feature = "arbitrary")]
impl<'a> Arbitrary<'a> for Signature {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
// The valid range of r and s should be between 0 and n-1 where
// n = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141
let high_min = 0x0u128;
let high_max = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEu128;
let low_min = 0x0u128;
let low_max = 0xBAAEDCE6AF48A03BBFD25E8CD0364140u128;

// Equally weight the chances of getting a minimum value for a signature, maximum value for
// a signature, and an arbitrary valid signature
let choice = u.int_in_range(0..=2)?;
let (high, low) = match choice {
0 => (high_min, low_min),
1 => (high_max, low_max),
_ => (u.int_in_range(high_min..=high_max)?, u.int_in_range(low_min..=low_max)?),
};

// We can use the same bytes for r and s since they're just arbitrary values
let mut bytes: [u8; 32] = [0; 32];
bytes[..16].copy_from_slice(&high.to_be_bytes());
bytes[16..].copy_from_slice(&low.to_be_bytes());

let mut signature_bytes: [u8; 64] = [0; 64];
signature_bytes[..32].copy_from_slice(&bytes);
signature_bytes[32..].copy_from_slice(&bytes);

Ok(Signature{
signature: secp256k1::ecdsa::Signature::from_compact(&signature_bytes).unwrap(),
sighash_type: EcdsaSighashType::arbitrary(u)?,
})
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
33 changes: 33 additions & 0 deletions bitcoin/src/crypto/sighash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
use core::{fmt, str};

#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
use hashes::{hash_newtype, sha256, sha256d, sha256t, sha256t_tag};
use internals::write_err;
use io::Write;
Expand Down Expand Up @@ -1467,6 +1469,37 @@ impl<E: std::error::Error + 'static> std::error::Error for SigningDataError<E> {
}
}

#[cfg(feature = "arbitrary")]
impl<'a> Arbitrary<'a> for EcdsaSighashType {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let choice = u.int_in_range(0..=5)?;
match choice {
0 => Ok(EcdsaSighashType::All),
1 => Ok(EcdsaSighashType::None),
2 => Ok(EcdsaSighashType::Single),
3 => Ok(EcdsaSighashType::AllPlusAnyoneCanPay),
4 => Ok(EcdsaSighashType::NonePlusAnyoneCanPay),
_ => Ok(EcdsaSighashType::SinglePlusAnyoneCanPay)
}
}
}

#[cfg(feature = "arbitrary")]
impl<'a> Arbitrary<'a> for TapSighashType {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let choice = u.int_in_range(0..=6)?;
match choice {
0 => Ok(TapSighashType::Default),
1 => Ok(TapSighashType::All),
2 => Ok(TapSighashType::None),
3 => Ok(TapSighashType::Single),
4 => Ok(TapSighashType::AllPlusAnyoneCanPay),
5 => Ok(TapSighashType::NonePlusAnyoneCanPay),
_ => Ok(TapSighashType::SinglePlusAnyoneCanPay)
}
}
}

#[cfg(test)]
mod tests {
use hashes::HashEngine;
Expand Down
14 changes: 14 additions & 0 deletions bitcoin/src/crypto/taproot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
use core::fmt;

#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
use internals::write_err;
use io::Write;

Expand Down Expand Up @@ -133,3 +135,15 @@ impl From<secp256k1::Error> for SigFromSliceError {
impl From<InvalidSighashTypeError> for SigFromSliceError {
fn from(err: InvalidSighashTypeError) -> Self { Self::SighashType(err) }
}

#[cfg(feature = "arbitrary")]
impl<'a> Arbitrary<'a> for Signature {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let arbitrary_bytes: [u8; secp256k1::constants::SCHNORR_SIGNATURE_SIZE] = u.arbitrary()?;

Ok(Signature {
signature: secp256k1::schnorr::Signature::from_slice(&arbitrary_bytes).unwrap(),
sighash_type: TapSighashType::arbitrary(u)?,
})
}
}

0 comments on commit 10f1968

Please sign in to comment.