Merge rust-bitcoin/rust-bitcoin#3397: Implement Arbitrary for signature types

74a992a5c4 Implement Arbitrary for signature types (Shing Him Ng)

Pull request description:

  Implementing `Arbitrary` for some signature types in preparation for #3366

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

Tree-SHA512: 8bfab4d70b6c8d51374177764323fe4b2bac5c0ac25ef39162fb95040948f27465f488df2094488aab28bdb9656521269b65f8ad7952ed2c5f91589bce084560
This commit is contained in:
merge-script 2024-09-28 12:16:23 +00:00
commit 10f19683cb
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
3 changed files with 84 additions and 0 deletions

View File

@ -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;
@ -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::*;

View File

@ -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;
@ -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;

View File

@ -6,6 +6,8 @@
use core::fmt;
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
use internals::write_err;
use io::Write;
@ -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)?,
})
}
}