diff --git a/Cargo.lock b/Cargo.lock index 6479e57e..61ec137b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,6 +39,7 @@ dependencies = [ "hex", "miniscript", "pretty_assertions", + "secp256k1", "snafu", ] @@ -90,6 +91,12 @@ dependencies = [ "hex-conservative", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cc" version = "1.1.18" @@ -99,12 +106,29 @@ dependencies = [ "shlex", ] +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "heck" version = "0.5.0" @@ -132,6 +156,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + [[package]] name = "miniscript" version = "12.2.0" @@ -142,6 +172,15 @@ dependencies = [ "bitcoin", ] +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "pretty_assertions" version = "1.4.1" @@ -170,6 +209,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "secp256k1" version = "0.29.1" @@ -177,6 +246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "bitcoin_hashes", + "rand", "secp256k1-sys", ] @@ -233,8 +303,35 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "yansi" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index ee451c12..b661897c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ bitcoin = "0.32.3" hex = "0.4.3" miniscript = "12.2.0" snafu = { version = "0.8.5", default-features = false, features = ["rust_1_61", "std"] } +secp256k1 = { version = "0.29.1", features = ["global-context", "rand-std"] } [dev-dependencies] pretty_assertions = "1.4.1" diff --git a/src/lib.rs b/src/lib.rs index 94ed2c2f..d3e61b16 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ use { opcodes, psbt::Psbt, script::PushBytes, - secp256k1::{self, schnorr::Signature, Message, Secp256k1, XOnlyPublicKey}, + secp256k1::{self, Secp256k1, Message, schnorr::Signature, XOnlyPublicKey}, sighash::{self, SighashCache, TapSighashType}, transaction::Version, Address, Amount, EcdsaSighashType, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence, diff --git a/src/sign.rs b/src/sign.rs index 3cf84fe6..297e8d31 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -175,7 +175,7 @@ fn create_message_signature_taproot( .tap_tweak(&secp, to_sign.inputs[0].tap_merkle_root) .to_inner(); - let signature = secp.sign_schnorr_no_aux_rand( + let signature = secp.sign_schnorr( &secp256k1::Message::from_digest_slice(sighash.as_ref()) .expect("should be cryptographically secure hash"), &key_pair, diff --git a/src/verify.rs b/src/verify.rs index dafa19df..1da20efe 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -53,6 +53,7 @@ pub fn verify_simple(address: &Address, message: &[u8], signature: Witness) -> R /// Verifies the BIP-322 full from proper Rust types. pub fn verify_full(address: &Address, message: &[u8], to_sign: Transaction) -> Result<()> { match address.to_address_data() { + // Handle P2TR (Taproot) addresses AddressData::Segwit { witness_program } if witness_program.version().to_num() == 1 && witness_program.program().len() == 32 => { @@ -61,6 +62,7 @@ pub fn verify_full(address: &Address, message: &[u8], to_sign: Transaction) -> R verify_full_p2tr(address, message, to_sign, pub_key) } + // Handle P2WPKH addresses AddressData::Segwit { witness_program } if witness_program.version().to_num() == 0 && witness_program.program().len() == 20 => { @@ -69,12 +71,14 @@ pub fn verify_full(address: &Address, message: &[u8], to_sign: Transaction) -> R verify_full_p2wpkh(address, message, to_sign, pub_key, false) } + // Handle P2SH-wrapped segwit addresses AddressData::P2sh { script_hash: _ } => { let pub_key = PublicKey::from_slice(&to_sign.input[0].witness[1]).map_err(|_| Error::InvalidPublicKey)?; verify_full_p2wpkh(address, message, to_sign, pub_key, true) } + // All other address types are unsupported _ => Err(Error::UnsupportedAddress { address: address.to_string(), }), @@ -184,9 +188,7 @@ fn verify_full_p2tr( return Err(Error::ToSignInvalid); } - let witness = if let Some(witness) = to_sign.inputs[0].final_script_witness.clone() { - witness - } else { + let Some(witness) = to_sign.inputs[0].final_script_witness.clone() else { return Err(Error::WitnessEmpty); };