From 8a843cff94e5ac58d72849b62e17ed8f0083ef59 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 21 Mar 2024 17:14:19 +1100 Subject: [PATCH] bitcoin: Depend on tip of master --- Cargo.toml | 35 ++++++++++++++-- bitcoind-tests/Cargo.toml | 4 +- examples/sign_multisig.rs | 4 +- examples/verify_tx.rs | 4 +- src/descriptor/key.rs | 85 +++++++++++++++++++------------------- src/descriptor/mod.rs | 8 ++-- src/descriptor/segwitv0.rs | 6 +-- src/interpreter/error.rs | 6 +-- src/interpreter/mod.rs | 31 +++++++------- src/lib.rs | 22 ++++++++-- src/miniscript/decode.rs | 2 +- src/miniscript/mod.rs | 8 ++-- src/psbt/finalizer.rs | 10 +++-- src/psbt/mod.rs | 55 ++++++++++++++---------- 14 files changed, 168 insertions(+), 112 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c78a20d0b..f2f77a615 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" [features] default = ["std"] std = ["bitcoin/std", "bitcoin/secp-recovery", "bech32/std"] -no-std = ["bitcoin/no-std", "bech32/alloc"] +no-std = ["bech32/alloc"] compiler = [] trace = [] @@ -23,15 +23,15 @@ base64 = ["bitcoin/base64"] [dependencies] bech32 = { version = "0.11.0", default-features = false } -bitcoin = { version = "0.31.0", default-features = false } +bitcoin = { version = "0.32.0", default-features = false } # Do NOT use this as a feature! Use the `serde` feature instead. actual-serde = { package = "serde", version = "1.0.103", optional = true } [dev-dependencies] serde_test = "1.0.147" -bitcoin = { version = "0.31.0", features = ["base64"] } -secp256k1 = {version = "0.28.0", features = ["rand-std"]} +bitcoin = { version = "0.32.0", features = ["base64"] } +secp256k1 = {version = "0.29.0", features = ["rand-std"]} [[example]] name = "htlc" @@ -68,3 +68,30 @@ required-features = ["std", "base64", "compiler"] [workspace] members = ["bitcoind-tests", "fuzz"] exclude = ["embedded"] + +[patch.crates-io.secp256k1] +path = "/home/tobin/build/github.com/tcharding/rust-secp256k1/test-bitcoin" + +[patch.crates-io.bitcoind] +path = "/home/tobin/build/github.com/tcharding/bitcoind/test-bitcoin" + +[patch.crates-io.bitcoincore-rpc] +path = "/home/tobin/build/github.com/tcharding/rust-bitcoincore-rpc/test-bitcoin/client" + +[patch.crates-io.base58ck] +path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/base58" + +[patch.crates-io.bitcoin] +path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/bitcoin" + +[patch.crates-io.bitcoin_hashes] +path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/hashes" + +[patch.crates-io.bitcoin-internals] +path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/internals" + +[patch.crates-io.bitcoin-io] +path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/io" + +[patch.crates-io.bitcoin-units] +path = "/home/tobin/build/github.com/tcharding/rust-bitcoin/release/units" diff --git a/bitcoind-tests/Cargo.toml b/bitcoind-tests/Cargo.toml index 1e5d11359..ded96ba64 100644 --- a/bitcoind-tests/Cargo.toml +++ b/bitcoind-tests/Cargo.toml @@ -9,6 +9,6 @@ publish = false [dependencies] miniscript = {path = "../"} -bitcoind = { version = "0.34.0" } +bitcoind = { version = "0.35.0" } actual-rand = { package = "rand", version = "0.8.4"} -secp256k1 = {version = "0.28.0", features = ["rand-std"]} +secp256k1 = {version = "0.29.0", features = ["rand-std"]} diff --git a/examples/sign_multisig.rs b/examples/sign_multisig.rs index ae51ecd72..66711ea93 100644 --- a/examples/sign_multisig.rs +++ b/examples/sign_multisig.rs @@ -118,7 +118,7 @@ fn list_of_three_arbitrary_public_keys() -> Vec { // a valid signature for this transaction; Miniscript does not verify the validity. fn random_signature_from_the_blockchain() -> ecdsa::Signature { ecdsa::Signature { - sig: secp256k1::ecdsa::Signature::from_str( + signature: secp256k1::ecdsa::Signature::from_str( "3045\ 0221\ 00f7c3648c390d87578cd79c8016940aa8e3511c4104cb78daa8fb8e429375efc1\ @@ -126,6 +126,6 @@ fn random_signature_from_the_blockchain() -> ecdsa::Signature { 531d75c136272f127a5dc14acc0722301cbddc222262934151f140da345af177", ) .unwrap(), - hash_ty: bitcoin::sighash::EcdsaSighashType::All, + sighash_type: bitcoin::sighash::EcdsaSighashType::All, } } diff --git a/examples/verify_tx.rs b/examples/verify_tx.rs index c23e2d4bc..05160ca6b 100644 --- a/examples/verify_tx.rs +++ b/examples/verify_tx.rs @@ -87,9 +87,9 @@ fn main() { let iter = interpreter.iter_custom(Box::new(|key_sig: &KeySigPair| { let (pk, ecdsa_sig) = key_sig.as_ecdsa().expect("Ecdsa Sig"); - ecdsa_sig.hash_ty == bitcoin::sighash::EcdsaSighashType::All + ecdsa_sig.sighash_type == bitcoin::sighash::EcdsaSighashType::All && secp - .verify_ecdsa(&message, &ecdsa_sig.sig, &pk.inner) + .verify_ecdsa(&message, &ecdsa_sig.signature, &pk.inner) .is_ok() })); diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index 85bb27ac5..2052145ec 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -7,7 +7,6 @@ use core::str::FromStr; use std::error; use bitcoin::bip32::{self, XKeyIdentifier}; -use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::{hash160, ripemd160, sha256, Hash, HashEngine}; use bitcoin::key::XOnlyPublicKey; use bitcoin::secp256k1::{Secp256k1, Signing, Verification}; @@ -906,21 +905,21 @@ impl DescriptorXKey { /// assert_eq!( /// xpub.matches(&( /// bip32::Fingerprint::from_str("d34db33f").or(Err(()))?, - /// bip32::DerivationPath::from_str("m/44'/0'/0'/1/42").or(Err(()))? + /// bip32::DerivationPath::from_str("44'/0'/0'/1/42").or(Err(()))? /// ), &ctx), - /// Some(bip32::DerivationPath::from_str("m/44'/0'/0'/1").or(Err(()))?) + /// Some(bip32::DerivationPath::from_str("44'/0'/0'/1").or(Err(()))?) /// ); /// assert_eq!( /// xpub.matches(&( /// bip32::Fingerprint::from_str("ffffffff").or(Err(()))?, - /// bip32::DerivationPath::from_str("m/44'/0'/0'/1/42").or(Err(()))? + /// bip32::DerivationPath::from_str("44'/0'/0'/1/42").or(Err(()))? /// ), &ctx), /// None /// ); /// assert_eq!( /// xpub.matches(&( /// bip32::Fingerprint::from_str("d34db33f").or(Err(()))?, - /// bip32::DerivationPath::from_str("m/44'/0'/0'/100/0").or(Err(()))? + /// bip32::DerivationPath::from_str("44'/0'/0'/100/0").or(Err(()))? /// ), &ctx), /// None /// ); @@ -1234,17 +1233,17 @@ mod test { fn test_wildcard() { let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2").unwrap(); assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00"); - assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "m/0'/1'/2"); + assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'/2"); assert!(!public_key.has_wildcard()); let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*").unwrap(); assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00"); - assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "m/0'/1'"); + assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'"); assert!(public_key.has_wildcard()); let public_key = DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/*h").unwrap(); assert_eq!(public_key.master_fingerprint().to_string(), "abcdef00"); - assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "m/0'/1'"); + assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'"); assert!(public_key.has_wildcard()); } @@ -1256,32 +1255,32 @@ mod test { let public_key = secret_key.to_public(&secp).unwrap(); assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2"); assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d"); - assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "m/0'/1'/2"); + assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'/2"); assert!(!public_key.has_wildcard()); let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2'").unwrap(); let public_key = secret_key.to_public(&secp).unwrap(); assert_eq!(public_key.to_string(), "[2cbe2a6d/0'/1'/2']tpubDDPuH46rv4dbFtmF6FrEtJEy1CvLZonyBoVxF6xsesHdYDdTBrq2mHhm8AbsPh39sUwL2nZyxd6vo4uWNTU9v4t893CwxjqPnwMoUACLvMV"); assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d"); - assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "m/0'/1'/2'"); + assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0'/1'/2'"); let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0/1/2").unwrap(); let public_key = secret_key.to_public(&secp).unwrap(); assert_eq!(public_key.to_string(), "tpubD6NzVbkrYhZ4WQdzxL7NmJN7b85ePo4p6RSj9QQHF7te2RR9iUeVSGgnGkoUsB9LBRosgvNbjRv9bcsJgzgBd7QKuxDm23ZewkTRzNSLEDr/0/1/2"); assert_eq!(public_key.master_fingerprint().to_string(), "2cbe2a6d"); - assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "m/0/1/2"); + assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0/1/2"); let secret_key = DescriptorSecretKey::from_str("[aabbccdd]tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0/1/2").unwrap(); let public_key = secret_key.to_public(&secp).unwrap(); assert_eq!(public_key.to_string(), "[aabbccdd]tpubD6NzVbkrYhZ4WQdzxL7NmJN7b85ePo4p6RSj9QQHF7te2RR9iUeVSGgnGkoUsB9LBRosgvNbjRv9bcsJgzgBd7QKuxDm23ZewkTRzNSLEDr/0/1/2"); assert_eq!(public_key.master_fingerprint().to_string(), "aabbccdd"); - assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "m/0/1/2"); + assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "0/1/2"); let secret_key = DescriptorSecretKey::from_str("[aabbccdd/90']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2").unwrap(); let public_key = secret_key.to_public(&secp).unwrap(); assert_eq!(public_key.to_string(), "[aabbccdd/90'/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2"); assert_eq!(public_key.master_fingerprint().to_string(), "aabbccdd"); - assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "m/90'/0'/1'/2"); + assert_eq!(public_key.full_derivation_path().unwrap().to_string(), "90'/0'/1'/2"); } #[test] @@ -1323,10 +1322,10 @@ mod test { assert_eq!( xpub.derivation_paths.paths(), &vec![ - bip32::DerivationPath::from_str("m/2/0").unwrap(), - bip32::DerivationPath::from_str("m/2/1").unwrap(), - bip32::DerivationPath::from_str("m/2/42").unwrap(), - bip32::DerivationPath::from_str("m/2/9854").unwrap() + bip32::DerivationPath::from_str("2/0").unwrap(), + bip32::DerivationPath::from_str("2/1").unwrap(), + bip32::DerivationPath::from_str("2/42").unwrap(), + bip32::DerivationPath::from_str("2/9854").unwrap() ], ); assert_eq!( @@ -1338,9 +1337,9 @@ mod test { assert_eq!( xpub.derivation_paths.paths(), &vec![ - bip32::DerivationPath::from_str("m/2/0/0/5/10").unwrap(), - bip32::DerivationPath::from_str("m/2/1/0/5/10").unwrap(), - bip32::DerivationPath::from_str("m/2/9854/0/5/10").unwrap() + bip32::DerivationPath::from_str("2/0/0/5/10").unwrap(), + bip32::DerivationPath::from_str("2/1/0/5/10").unwrap(), + bip32::DerivationPath::from_str("2/9854/0/5/10").unwrap() ], ); assert_eq!( @@ -1353,9 +1352,9 @@ mod test { assert_eq!( xpub.derivation_paths.paths(), &vec![ - bip32::DerivationPath::from_str("m/2/0/3456/9876").unwrap(), - bip32::DerivationPath::from_str("m/2/1/3456/9876").unwrap(), - bip32::DerivationPath::from_str("m/2/9854/3456/9876").unwrap() + bip32::DerivationPath::from_str("2/0/3456/9876").unwrap(), + bip32::DerivationPath::from_str("2/1/3456/9876").unwrap(), + bip32::DerivationPath::from_str("2/9854/3456/9876").unwrap() ], ); assert_eq!( @@ -1368,8 +1367,8 @@ mod test { assert_eq!( xpub.derivation_paths.paths(), &vec![ - bip32::DerivationPath::from_str("m/0").unwrap(), - bip32::DerivationPath::from_str("m/1").unwrap(), + bip32::DerivationPath::from_str("0").unwrap(), + bip32::DerivationPath::from_str("1").unwrap(), ], ); assert_eq!( @@ -1383,8 +1382,8 @@ mod test { assert_eq!( xpub.derivation_paths.paths(), &vec![ - bip32::DerivationPath::from_str("m/9478'/0'/8'").unwrap(), - bip32::DerivationPath::from_str("m/9478h/1h/8h").unwrap(), + bip32::DerivationPath::from_str("9478'/0'/8'").unwrap(), + bip32::DerivationPath::from_str("9478h/1h/8h").unwrap(), ], ); assert_eq!( @@ -1399,8 +1398,8 @@ mod test { assert_eq!( desc_key.full_derivation_paths(), vec![ - bip32::DerivationPath::from_str("m/0'/1'/9478'/0'/8'").unwrap(), - bip32::DerivationPath::from_str("m/0'/1'/9478'/1/8'").unwrap(), + bip32::DerivationPath::from_str("0'/1'/9478'/0'/8'").unwrap(), + bip32::DerivationPath::from_str("0'/1'/9478'/1/8'").unwrap(), ], ); assert_eq!(desc_key.into_single_keys(), vec![DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/9478'/0'/8h/*'").unwrap(), DescriptorPublicKey::from_str("[abcdef00/0'/1']tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/9478'/1/8h/*'").unwrap()]); @@ -1410,10 +1409,10 @@ mod test { assert_eq!( xprv.derivation_paths.paths(), &vec![ - bip32::DerivationPath::from_str("m/2/0").unwrap(), - bip32::DerivationPath::from_str("m/2/1").unwrap(), - bip32::DerivationPath::from_str("m/2/42").unwrap(), - bip32::DerivationPath::from_str("m/2/9854").unwrap() + bip32::DerivationPath::from_str("2/0").unwrap(), + bip32::DerivationPath::from_str("2/1").unwrap(), + bip32::DerivationPath::from_str("2/42").unwrap(), + bip32::DerivationPath::from_str("2/9854").unwrap() ], ); assert_eq!( @@ -1424,9 +1423,9 @@ mod test { assert_eq!( xprv.derivation_paths.paths(), &vec![ - bip32::DerivationPath::from_str("m/2/0/0/5/10").unwrap(), - bip32::DerivationPath::from_str("m/2/1/0/5/10").unwrap(), - bip32::DerivationPath::from_str("m/2/9854/0/5/10").unwrap() + bip32::DerivationPath::from_str("2/0/0/5/10").unwrap(), + bip32::DerivationPath::from_str("2/1/0/5/10").unwrap(), + bip32::DerivationPath::from_str("2/9854/0/5/10").unwrap() ], ); assert_eq!( @@ -1438,9 +1437,9 @@ mod test { assert_eq!( xprv.derivation_paths.paths(), &vec![ - bip32::DerivationPath::from_str("m/2/0/3456/9876").unwrap(), - bip32::DerivationPath::from_str("m/2/1/3456/9876").unwrap(), - bip32::DerivationPath::from_str("m/2/9854/3456/9876").unwrap() + bip32::DerivationPath::from_str("2/0/3456/9876").unwrap(), + bip32::DerivationPath::from_str("2/1/3456/9876").unwrap(), + bip32::DerivationPath::from_str("2/9854/3456/9876").unwrap() ], ); assert_eq!( @@ -1452,8 +1451,8 @@ mod test { assert_eq!( xprv.derivation_paths.paths(), &vec![ - bip32::DerivationPath::from_str("m/0").unwrap(), - bip32::DerivationPath::from_str("m/1").unwrap(), + bip32::DerivationPath::from_str("0").unwrap(), + bip32::DerivationPath::from_str("1").unwrap(), ], ); assert_eq!( @@ -1465,8 +1464,8 @@ mod test { assert_eq!( xprv.derivation_paths.paths(), &vec![ - bip32::DerivationPath::from_str("m/9478'/0'/8'").unwrap(), - bip32::DerivationPath::from_str("m/9478h/1h/8h").unwrap(), + bip32::DerivationPath::from_str("9478'/0'/8'").unwrap(), + bip32::DerivationPath::from_str("9478h/1h/8h").unwrap(), ], ); assert_eq!( diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index bea539920..ef60c0b85 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -1266,8 +1266,8 @@ mod tests { ) -> Option { if *pk == self.pk { Some(bitcoin::ecdsa::Signature { - sig: self.sig, - hash_ty: bitcoin::sighash::EcdsaSighashType::All, + signature: self.sig, + sighash_type: bitcoin::sighash::EcdsaSighashType::All, }) } else { None @@ -1533,11 +1533,11 @@ mod tests { satisfier.insert( a, - bitcoin::ecdsa::Signature { sig: sig_a, hash_ty: EcdsaSighashType::All }, + bitcoin::ecdsa::Signature { signature: sig_a, sighash_type: EcdsaSighashType::All }, ); satisfier.insert( b, - bitcoin::ecdsa::Signature { sig: sig_b, hash_ty: EcdsaSighashType::All }, + bitcoin::ecdsa::Signature { signature: sig_b, sighash_type: EcdsaSighashType::All }, ); satisfier diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index 541f0f0db..48c330d6a 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -371,15 +371,13 @@ impl Wpkh { impl Wpkh { /// Obtains the corresponding script pubkey for this descriptor. pub fn script_pubkey(&self) -> ScriptBuf { - let addr = Address::p2wpkh(&self.pk.to_public_key(), Network::Bitcoin) - .expect("wpkh descriptors have compressed keys"); + let addr = Address::p2wpkh(&self.pk.to_compressed_public_key(), Network::Bitcoin); addr.script_pubkey() } /// Obtains the corresponding script pubkey for this descriptor. pub fn address(&self, network: Network) -> Address { - Address::p2wpkh(&self.pk.to_public_key(), network) - .expect("Rust Miniscript types don't allow uncompressed pks in segwit descriptors") + Address::p2wpkh(&self.pk.to_compressed_public_key(), network) } /// Obtains the underlying miniscript for this descriptor. diff --git a/src/interpreter/error.rs b/src/interpreter/error.rs index d19c28bea..4e47932a6 100644 --- a/src/interpreter/error.rs +++ b/src/interpreter/error.rs @@ -95,7 +95,7 @@ pub enum Error { /// Schnorr Signature error SchnorrSig(bitcoin::taproot::SigFromSliceError), /// Errors in signature hash calculations - SighashError(bitcoin::sighash::Error), + SighashError(bitcoin::sighash::InvalidSighashTypeError), /// Taproot Annex Unsupported TapAnnexUnsupported, /// An uncompressed public key was encountered in a context where it is @@ -242,8 +242,8 @@ impl From for Error { } #[doc(hidden)] -impl From for Error { - fn from(e: bitcoin::sighash::Error) -> Error { Error::SighashError(e) } +impl From for Error { + fn from(e: bitcoin::sighash::InvalidSighashTypeError) -> Error { Error::SighashError(e) } } #[doc(hidden)] diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 55ec97ed4..0298bdbaa 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -211,7 +211,7 @@ impl<'txin> Interpreter<'txin> { KeySigPair::Ecdsa(key, ecdsa_sig) => { let script_pubkey = self.script_code.as_ref().expect("Legacy have script code"); let msg = if self.is_legacy() { - let sighash_u32 = ecdsa_sig.hash_ty.to_u32(); + let sighash_u32 = ecdsa_sig.sighash_type.to_u32(); let sighash = cache.legacy_signature_hash(input_idx, script_pubkey, sighash_u32); sighash.map(|hash| secp256k1::Message::from_digest(hash.to_byte_array())) @@ -220,11 +220,12 @@ impl<'txin> Interpreter<'txin> { Some(txout) => txout.borrow().value, None => return false, }; - let sighash = cache.segwit_signature_hash( + // TODO: Don't manually handle the script code. + let sighash = cache.p2wsh_signature_hash( input_idx, script_pubkey, amt, - ecdsa_sig.hash_ty, + ecdsa_sig.sighash_type, ); sighash.map(|hash| secp256k1::Message::from_digest(hash.to_byte_array())) } else { @@ -233,12 +234,12 @@ impl<'txin> Interpreter<'txin> { }; let success = - msg.map(|msg| secp.verify_ecdsa(&msg, &ecdsa_sig.sig, &key.inner).is_ok()); + msg.map(|msg| secp.verify_ecdsa(&msg, &ecdsa_sig.signature, &key.inner).is_ok()); success.unwrap_or(false) // unwrap_or checks for errors, while success would have checksig results } KeySigPair::Schnorr(xpk, schnorr_sig) => { let sighash_msg = if self.is_taproot_v1_key_spend() { - cache.taproot_key_spend_signature_hash(input_idx, prevouts, schnorr_sig.hash_ty) + cache.taproot_key_spend_signature_hash(input_idx, prevouts, schnorr_sig.sighash_type) } else if self.is_taproot_v1_script_spend() { let tap_script = self.script_code.as_ref().expect( "Internal Hack: Saving leaf script instead\ @@ -252,7 +253,7 @@ impl<'txin> Interpreter<'txin> { input_idx, prevouts, leaf_hash, - schnorr_sig.hash_ty, + schnorr_sig.sighash_type, ) } else { // schnorr sigs in ecdsa descriptors @@ -261,7 +262,7 @@ impl<'txin> Interpreter<'txin> { let msg = sighash_msg.map(|hash| secp256k1::Message::from_digest(hash.to_byte_array())); let success = - msg.map(|msg| secp.verify_schnorr(&schnorr_sig.sig, &msg, xpk).is_ok()); + msg.map(|msg| secp.verify_schnorr(&schnorr_sig.signature, &msg, xpk).is_ok()); success.unwrap_or(false) // unwrap_or_default checks for errors, while success would have checksig results } } @@ -1062,12 +1063,12 @@ mod tests { inner: secp256k1::PublicKey::from_secret_key(&secp, &sk), compressed: true, }; - let sig = secp.sign_ecdsa(&msg, &sk); + let signature = secp.sign_ecdsa(&msg, &sk); ecdsa_sigs.push(bitcoin::ecdsa::Signature { - sig, - hash_ty: bitcoin::sighash::EcdsaSighashType::All, + signature, + sighash_type: bitcoin::sighash::EcdsaSighashType::All, }); - let mut sigser = sig.serialize_der().to_vec(); + let mut sigser = signature.serialize_der().to_vec(); sigser.push(0x01); // sighash_all pks.push(pk); der_sigs.push(sigser); @@ -1077,8 +1078,8 @@ mod tests { x_only_pks.push(x_only_pk); let schnorr_sig = secp.sign_schnorr_with_aux_rand(&msg, &keypair, &[0u8; 32]); let schnorr_sig = bitcoin::taproot::Signature { - sig: schnorr_sig, - hash_ty: bitcoin::sighash::TapSighashType::Default, + signature: schnorr_sig, + sighash_type: bitcoin::sighash::TapSighashType::Default, }; ser_schnorr_sigs.push(schnorr_sig.to_vec()); schnorr_sigs.push(schnorr_sig); @@ -1093,10 +1094,10 @@ mod tests { let secp_ref = &secp; let vfyfn = |pksig: &KeySigPair| match pksig { KeySigPair::Ecdsa(pk, ecdsa_sig) => secp_ref - .verify_ecdsa(&sighash, &ecdsa_sig.sig, &pk.inner) + .verify_ecdsa(&sighash, &ecdsa_sig.signature, &pk.inner) .is_ok(), KeySigPair::Schnorr(xpk, schnorr_sig) => secp_ref - .verify_schnorr(&schnorr_sig.sig, &sighash, xpk) + .verify_schnorr(&schnorr_sig.signature, &sighash, xpk) .is_ok(), }; diff --git a/src/lib.rs b/src/lib.rs index 6c644e6e4..670b566ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -222,6 +222,13 @@ pub trait ToPublicKey: MiniscriptKey { /// Converts an object to a public key fn to_public_key(&self) -> bitcoin::PublicKey; + /// Converts an object to a compressed public key. + fn to_compressed_public_key(&self) -> bitcoin::CompressedPublicKey { + use core::convert::TryFrom; + // TODO: Can we remove to_public_key altogether? + bitcoin::key::CompressedPublicKey::try_from(self.to_public_key()).expect("for now just panic for uncompressed keys") + } + /// Convert an object to x-only pubkey fn to_x_only_pubkey(&self) -> bitcoin::secp256k1::XOnlyPublicKey { let pk = self.to_public_key(); @@ -428,7 +435,9 @@ pub enum Error { /// rust-bitcoin script error Script(script::Error), /// rust-bitcoin address error - AddrError(bitcoin::address::Error), + AddrError(bitcoin::address::ParseError), + /// rust-bitcoin p2sh address error + AddrP2shError(bitcoin::address::P2shError), /// A `CHECKMULTISIG` opcode was preceded by a number > 20 CmsTooManyKeys(u32), /// A tapscript multi_a cannot support more than Weight::MAX_BLOCK/32 keys @@ -507,6 +516,7 @@ impl fmt::Display for Error { }, Error::Script(ref e) => fmt::Display::fmt(e, f), Error::AddrError(ref e) => fmt::Display::fmt(e, f), + Error::AddrP2shError(ref e) => fmt::Display::fmt(e, f), Error::CmsTooManyKeys(n) => write!(f, "checkmultisig with {} keys", n), Error::Unprintable(x) => write!(f, "unprintable character 0x{:02x}", x), Error::ExpectedChar(c) => write!(f, "expected {}", c), @@ -585,6 +595,7 @@ impl error::Error for Error { | MultipathDescLenMismatch => None, Script(e) => Some(e), AddrError(e) => Some(e), + AddrP2shError(e) => Some(e), Secp(e) => Some(e), #[cfg(feature = "compiler")] CompilerError(e) => Some(e), @@ -625,8 +636,13 @@ impl From for Error { } #[doc(hidden)] -impl From for Error { - fn from(e: bitcoin::address::Error) -> Error { Error::AddrError(e) } +impl From for Error { + fn from(e: bitcoin::address::ParseError) -> Error { Error::AddrError(e) } +} + +#[doc(hidden)] +impl From for Error { + fn from(e: bitcoin::address::P2shError) -> Error { Error::AddrP2shError(e) } } #[doc(hidden)] diff --git a/src/miniscript/decode.rs b/src/miniscript/decode.rs index 6500eb8d5..749686dc0 100644 --- a/src/miniscript/decode.rs +++ b/src/miniscript/decode.rs @@ -46,7 +46,7 @@ impl ParseableKey for bitcoin::secp256k1::XOnlyPublicKey { #[derive(Debug, Clone, PartialEq, Eq)] pub enum KeyParseError { /// Bitcoin PublicKey parse error - FullKeyParseError(bitcoin::key::Error), + FullKeyParseError(bitcoin::key::FromSliceError), /// Xonly key parse Error XonlyKeyParseError(bitcoin::secp256k1::Error), } diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 26f220a9f..81979c476 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -1286,8 +1286,8 @@ mod tests { _h: &TapLeafHash, ) -> Option { Some(bitcoin::taproot::Signature { - sig: self.0, - hash_ty: bitcoin::sighash::TapSighashType::Default, + signature: self.0, + sighash_type: bitcoin::sighash::TapSighashType::Default, }) } } @@ -1417,8 +1417,8 @@ mod tests { ) -> Option { if pk == &self.1 { Some(bitcoin::taproot::Signature { - sig: self.0, - hash_ty: bitcoin::sighash::TapSighashType::Default, + signature: self.0, + sighash_type: bitcoin::sighash::TapSighashType::Default, }) } else { None diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index 7dafcec53..c17335978 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -184,10 +184,11 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In } else if script_pubkey.is_p2wpkh() { // 3. `Wpkh`: creates a `wpkh` descriptor if the partial sig has corresponding pk. let partial_sig_contains_pk = inp.partial_sigs.iter().find(|&(&pk, _sig)| { + use core::convert::TryFrom; + let compressed = bitcoin::key::CompressedPublicKey::try_from(pk).expect("TODO: Handle compressed key"); // Indirect way to check the equivalence of pubkey-hashes. // Create a pubkey hash and check if they are the same. - let addr = bitcoin::Address::p2wpkh(&pk, bitcoin::Network::Bitcoin) - .expect("Address corresponding to valid pubkey"); + let addr = bitcoin::Address::p2wpkh(&compressed, bitcoin::Network::Bitcoin); *script_pubkey == addr.script_pubkey() }); match partial_sig_contains_pk { @@ -244,8 +245,9 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In } else if redeem_script.is_p2wpkh() { // 6. `ShWpkh` case let partial_sig_contains_pk = inp.partial_sigs.iter().find(|&(&pk, _sig)| { - let addr = bitcoin::Address::p2wpkh(&pk, bitcoin::Network::Bitcoin) - .expect("Address corresponding to valid pubkey"); + use core::convert::TryFrom; + let compressed = bitcoin::key::CompressedPublicKey::try_from(pk).expect("TODO: Handle compressed key"); + let addr = bitcoin::Address::p2wpkh(&compressed, bitcoin::Network::Bitcoin); *redeem_script == addr.script_pubkey() }); match partial_sig_contains_pk { diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 61027d6ad..1698774dd 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -88,7 +88,7 @@ pub enum InputError { /// Get the secp Errors directly SecpErr(bitcoin::secp256k1::Error), /// Key errors - KeyErr(bitcoin::key::Error), + KeyErr(bitcoin::key::FromSliceError), /// Could not satisfy taproot descriptor /// This error is returned when both script path and key paths could not be /// satisfied. We cannot return a detailed error because we try all miniscripts @@ -231,8 +231,8 @@ impl From for InputError { } #[doc(hidden)] -impl From for InputError { - fn from(e: bitcoin::key::Error) -> InputError { InputError::KeyErr(e) } +impl From for InputError { + fn from(e: bitcoin::key::FromSliceError) -> InputError { InputError::KeyErr(e) } } /// Psbt satisfier for at inputs at a particular index @@ -395,7 +395,7 @@ fn sanity_check(psbt: &Psbt) -> Result<(), Error> { None => sighash::EcdsaSighashType::All, }; for (key, ecdsa_sig) in &input.partial_sigs { - let flag = sighash::EcdsaSighashType::from_standard(ecdsa_sig.hash_ty as u32).map_err( + let flag = sighash::EcdsaSighashType::from_standard(ecdsa_sig.sighash_type as u32).map_err( |_| { Error::InputError( InputError::Interpreter(interpreter::Error::NonStandardSighash( @@ -736,7 +736,7 @@ impl PsbtExt for Psbt { let desc_type = desc.desc_type(); if let Some(non_witness_utxo) = &input.non_witness_utxo { - if txin.previous_output.txid != non_witness_utxo.txid() { + if txin.previous_output.txid != non_witness_utxo.compute_txid() { return Err(UtxoUpdateError::UtxoCheck); } } @@ -1315,10 +1315,12 @@ pub enum SighashError { MissingSpendUtxos, /// Invalid Sighash type InvalidSighashType, - /// Sighash computation error - /// Only happens when single does not have corresponding output as psbts - /// already have information to compute the sighash - SighashComputationError(sighash::Error), + /// Computation error for taproot sighash. + SighashTaproot(sighash::TaprootError), + /// Computation error for P2WPKH sighash. + SighashP2wpkh(sighash::P2wpkhError), + /// Computation error for P2WSH sighash. + TransactionInputsIndex(transaction::InputsIndexError), /// Missing Witness script MissingWitnessScript, /// Missing Redeem script, @@ -1334,11 +1336,11 @@ impl fmt::Display for SighashError { SighashError::MissingInputUtxo => write!(f, "Missing input utxo in pbst"), SighashError::MissingSpendUtxos => write!(f, "Missing Psbt spend utxos"), SighashError::InvalidSighashType => write!(f, "Invalid Sighash type"), - SighashError::SighashComputationError(e) => { - write!(f, "Sighash computation error : {}", e) - } SighashError::MissingWitnessScript => write!(f, "Missing Witness Script"), SighashError::MissingRedeemScript => write!(f, "Missing Redeem Script"), + SighashError::SighashTaproot(ref e) => write!(f, "sighash taproot: {}", e), + SighashError::SighashP2wpkh(ref e) => write!(f, "sighash p2wpkh: {}", e), + SighashError::TransactionInputsIndex(ref e) => write!(f, "tx inputs index: {}", e), } } } @@ -1355,13 +1357,24 @@ impl error::Error for SighashError { | InvalidSighashType | MissingWitnessScript | MissingRedeemScript => None, - SighashComputationError(e) => Some(e), + SighashTaproot(ref e) => Some(e), + SighashP2wpkh(ref e) => Some(e), + TransactionInputsIndex(ref e) => Some(e), + } } } -impl From for SighashError { - fn from(e: sighash::Error) -> Self { SighashError::SighashComputationError(e) } +impl From for SighashError { + fn from(e: sighash::TaprootError) -> Self { SighashError::SighashTaproot(e) } +} + +impl From for SighashError { + fn from(e: sighash::P2wpkhError) -> Self { SighashError::SighashP2wpkh(e) } +} + +impl From for SighashError { + fn from(e: transaction::InputsIndexError) -> Self { SighashError::TransactionInputsIndex(e) } } /// Sighash message(signing data) for a given psbt transaction input. @@ -1431,7 +1444,7 @@ mod tests { assert_eq!(psbt_input.tap_internal_key, Some(internal_key)); assert_eq!( psbt_input.tap_key_origins.get(&internal_key), - Some(&(vec![], (fingerprint, DerivationPath::from_str("m/86'/0'/0'/0/0").unwrap()))) + Some(&(vec![], (fingerprint, DerivationPath::from_str("86'/0'/0'/0/0").unwrap()))) ); assert_eq!(psbt_input.tap_key_origins.len(), 1); assert_eq!(psbt_input.tap_scripts.len(), 0); @@ -1464,7 +1477,7 @@ mod tests { assert_eq!(psbt_input.tap_internal_key, Some(internal_key)); assert_eq!( psbt_input.tap_key_origins.get(&internal_key), - Some(&(vec![], (fingerprint, DerivationPath::from_str("m/86'/0'/0'/0/0").unwrap()))) + Some(&(vec![], (fingerprint, DerivationPath::from_str("86'/0'/0'/0/0").unwrap()))) ); assert_eq!(psbt_input.tap_key_origins.len(), 3); assert_eq!(psbt_input.tap_scripts.len(), 2); @@ -1494,7 +1507,7 @@ mod tests { let (leaf_hashes, (key_fingerprint, deriv_path)) = psbt_input.tap_key_origins.get(&key_0_1).unwrap(); assert_eq!(key_fingerprint, &fingerprint); - assert_eq!(&deriv_path.to_string(), "m/86'/0'/0'/0/1"); + assert_eq!(&deriv_path.to_string(), "86'/0'/0'/0/1"); assert_eq!(leaf_hashes.len(), 2); assert!(leaf_hashes.contains(&first_leaf_hash)); } @@ -1508,7 +1521,7 @@ mod tests { let (leaf_hashes, (key_fingerprint, deriv_path)) = psbt_input.tap_key_origins.get(&key_1_0).unwrap(); assert_eq!(key_fingerprint, &fingerprint); - assert_eq!(&deriv_path.to_string(), "m/86'/0'/0'/1/0"); + assert_eq!(&deriv_path.to_string(), "86'/0'/0'/1/0"); assert_eq!(leaf_hashes.len(), 1); assert!(!leaf_hashes.contains(&first_leaf_hash)); } @@ -1534,7 +1547,7 @@ mod tests { PublicKey::from_str(pubkey).unwrap(), ( fingerprint, - DerivationPath::from_str(&format!("m/84'/0'/0'/{}", path)).unwrap(), + DerivationPath::from_str(&format!("84'/0'/0'/{}", path)).unwrap(), ), ) }) @@ -1605,7 +1618,7 @@ mod tests { version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![TxIn { - previous_output: OutPoint { txid: non_witness_utxo.txid(), vout: 0 }, + previous_output: OutPoint { txid: non_witness_utxo.compute_txid(), vout: 0 }, ..Default::default() }], output: vec![],