diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 000000000..53338c51c --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,19 @@ +{ + "permissions": { + "allow": [ + "Bash(cargo check:*)", + "Bash(find:*)", + "Bash(xargs cat:*)", + "Bash(grep:*)", + "Bash(cargo doc:*)", + "Bash(cat:*)", + "Bash(1)", + "Bash(cargo test:*)", + "Bash(python3:*)", + "Bash(cargo clean:*)", + "Bash(awk:*)" + ], + "deny": [], + "ask": [] + } +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..17d943bf0 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,584 @@ +# Migration Guide: Upgrading to bitcoin v0.33.0-beta.0 + +This guide helps downstream projects migrate from bitcoin v0.32.x to v0.33.0-beta.0. + +## Overview + +Bitcoin v0.33.0-beta.0 represents a significant update with multiple breaking changes. The primary goals of this release are: + +1. Facilitate testing of `primitives 1.0.0-rc.x` and upcoming 1.0 releases +2. Prepare for 1.0 releases of core dependencies: + - `bitcoin-io` (1.0) + - `primitives` (1.0) + - `units` (1.0) + +## Dependency Version Updates + +Update your `Cargo.toml` dependencies: + +```toml +[dependencies] +bitcoin = "0.33.0-beta.0" +``` + +## Breaking Changes & Migration Steps + +### 1. Secp256k1 Context Changes + +**What Changed:** The secp256k1 crate removed context types from public API. Functions like `generate_keypair` are now available at the crate level. + +**Migration:** + +```rust +// Before (v0.32.x) +use secp256k1::Secp256k1; +let secp = Secp256k1::new(); +let (secret_key, public_key) = secp.generate_keypair(&mut rng); + +// After (v0.33.0) +use secp256k1; +let (secret_key, public_key) = secp256k1::generate_keypair(&mut rng); + +// For Schnorr signatures +// Before +let sig = secp.sign_schnorr_with_aux_rand(&msg, &keypair, &aux_rand); + +// After +use secp256k1::schnorr; +let sig = schnorr::sign_no_aux_rand(&msg, &keypair); // Or use aux_rand variant if needed +``` + +### 2. Transaction Default Implementations Removed + +**What Changed:** `TxOut::default()`, `OutPoint::default()`, and `TxIn::default()` removed to prevent misuse. + +**Migration:** + +```rust +// Before +let prevout = OutPoint::default(); +let input = TxIn::default(); + +// After - Use semantic constants +use bitcoin::OutPoint; +let prevout = OutPoint::COINBASE_PREVOUT; // For coinbase inputs +let input = TxIn::EMPTY_COINBASE; // For coinbase transactions + +// For regular outputs, explicitly construct: +let txout = TxOut { + value: Amount::ZERO, + script_pubkey: ScriptBuf::new(), +}; +``` + +### 3. Amount Module Reorganization + +**What Changed:** The `amount` module was reorganized and moved to the `units` crate. + +**Migration:** + +```rust +// Imports may need updating +use bitcoin::Amount; +use bitcoin::SignedAmount; + +// Amount::MAX_MONEY constant handling +// Check your usage - this constant may have changed/moved +``` + +### 4. Script Type Tagging (MAJOR BREAKING CHANGE) + +**What Changed:** The generic `Script` and `ScriptBuf` types no longer exist. Scripts are now tagged by their purpose, requiring you to specify the exact script type. This provides better type safety and prevents misuse of scripts in the wrong context. + +**Available Script Types:** + +Borrowed (reference) types: +- `ScriptPubKey` - Script public key (locking script in outputs) +- `ScriptSig` - Script signature (unlocking script in inputs) +- `RedeemScript` - P2SH redeem script +- `WitnessScript` - Segwit v0 witness script +- `TapScript` - Taproot (Segwit v1) script + +Owned types (similar to the old `ScriptBuf`): +- `ScriptPubKeyBuf` +- `ScriptSigBuf` +- `RedeemScriptBuf` +- `WitnessScriptBuf` +- `TapScriptBuf` + +**Migration:** + +The correct script type is usually obvious from context - check variable names, function parameter names, struct field names, or code comments to determine which type to use. + +```rust +// Before (v0.32.x) +use bitcoin::Script; +use bitcoin::ScriptBuf; + +fn process_output_script(script: &Script) { + // ... +} + +let mut script = ScriptBuf::new(); + +// After (v0.33.0) - Use specific types based on context +use bitcoin::script::{ScriptPubKey, ScriptPubKeyBuf}; +use bitcoin::script::{ScriptSig, ScriptSigBuf}; + +fn process_output_script(script: &ScriptPubKey) { // Variable name hints at ScriptPubKey + // ... +} + +let mut script_pubkey = ScriptPubKeyBuf::new(); +let mut script_sig = ScriptSigBuf::new(); +``` + +**Common Migration Patterns:** + +```rust +// Transaction construction +// Before +let txout = TxOut { + amount: Amount::ZERO, + script_pubkey: ScriptBuf::new(), // Generic ScriptBuf +}; + +// After +let txout = TxOut { + amount: Amount::ZERO, + script_pubkey: ScriptPubKeyBuf::new(), // Tagged as ScriptPubKeyBuf +}; + +// Transaction input scripts +// Before +let txin = TxIn { + previous_output: outpoint, + script_sig: ScriptBuf::new(), // Generic ScriptBuf + sequence: Sequence::MAX, + witness: Witness::new(), +}; + +// After +let txin = TxIn { + previous_output: outpoint, + script_sig: ScriptSigBuf::new(), // Tagged as ScriptSigBuf + sequence: Sequence::MAX, + witness: Witness::new(), +}; + +// P2SH redeem scripts +// Before +use bitcoin::Script; +let redeem_script: &Script = ...; + +// After +use bitcoin::script::RedeemScript; +let redeem_script: &RedeemScript = ...; + +// Witness scripts (SegWit v0) +// Before +let witness_script = ScriptBuf::from(...); + +// After +use bitcoin::script::WitnessScriptBuf; +let witness_script = WitnessScriptBuf::from(...); + +// Taproot scripts +// Before +let tap_script = ScriptBuf::from(...); + +// After +use bitcoin::script::TapScriptBuf; +let tap_script = TapScriptBuf::from(...); +``` + +**How to Choose the Right Type:** + +1. **Look at variable/parameter names** - `script_pubkey` → `ScriptPubKey(Buf)`, `script_sig` → `ScriptSig(Buf)` +2. **Check the context** - Output scripts are `ScriptPubKey`, input scripts are `ScriptSig` +3. **Struct field types** - `TxOut::script_pubkey` is `ScriptPubKeyBuf`, `TxIn::script_sig` is `ScriptSigBuf` +4. **Read comments** - Code comments often indicate the script type +5. **Choose borrowed vs owned** - Use borrowed types (`ScriptPubKey`) for references, owned types (`ScriptPubKeyBuf`) for owned data (similar to `&str` vs `String`) + +**Import Changes:** + +```rust +// Before +use bitcoin::Script; +use bitcoin::ScriptBuf; + +// After - Import the specific types you need +use bitcoin::script::{ScriptPubKey, ScriptPubKeyBuf}; +use bitcoin::script::{ScriptSig, ScriptSigBuf}; +use bitcoin::script::{RedeemScript, RedeemScriptBuf}; +use bitcoin::script::{WitnessScript, WitnessScriptBuf}; +use bitcoin::script::{TapScript, TapScriptBuf}; + +// Or import from the root if you prefer +use bitcoin::{ScriptPubKey, ScriptPubKeyBuf}; +``` + +### 5. Script Method Changes + +**What Changed:** `read_scriptint` moved from a free function to a method on `PushBytes`. + +**Migration:** + +```rust +// Before +use bitcoin::blockdata::script::read_scriptint; +let num = read_scriptint(bytes); + +// After +use bitcoin::script::PushBytes; +let push_bytes = PushBytes::from(bytes); +let num = push_bytes.read_scriptint(); +``` + +### 6. ECDSA Error Type Changes + +**What Changed:** `ecdsa::Error` split into more specific error types. + +**Migration:** + +```rust +// Before +use bitcoin::ecdsa::Error; + +// After - Use specific error types +use bitcoin::ecdsa::DecodeError; // For Signature::from_slice +use bitcoin::ecdsa::ParseSignatureError; // For Signature::from_str + +// Update error handling accordingly +match signature_result { + Err(DecodeError::...) => // Handle decode error + Ok(sig) => // Handle success +} +``` + +### 7. Hash Method Renames + +**What Changed:** `to_raw_hash()` renamed to `to_byte_array()` across hash types. + +**Migration:** + +```rust +// Before +let bytes = txid.to_raw_hash(); + +// After +let bytes = txid.to_byte_array(); +``` + +### 8. Base58 Error Handling + +**What Changed:** Base58 errors are now "closed" (no more `#[non_exhaustive]`). + +**Migration:** + +No code changes required, but error matching is now exhaustive: + +```rust +// You can now match exhaustively +match result { + Ok(decoded) => // ... + Err(base58::Error::InvalidCharacter(c)) => // ... + Err(base58::Error::InvalidLength) => // ... + // No need for catch-all anymore +} +``` + +### 9. Hex Error Imports + +**What Changed:** `UnprefixedHexError` moved location. + +**Migration:** + +```rust +// Before +use bitcoin::error::UnprefixedHexError; + +// After +use bitcoin::parse::UnprefixedHexError; +``` + +### 10. Checked Division Methods Split + +**What Changed:** `checked_div_by_weight` split into ceiling and floor versions. + +**Migration:** + +```rust +// Before +let result = amount.checked_div_by_weight(weight); + +// After - Choose the appropriate rounding behavior +let result_floor = amount.checked_div_by_weight_floor(weight); +// or +let result_ceil = amount.checked_div_by_weight_ceil(weight); +``` + +### 11. Sequence Constants Renamed + +**What Changed:** Sequence constant naming clarified, `FINAL` constant added. + +**Migration:** + +```rust +// Check usage of sequence constants +use bitcoin::Sequence; + +// New constant available: +let final_sequence = Sequence::FINAL; +``` + +### 12. Transaction Version Three Support + +**What Changed:** Added `Version::THREE` variant to `transaction::Version`. + +**Migration:** + +```rust +use bitcoin::transaction::Version; + +// Now supports version 3 transactions +let version = Version::THREE; +``` + +### 13. Locktime API Changes + +**What Changed:** `ENABLE_RBF_NO_LOCKTIME` replaced with `ENABLE_LOCKTIME_AND_RBF`. + +**Migration:** + +```rust +// Before +use bitcoin::transaction::ENABLE_RBF_NO_LOCKTIME; + +// After +use bitcoin::transaction::ENABLE_LOCKTIME_AND_RBF; +// Review usage - semantic meaning may have changed +``` + +### 14. PSBT Encoding Changes + +**What Changed:** PSBT keytype now encoded as compact size unsigned integer. + +**Migration:** + +If you're manually encoding/decoding PSBTs, update your code. For most users using the provided API, this is handled automatically. + +### 15. Testnet4 Support + +**What Changed:** Support for Testnet4 network added. + +**Migration:** + +```rust +use bitcoin::Network; + +// New network variant available +let network = Network::Testnet4; +``` + +### 16. Signature Passing Convention + +**What Changed:** Signatures and associated types now passed by value instead of reference. + +**Migration:** + +```rust +// Before +fn verify_signature(sig: &Signature, ...) { } +verify_signature(&signature, ...); + +// After +fn verify_signature(sig: Signature, ...) { } +verify_signature(signature, ...); +``` + +### 17. Key Passing Convention + +**What Changed:** Keys now passed by value instead of reference. + +**Migration:** + +```rust +// Before +fn sign_with_key(key: &PrivateKey) { } + +// After +fn sign_with_key(key: PrivateKey) { } +``` + +### 18. BIP32 Field Rename + +**What Changed:** Key field in `Key` renamed to `key_data`. + +**Migration:** + +```rust +// Before +let key_bytes = extended_key.key; + +// After +let key_bytes = extended_key.key_data; +``` + +### 19. Midstate Method Rename + +**What Changed:** `Midstate::into_parts` renamed to `Midstate::to_parts` (since it derives `Copy`). + +**Migration:** + +```rust +// Before +let parts = midstate.into_parts(); + +// After +let parts = midstate.to_parts(); +``` + +### 20. Module Path Changes + +**What Changed:** Usage of `blockdata` removed from paths. + +**Migration:** + +```rust +// Before +use bitcoin::blockdata::script::Script; +use bitcoin::blockdata::transaction::Transaction; + +// After - Also note that generic Script no longer exists (see section 4) +use bitcoin::script::{ScriptPubKey, ScriptPubKeyBuf}; // Use specific script types +use bitcoin::transaction::Transaction; +``` + +### 21. Denomination Changes + +**What Changed:** `Denomination::MilliSatoshi` removed. + +**Migration:** + +```rust +// MilliSatoshi is not supported in bitcoin amounts +// Use the lightning crates for millisatoshi support +``` + +### 22. Script Size Limit Changes + +**What Changed:** `MAX_SCRIPT_ELEMENT_SIZE` removed. + +**Migration:** + +```rust +// Before +use bitcoin::blockdata::constants::MAX_SCRIPT_ELEMENT_SIZE; + +// After - Use more specific constants +use bitcoin::blockdata::constants::MAX_REDEEM_SCRIPT_SIZE; +// or +use bitcoin::blockdata::constants::MAX_STACK_ELEMENT_SIZE; +``` + +### 23. TxIdentifier Trait + +**What Changed:** New `TxIdentifier` trait added for transaction identification. + +**Migration:** + +This is an addition, not a breaking change. You can now use: + +```rust +use bitcoin::transaction::TxIdentifier; + +// Trait provides unified interface for Txid and Wtxid +``` + +### 24. BlockHeader Re-export + +**What Changed:** `block::Header` now re-exported as `BlockHeader` at crate root. + +**Migration:** + +```rust +// Before +use bitcoin::block::Header; + +// After - Can use shorter import +use bitcoin::BlockHeader; +// Old path still works for compatibility +``` + +## PSBT Serde Breaking Change (Unreleased) + +**Note:** This change is in the unreleased section and may be included in beta.0. + +**What Changed:** PSBT serde implementation now contextually uses PSBT binary or base64 encoded formats per BIP-0174. + +**Migration:** + +Review your PSBT serialization code if using serde. The format will now depend on context: +- Binary format for binary serializers +- Base64 format for text serializers (JSON, etc.) + +```rust +// Ensure your serialization/deserialization matches expected format +let psbt: Psbt = serde_json::from_str(&json_str)?; // Expects base64 +let psbt: Psbt = bincode::deserialize(&bytes)?; // Expects binary +``` + +## Testing Your Migration + +1. **Update dependencies** in Cargo.toml +2. **Run `cargo check`** to identify compilation errors +3. **Address each error** using this guide +4. **Run your test suite** to catch runtime issues +5. **Review deprecation warnings** for future removals +6. **Test with alpha/beta versions** before final release + +## Gradual Migration Strategy + +If you cannot migrate everything at once: + +1. **Update in a feature branch** to isolate changes +2. **Migrate module by module** using conditional compilation if needed +3. **Use type aliases temporarily** to reduce changeset size: + ```rust + // Temporary during migration + type OldAmount = bitcoin::Amount; + ``` +4. **Monitor for additional beta releases** as the API may still evolve + +## Getting Help + +- **GitHub Issues:** https://github.com/rust-bitcoin/rust-bitcoin/issues +- **API Documentation:** https://docs.rs/bitcoin/0.33.0-alpha.0/bitcoin/ (will update to beta.0) +- **Changelog:** See `bitcoin/CHANGELOG.md` for complete details +- **Dependency Changelogs:** + - `bitcoin_hashes`: https://github.com/rust-bitcoin/rust-bitcoin/blob/master/hashes/CHANGELOG.md + - `hex-conservative`: https://github.com/rust-bitcoin/hex-conservative/blob/master/CHANGELOG.md + - `bitcoin-io`: https://github.com/rust-bitcoin/rust-bitcoin/blob/master/io/CHANGELOG.md + - `bitcoin-primitives`: https://github.com/rust-bitcoin/rust-bitcoin/blob/master/primitives/CHANGELOG.md + - `bitcoin-units`: https://github.com/rust-bitcoin/rust-bitcoin/blob/master/units/CHANGELOG.md + +## Important Notes + +1. **Not a 1.0 Release:** While major dependencies are approaching 1.0, the bitcoin crate itself is still pre-1.0, meaning further breaking changes are possible. + +2. **Alpha/Beta Stability:** This is a beta release for testing purposes. Pin your version explicitly if you need stability. + +3. **MSRV:** Minimum Supported Rust Version may have changed. Check `Cargo.toml` for current MSRV (currently 1.74.0). + +4. **Feature Flags:** Review your feature flag usage as some may have changed or been added. + +## Future Plans + +The rust-bitcoin project is working toward 1.0 releases of core dependencies. After 0.33.0 is finalized: +- Expect continued API refinement +- More comprehensive documentation +- Stabilization of core interfaces +- Eventually, a 1.0 release of the bitcoin crate itself + +Stay updated by watching the repository and reviewing changelogs regularly. diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 91a74f3b2..0c2e9b7d0 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - [[package]] name = "arrayvec" version = "0.7.4" @@ -19,9 +10,8 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "base58ck" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" +version = "0.2.0" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" dependencies = [ "bitcoin-internals", "bitcoin_hashes", @@ -29,9 +19,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bech32" @@ -41,59 +31,95 @@ checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" [[package]] name = "bitcoin" -version = "0.32.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8929a18b8e33ea6b3c09297b687baaa71fb1b97353243a3f1029fad5c59c5b" +version = "0.33.0-beta.0" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" dependencies = [ "base58ck", "base64", "bech32", "bitcoin-internals", "bitcoin-io", + "bitcoin-primitives", "bitcoin-units", "bitcoin_hashes", - "hex-conservative 0.2.1", - "hex_lit", + "bitcoinconsensus", + "hex-conservative 0.3.0", "secp256k1", "serde", ] +[[package]] +name = "bitcoin-consensus-encoding" +version = "1.0.0-rc.1" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" +dependencies = [ + "bitcoin-internals", +] + [[package]] name = "bitcoin-internals" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" +version = "0.4.1" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" dependencies = [ + "hex-conservative 0.3.0", "serde", ] [[package]] name = "bitcoin-io" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e5b76b88667412087beea1882980ad843b660490bbf6cce0a6cfc999c5b989" +version = "0.2.0" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals", + "bitcoin_hashes", +] + +[[package]] +name = "bitcoin-primitives" +version = "1.0.0-rc.0" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" +dependencies = [ + "arrayvec", + "bitcoin-consensus-encoding", + "bitcoin-internals", + "bitcoin-units", + "bitcoin_hashes", + "hex-conservative 0.3.0", + "hex-conservative 1.0.0", + "serde", +] [[package]] name = "bitcoin-units" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d437fd727271c866d6fd5e71eb2c886437d4c97f80d89246be3189b1da4e58b" +version = "1.0.0-rc.2" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" dependencies = [ + "bitcoin-consensus-encoding", "bitcoin-internals", "serde", ] [[package]] name = "bitcoin_hashes" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +version = "0.17.0" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" dependencies = [ - "bitcoin-io", - "hex-conservative 0.2.1", + "bitcoin-consensus-encoding", + "bitcoin-internals", + "hex-conservative 0.3.0", "serde", ] +[[package]] +name = "bitcoinconsensus" +version = "0.106.0+26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12cba9cce5043cdda968e07b9df6d05ec6b0b38aa27a9a40bb575cf3e521ae9" +dependencies = [ + "cc", +] + [[package]] name = "cc" version = "1.0.28" @@ -106,32 +132,23 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "descriptor-fuzz" -version = "0.0.1" -dependencies = [ - "honggfuzz", - "miniscript 12.3.0", - "miniscript 13.0.0", - "regex", -] - [[package]] name = "getrandom" -version = "0.2.14" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi", + "wasip2", ] [[package]] name = "hex-conservative" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +checksum = "4afe881d0527571892c4034822e59bb10c6c991cce6abe8199b6f5cf10766f55" dependencies = [ "arrayvec", ] @@ -142,60 +159,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ee770c000993d17c185713463d5ebfbd1af9afae4c17cc295640104383bfbf0" -[[package]] -name = "hex_lit" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" - -[[package]] -name = "honggfuzz" -version = "0.5.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c76b6234c13c9ea73946d1379d33186151148e0da231506b964b44f3d023505" -dependencies = [ - "lazy_static", - "memmap2", - "rustc_version", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memmap2" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" -dependencies = [ - "libc", -] - -[[package]] -name = "miniscript" -version = "12.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd3c9608217b0d6fa9c9c8ddd875b85ab72bd4311cfc8db35e1b5a08fc11f4d" -dependencies = [ - "bech32", - "bitcoin", -] - [[package]] name = "miniscript" version = "13.0.0" @@ -232,22 +201,27 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" -version = "0.8.5" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core", @@ -255,46 +229,19 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom", ] -[[package]] -name = "regex" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - [[package]] name = "secp256k1" -version = "0.29.0" +version = "0.32.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" +checksum = "3c5fdc7d6e800869d3fd60ff857c479bf0a83ea7bf44b389e64461e844204994" dependencies = [ - "bitcoin_hashes", "rand", "secp256k1-sys", "serde", @@ -302,19 +249,13 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.10.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +checksum = "6d3be00697c88c00fe102af8dc316038cc2062eab8da646e7463f4c0e70ca9fd" dependencies = [ "cc", ] -[[package]] -name = "semver" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" - [[package]] name = "serde" version = "1.0.199" @@ -362,7 +303,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" diff --git a/Cargo-recent.lock b/Cargo-recent.lock index 91a74f3b2..0c2e9b7d0 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - [[package]] name = "arrayvec" version = "0.7.4" @@ -19,9 +10,8 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "base58ck" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" +version = "0.2.0" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" dependencies = [ "bitcoin-internals", "bitcoin_hashes", @@ -29,9 +19,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bech32" @@ -41,59 +31,95 @@ checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" [[package]] name = "bitcoin" -version = "0.32.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8929a18b8e33ea6b3c09297b687baaa71fb1b97353243a3f1029fad5c59c5b" +version = "0.33.0-beta.0" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" dependencies = [ "base58ck", "base64", "bech32", "bitcoin-internals", "bitcoin-io", + "bitcoin-primitives", "bitcoin-units", "bitcoin_hashes", - "hex-conservative 0.2.1", - "hex_lit", + "bitcoinconsensus", + "hex-conservative 0.3.0", "secp256k1", "serde", ] +[[package]] +name = "bitcoin-consensus-encoding" +version = "1.0.0-rc.1" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" +dependencies = [ + "bitcoin-internals", +] + [[package]] name = "bitcoin-internals" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" +version = "0.4.1" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" dependencies = [ + "hex-conservative 0.3.0", "serde", ] [[package]] name = "bitcoin-io" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e5b76b88667412087beea1882980ad843b660490bbf6cce0a6cfc999c5b989" +version = "0.2.0" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals", + "bitcoin_hashes", +] + +[[package]] +name = "bitcoin-primitives" +version = "1.0.0-rc.0" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" +dependencies = [ + "arrayvec", + "bitcoin-consensus-encoding", + "bitcoin-internals", + "bitcoin-units", + "bitcoin_hashes", + "hex-conservative 0.3.0", + "hex-conservative 1.0.0", + "serde", +] [[package]] name = "bitcoin-units" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d437fd727271c866d6fd5e71eb2c886437d4c97f80d89246be3189b1da4e58b" +version = "1.0.0-rc.2" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" dependencies = [ + "bitcoin-consensus-encoding", "bitcoin-internals", "serde", ] [[package]] name = "bitcoin_hashes" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +version = "0.17.0" +source = "git+https://github.com/tcharding/rust-bitcoin?branch=bitcoin-0.33.0-rc.0#352ad5d960b5f1d7893b91a5fca78cd5334d5baa" dependencies = [ - "bitcoin-io", - "hex-conservative 0.2.1", + "bitcoin-consensus-encoding", + "bitcoin-internals", + "hex-conservative 0.3.0", "serde", ] +[[package]] +name = "bitcoinconsensus" +version = "0.106.0+26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12cba9cce5043cdda968e07b9df6d05ec6b0b38aa27a9a40bb575cf3e521ae9" +dependencies = [ + "cc", +] + [[package]] name = "cc" version = "1.0.28" @@ -106,32 +132,23 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "descriptor-fuzz" -version = "0.0.1" -dependencies = [ - "honggfuzz", - "miniscript 12.3.0", - "miniscript 13.0.0", - "regex", -] - [[package]] name = "getrandom" -version = "0.2.14" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi", + "wasip2", ] [[package]] name = "hex-conservative" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +checksum = "4afe881d0527571892c4034822e59bb10c6c991cce6abe8199b6f5cf10766f55" dependencies = [ "arrayvec", ] @@ -142,60 +159,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ee770c000993d17c185713463d5ebfbd1af9afae4c17cc295640104383bfbf0" -[[package]] -name = "hex_lit" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" - -[[package]] -name = "honggfuzz" -version = "0.5.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c76b6234c13c9ea73946d1379d33186151148e0da231506b964b44f3d023505" -dependencies = [ - "lazy_static", - "memmap2", - "rustc_version", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memmap2" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" -dependencies = [ - "libc", -] - -[[package]] -name = "miniscript" -version = "12.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd3c9608217b0d6fa9c9c8ddd875b85ab72bd4311cfc8db35e1b5a08fc11f4d" -dependencies = [ - "bech32", - "bitcoin", -] - [[package]] name = "miniscript" version = "13.0.0" @@ -232,22 +201,27 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" -version = "0.8.5" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core", @@ -255,46 +229,19 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom", ] -[[package]] -name = "regex" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - [[package]] name = "secp256k1" -version = "0.29.0" +version = "0.32.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" +checksum = "3c5fdc7d6e800869d3fd60ff857c479bf0a83ea7bf44b389e64461e844204994" dependencies = [ - "bitcoin_hashes", "rand", "secp256k1-sys", "serde", @@ -302,19 +249,13 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.10.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +checksum = "6d3be00697c88c00fe102af8dc316038cc2062eab8da646e7463f4c0e70ca9fd" dependencies = [ "cc", ] -[[package]] -name = "semver" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" - [[package]] name = "serde" version = "1.0.199" @@ -362,7 +303,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" diff --git a/Cargo.toml b/Cargo.toml index 1a5f8d039..36d396f59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,15 +23,15 @@ base64 = ["bitcoin/base64"] [dependencies] bech32 = { version = "0.11.0", default-features = false, features = ["alloc"] } -bitcoin = { version = "0.32.6", default-features = false } +bitcoin = { git = "https://github.com/tcharding/rust-bitcoin", branch = "bitcoin-0.33.0-rc.0", default-features = false } hex = { package = "hex-conservative", default-features = false, features = ["alloc"], version = "1.0.0" } serde = { version = "1.0.103", optional = true } [dev-dependencies] serde_test = "1.0.147" -bitcoin = { version = "0.32.0", features = ["base64"] } -secp256k1 = {version = "0.29.0", features = ["rand-std"]} +bitcoin = { git = "https://github.com/tcharding/rust-bitcoin", branch = "bitcoin-0.33.0-rc.0", features = ["base64"] } +secp256k1 = {version = "0.32.0-beta.2", features = ["rand"]} [[example]] name = "htlc" @@ -71,5 +71,5 @@ path = "examples/taptree_of_horror/taptree_of_horror.rs" required-features = ["compiler"] [workspace] -members = ["fuzz"] -exclude = ["embedded", "bitcoind-tests"] +members = [] +exclude = ["embedded", "bitcoind-tests", "fuzz"] diff --git a/bitcoind-tests/Cargo.toml b/bitcoind-tests/Cargo.toml index 02450bb1f..f1c71661c 100644 --- a/bitcoind-tests/Cargo.toml +++ b/bitcoind-tests/Cargo.toml @@ -11,7 +11,7 @@ publish = false miniscript = {path = "../"} bitcoind = { package = "corepc-node", version = "0.4.0", default-features = false } actual-rand = { package = "rand", version = "0.8.4"} -secp256k1 = {version = "0.29.0", features = ["rand-std"]} +secp256k1 = {version = "0.32.0-beta.2", features = ["rand"]} [features] # Enable the same feature in `bitcoind`. diff --git a/bitcoind-tests/tests/setup/test_util.rs b/bitcoind-tests/tests/setup/test_util.rs index 64ffa6f5a..c48ddd0eb 100644 --- a/bitcoind-tests/tests/setup/test_util.rs +++ b/bitcoind-tests/tests/setup/test_util.rs @@ -65,7 +65,6 @@ fn setup_keys( Vec, Vec, ) { - let secp_sign = secp256k1::Secp256k1::signing_only(); let mut sk = [0; 32]; let mut sks = vec![]; let mut pks = vec![]; @@ -76,7 +75,7 @@ fn setup_keys( let sk = secp256k1::SecretKey::from_slice(&sk[..]).expect("secret key"); let pk = miniscript::bitcoin::PublicKey { - inner: secp256k1::PublicKey::from_secret_key(&secp_sign, &sk), + inner: secp256k1::PublicKey::from_secret_key(&sk), compressed: true, }; pks.push(pk); @@ -87,7 +86,7 @@ fn setup_keys( let mut x_only_pks = vec![]; for sk in &sks { - let keypair = bitcoin::secp256k1::Keypair::from_secret_key(&secp_sign, sk); + let keypair = bitcoin::secp256k1::Keypair::from_secret_key(sk); let (xpk, _parity) = XOnlyPublicKey::from_keypair(&keypair); x_only_keypairs.push(keypair); x_only_pks.push(xpk); diff --git a/bitcoind-tests/tests/test_cpp.rs b/bitcoind-tests/tests/test_cpp.rs index cdc336b2f..bccfba7f5 100644 --- a/bitcoind-tests/tests/test_cpp.rs +++ b/bitcoind-tests/tests/test_cpp.rs @@ -68,7 +68,6 @@ fn get_vout(cl: &Client, txid: Txid, value: Amount) -> (OutPoint, TxOut) { } pub fn test_from_cpp_ms(cl: &Client, testdata: &TestData) { - let secp = secp256k1::Secp256k1::new(); let desc_vec = parse_miniscripts(&testdata.pubdata); let sks = &testdata.secretdata.sks; let pks = &testdata.pubdata.pks; @@ -145,7 +144,7 @@ pub fn test_from_cpp_ms(cl: &Client, testdata: &TestData) { // Sign the transactions with all keys // AKA the signer role of psbt for i in 0..psbts.len() { - let wsh_derived = desc_vec[i].derived_descriptor(&secp); + let wsh_derived = desc_vec[i].derived_descriptor(); let ms = if let Descriptor::Wsh(wsh) = &wsh_derived { match wsh.as_inner() { miniscript::descriptor::WshInner::Ms(ms) => ms, @@ -173,7 +172,7 @@ pub fn test_from_cpp_ms(cl: &Client, testdata: &TestData) { // Finally construct the signature and add to psbt for sk in sks_reqd { - let signature = secp.sign_ecdsa(&msg, &sk); + let signature = secp256k1::ecdsa::sign(&msg, &sk); let pk = pks[sks.iter().position(|&x| x == sk).unwrap()]; psbts[i].inputs[0] .partial_sigs @@ -196,11 +195,11 @@ pub fn test_from_cpp_ms(cl: &Client, testdata: &TestData) { .insert(testdata.pubdata.ripemd160, testdata.secretdata.ripemd160_pre.to_vec()); // Finalize the transaction using psbt // Let miniscript do it's magic! - if let Err(e) = psbts[i].finalize_mall_mut(&secp) { + if let Err(e) = psbts[i].finalize_mall_mut() { // All miniscripts should satisfy panic!("Could not satisfy: error{} ms:{} at ind:{}", e[0], ms, i); } else { - let tx = psbts[i].extract(&secp).unwrap(); + let tx = psbts[i].extract().unwrap(); // Send the transactions to bitcoin node for mining. // Regtest mode has standardness checks diff --git a/bitcoind-tests/tests/test_desc.rs b/bitcoind-tests/tests/test_desc.rs index e09260097..314cc2770 100644 --- a/bitcoind-tests/tests/test_desc.rs +++ b/bitcoind-tests/tests/test_desc.rs @@ -73,7 +73,6 @@ pub fn test_desc_satisfy( testdata: &TestData, descriptor: &str, ) -> Result { - let secp = secp256k1::Secp256k1::new(); let sks = &testdata.secretdata.sks; let xonly_keypairs = &testdata.secretdata.x_only_keypairs; let pks = &testdata.pubdata.pks; @@ -89,7 +88,7 @@ pub fn test_desc_satisfy( .at_derivation_index(0) .unwrap(); - let derived_desc = definite_desc.derived_descriptor(&secp); + let derived_desc = definite_desc.derived_descriptor(); let desc_address = derived_desc.address(bitcoin::Network::Regtest); let desc_address = desc_address.map_err(|_x| DescError::AddressComputationError)?; @@ -169,7 +168,7 @@ pub fn test_desc_satisfy( if let Some(internal_keypair) = internal_keypair { // ---------------------- Tr key spend -------------------- let internal_keypair = internal_keypair - .tap_tweak(&secp, tr.spend_info().merkle_root()); + .tap_tweak(tr.spend_info().merkle_root()); let sighash_msg = sighash_cache .taproot_key_spend_signature_hash(0, &prevouts, sighash_type) .unwrap(); @@ -177,7 +176,7 @@ pub fn test_desc_satisfy( let mut aux_rand = [0u8; 32]; rand::thread_rng().fill_bytes(&mut aux_rand); let schnorr_sig = - secp.sign_schnorr_with_aux_rand(&msg, &internal_keypair.to_inner(), &aux_rand); + secp256k1::schnorr::sign_with_aux_rand(&msg, &internal_keypair.to_inner(), &aux_rand); psbt.inputs[0].tap_key_sig = Some(taproot::Signature { signature: schnorr_sig, sighash_type }); } else { @@ -201,7 +200,7 @@ pub fn test_desc_satisfy( let msg = secp256k1::Message::from_digest(sighash_msg.to_byte_array()); let mut aux_rand = [0u8; 32]; rand::thread_rng().fill_bytes(&mut aux_rand); - let signature = secp.sign_schnorr_with_aux_rand(&msg, &keypair, &aux_rand); + let signature = secp256k1::schnorr::sign_with_aux_rand(&msg, &keypair, &aux_rand); let x_only_pk = x_only_pks[xonly_keypairs.iter().position(|&x| x == keypair).unwrap()]; psbt.inputs[0] @@ -252,9 +251,9 @@ pub fn test_desc_satisfy( // Finally construct the signature and add to psbt for sk in sks_reqd { - let signature = secp.sign_ecdsa(&msg, &sk); + let signature = secp256k1::ecdsa::sign(&msg, &sk); let pk = pks[sks.iter().position(|&x| x == sk).unwrap()]; - assert!(secp.verify_ecdsa(&msg, &signature, &pk.inner).is_ok()); + assert!(secp256k1::ecdsa::verify(&msg, &signature, &pk.inner).is_ok()); psbt.inputs[0] .partial_sigs .insert(pk, ecdsa::Signature { signature, sighash_type }); @@ -278,10 +277,10 @@ pub fn test_desc_satisfy( println!("Testing descriptor: {}", definite_desc); // Finalize the transaction using psbt // Let miniscript do it's magic! - if psbt.finalize_mut(&secp).is_err() { + if psbt.finalize_mut().is_err() { return Err(DescError::PsbtFinalizeError); } - let tx = psbt.extract(&secp).expect("Extraction error"); + let tx = psbt.extract().expect("Extraction error"); // Send the transactions to bitcoin node for mining. // Regtest mode has standardness checks diff --git a/examples/big.rs b/examples/big.rs index 230d656b6..a5af0ee6e 100644 --- a/examples/big.rs +++ b/examples/big.rs @@ -20,7 +20,7 @@ use miniscript::{ translate_hash_fail, DefiniteDescriptorKey, Descriptor, DescriptorPublicKey, MiniscriptKey, Translator, }; -use secp256k1::Secp256k1; + fn main() { let empty = "".to_string(); let mut args = std::env::args().collect::>(); @@ -39,8 +39,7 @@ fn main() { .unwrap(); println!("{}", a); - let secp = Secp256k1::new(); - let (d, m) = Descriptor::parse_descriptor(&secp, &i).unwrap(); + let (d, m) = Descriptor::parse_descriptor(&i).unwrap(); use_descriptor(d); println!("{:?}", m); @@ -52,13 +51,13 @@ fn main() { println!("{:?}", h.address(bitcoin::Network::Bitcoin)); let psbt: bitcoin::Psbt = i.parse().unwrap(); - let psbt = psbt.finalize(&secp).unwrap(); + let psbt = psbt.finalize().unwrap(); let mut tx = psbt.extract_tx().unwrap(); println!("{:?}", tx); let d = miniscript::Descriptor::::from_str(&i).unwrap(); let sigs = HashMap::::new(); - d.satisfy(&mut tx.input[0], &sigs).unwrap(); + d.satisfy(&mut tx.inputs[0], &sigs).unwrap(); let pol = Concrete::::from_str(&i).unwrap(); let desc = pol.compile_tr(Some("UNSPENDABLE_KEY".to_string())).unwrap(); diff --git a/examples/psbt_sign_finalize.rs b/examples/psbt_sign_finalize.rs index 29bf8bc4e..81067e40e 100644 --- a/examples/psbt_sign_finalize.rs +++ b/examples/psbt_sign_finalize.rs @@ -5,18 +5,19 @@ use std::str::FromStr; use miniscript::bitcoin::consensus::encode::deserialize_hex; use miniscript::bitcoin::psbt::{self, Psbt}; +use miniscript::bitcoin::script::ScriptPubKey; use miniscript::bitcoin::sighash::SighashCache; +use miniscript::bitcoin::Witness; //use miniscript::bitcoin::secp256k1; // https://github.com/rust-lang/rust/issues/121684 +use miniscript::bitcoin::ext::*; use miniscript::bitcoin::{ - transaction, Address, Amount, Network, OutPoint, PrivateKey, Script, Sequence, Transaction, + transaction, Address, Amount, Network, OutPoint, PrivateKey, Sequence, Transaction, TxIn, TxOut, }; use miniscript::psbt::{PsbtExt, PsbtInputExt}; use miniscript::Descriptor; fn main() { - let secp256k1 = secp256k1::Secp256k1::new(); - let s = "wsh(t:or_c(pk(027a3565454fe1b749bccaef22aff72843a9c3efefd7b16ac54537a0c23f0ec0de),v:thresh(1,pkh(032d672a1a91cc39d154d366cd231983661b0785c7f27bc338447565844f4a6813),a:pkh(03417129311ed34c242c012cd0a3e0b9bca0065f742d0dfb63c78083ea6a02d4d9),a:pkh(025a687659658baeabdfc415164528065be7bcaade19342241941e556557f01e28))))#7hut9ukn"; let bridge_descriptor = Descriptor::from_str(s).unwrap(); //let bridge_descriptor = Descriptor::::from_str(&s).expect("parse descriptor string"); @@ -31,31 +32,31 @@ fn main() { let master_private_key_str = "cQhdvB3McbBJdx78VSSumqoHQiSXs75qwLptqwxSQBNBMDxafvaw"; let _master_private_key = PrivateKey::from_str(master_private_key_str).expect("Can't create private key"); - println!("Master public key: {}", _master_private_key.public_key(&secp256k1)); + println!("Master public key: {}", _master_private_key.public_key()); let backup1_private_key_str = "cWA34TkfWyHa3d4Vb2jNQvsWJGAHdCTNH73Rht7kAz6vQJcassky"; let backup1_private = PrivateKey::from_str(backup1_private_key_str).expect("Can't create private key"); - println!("Backup1 public key: {}", backup1_private.public_key(&secp256k1)); + println!("Backup1 public key: {}", backup1_private.public_key()); let backup2_private_key_str = "cPJFWUKk8sdL7pcDKrmNiWUyqgovimmhaaZ8WwsByDaJ45qLREkh"; let backup2_private = PrivateKey::from_str(backup2_private_key_str).expect("Can't create private key"); - println!("Backup2 public key: {}", backup2_private.public_key(&secp256k1)); + println!("Backup2 public key: {}", backup2_private.public_key()); let backup3_private_key_str = "cT5cH9UVm81W5QAf5KABXb23RKNSMbMzMx85y6R2mF42L94YwKX6"; let _backup3_private = PrivateKey::from_str(backup3_private_key_str).expect("Can't create private key"); - println!("Backup3 public key: {}", _backup3_private.public_key(&secp256k1)); + println!("Backup3 public key: {}", _backup3_private.public_key()); let spend_tx = Transaction { version: transaction::Version::TWO, lock_time: bitcoin::absolute::LockTime::from_consensus(5000), - input: vec![], - output: vec![], + inputs: vec![], + outputs: vec![], }; // Spend one input and spend one output for simplicity. @@ -82,19 +83,20 @@ fn main() { let txin = TxIn { previous_output: outpoint, + script_sig: bitcoin::ScriptSigBuf::new(), sequence: Sequence::from_height(26), - ..Default::default() + witness: Witness::default(), }; - psbt.unsigned_tx.input.push(txin); + psbt.unsigned_tx.inputs.push(txin); - psbt.unsigned_tx.output.push(TxOut { + psbt.unsigned_tx.outputs.push(TxOut { script_pubkey: receiver.script_pubkey(), - value: Amount::from_sat(amount / 5 - 500), + amount: Amount::from_sat_u32(amount / 5 - 500), }); - psbt.unsigned_tx.output.push(TxOut { + psbt.unsigned_tx.outputs.push(TxOut { script_pubkey: bridge_descriptor.script_pubkey(), - value: Amount::from_sat(amount * 4 / 5), + amount: Amount::from_sat_u32(amount * 4 / 5), }); // Generating signatures & witness data @@ -122,14 +124,14 @@ fn main() { let sk2 = backup2_private.inner; // Finally construct the signature and add to psbt - let sig1 = secp256k1.sign_ecdsa(&msg, &sk1); - let pk1 = backup1_private.public_key(&secp256k1); - assert!(secp256k1.verify_ecdsa(&msg, &sig1, &pk1.inner).is_ok()); + let sig1 = secp256k1::ecdsa::sign(msg, &sk1); + let pk1 = backup1_private.public_key(); + assert!(secp256k1::ecdsa::verify(&sig1, msg, &pk1.inner).is_ok()); // Second key just in case - let sig2 = secp256k1.sign_ecdsa(&msg, &sk2); - let pk2 = backup2_private.public_key(&secp256k1); - assert!(secp256k1.verify_ecdsa(&msg, &sig2, &pk2.inner).is_ok()); + let sig2 = secp256k1::ecdsa::sign(msg, &sk2); + let pk2 = backup2_private.public_key(); + assert!(secp256k1::ecdsa::verify(&sig2, msg, &pk2.inner).is_ok()); psbt.inputs[0] .partial_sigs @@ -138,7 +140,7 @@ fn main() { println!("{:#?}", psbt); println!("{}", psbt); - psbt.finalize_mut(&secp256k1).unwrap(); + psbt.finalize_mut().unwrap(); println!("{:#?}", psbt); let tx = psbt.extract_tx().expect("failed to extract tx"); @@ -146,10 +148,10 @@ fn main() { } // Find the Outpoint by spk -fn get_vout(tx: &Transaction, spk: &Script) -> (OutPoint, TxOut) { - for (i, txout) in tx.clone().output.into_iter().enumerate() { +fn get_vout(tx: &Transaction, spk: &ScriptPubKey) -> (OutPoint, TxOut) { + for (i, txout) in tx.clone().outputs.into_iter().enumerate() { if spk == &txout.script_pubkey { - return (OutPoint::new(tx.compute_txid(), i as u32), txout); + return (OutPoint::new(tx.compute_txid(), u32::try_from(i).expect("index is always positive")), txout); } } panic!("Only call get vout on functions which have the expected outpoint"); diff --git a/examples/sign_multisig.rs b/examples/sign_multisig.rs index b1117c102..cf291ebd3 100644 --- a/examples/sign_multisig.rs +++ b/examples/sign_multisig.rs @@ -6,6 +6,7 @@ use std::collections::HashMap; use std::str::FromStr; use bitcoin::blockdata::witness::Witness; +use bitcoin::script::{ScriptPubKeyBuf, ScriptSigBuf}; use bitcoin::{absolute, ecdsa, transaction, Amount, Sequence}; fn main() { @@ -49,30 +50,30 @@ fn main() { ); // Attempt to satisfy at age 0, height 0. - let original_txin = tx.input[0].clone(); + let original_txin = tx.inputs[0].clone(); let mut sigs = HashMap::::new(); // Doesn't work with no signatures. - assert!(descriptor.satisfy(&mut tx.input[0], &sigs).is_err()); - assert_eq!(tx.input[0], original_txin); + assert!(descriptor.satisfy(&mut tx.inputs[0], &sigs).is_err()); + assert_eq!(tx.inputs[0], original_txin); // ...or one signature... sigs.insert(pks[1], sig); - assert!(descriptor.satisfy(&mut tx.input[0], &sigs).is_err()); - assert_eq!(tx.input[0], original_txin); + assert!(descriptor.satisfy(&mut tx.inputs[0], &sigs).is_err()); + assert_eq!(tx.inputs[0], original_txin); // ...but two signatures is ok. sigs.insert(pks[2], sig); - assert!(descriptor.satisfy(&mut tx.input[0], &sigs).is_ok()); - assert_ne!(tx.input[0], original_txin); - assert_eq!(tx.input[0].witness.len(), 4); // 0, sig, sig, witness script + assert!(descriptor.satisfy(&mut tx.inputs[0], &sigs).is_ok()); + assert_ne!(tx.inputs[0], original_txin); + assert_eq!(tx.inputs[0].witness.len(), 4); // 0, sig, sig, witness script // ...and even if we give it a third signature, only two are used. sigs.insert(pks[0], sig); - assert!(descriptor.satisfy(&mut tx.input[0], &sigs).is_ok()); - assert_ne!(tx.input[0], original_txin); - assert_eq!(tx.input[0].witness.len(), 4); // 0, sig, sig, witness script + assert!(descriptor.satisfy(&mut tx.inputs[0], &sigs).is_ok()); + assert_ne!(tx.inputs[0], original_txin); + assert_eq!(tx.inputs[0].witness.len(), 4); // 0, sig, sig, witness script } // Transaction which spends some output. @@ -80,15 +81,15 @@ fn spending_transaction() -> bitcoin::Transaction { bitcoin::Transaction { version: transaction::Version::TWO, lock_time: absolute::LockTime::ZERO, - input: vec![bitcoin::TxIn { - previous_output: Default::default(), - script_sig: bitcoin::ScriptBuf::new(), + inputs: vec![bitcoin::TxIn { + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: ScriptSigBuf::new(), sequence: Sequence::MAX, witness: Witness::default(), }], - output: vec![bitcoin::TxOut { - script_pubkey: bitcoin::ScriptBuf::new(), - value: Amount::from_sat(100_000_000), + outputs: vec![bitcoin::TxOut { + script_pubkey: ScriptPubKeyBuf::new(), + amount: Amount::from_sat_u32(100_000_000), }], } } diff --git a/examples/taproot.rs b/examples/taproot.rs index aea13f6ce..b36bcb47f 100644 --- a/examples/taproot.rs +++ b/examples/taproot.rs @@ -86,8 +86,7 @@ fn main() { let mut pk_map = HashMap::new(); // We require secp for generating a random XOnlyPublicKey - let secp = secp256k1::Secp256k1::new(); - let key_pair = Keypair::new(&secp, &mut rand::thread_rng()); + let key_pair = Keypair::new(&mut rand::rng()); // Random unspendable XOnlyPublicKey provided for compilation to Taproot Descriptor let (unspendable_pubkey, _parity) = XOnlyPublicKey::from_keypair(&key_pair); @@ -142,7 +141,7 @@ fn hardcoded_xonlypubkeys() -> Vec { ]; let mut keys: Vec = vec![]; for key in serialized_keys { - keys.push(XOnlyPublicKey::from_slice(&key).unwrap()); + keys.push(XOnlyPublicKey::from_byte_array(&key).unwrap()); } keys } diff --git a/examples/taptree_of_horror/helper_fns.rs b/examples/taptree_of_horror/helper_fns.rs index d0ca62dad..38ac689f5 100644 --- a/examples/taptree_of_horror/helper_fns.rs +++ b/examples/taptree_of_horror/helper_fns.rs @@ -1,10 +1,9 @@ use std::str::FromStr; use bitcoin::bip32::{DerivationPath, Xpriv}; -use bitcoin::hashes::{ripemd160, sha256, Hash}; +use bitcoin::hashes::{ripemd160, sha256}; use miniscript::descriptor::DescriptorSecretKey; use miniscript::ToPublicKey; -use secp256k1::Secp256k1; use crate::KEYS_PER_PERSONA; @@ -28,7 +27,6 @@ pub fn produce_kelly_hash(secret: &str) -> (sha256::Hash, sha256::Hash) { pub fn produce_key_pairs( desc: DescriptorSecretKey, - secp: &Secp256k1, derivation_without_index: &str, _alias: &str, ) -> (Vec, Vec) { @@ -42,7 +40,7 @@ pub fn produce_key_pairs( for i in 0..KEYS_PER_PERSONA { let pk = desc - .to_public(secp) + .to_public() .unwrap() .at_derivation_index(i.try_into().unwrap()) .unwrap() @@ -50,7 +48,7 @@ pub fn produce_key_pairs( let derivation_with_index = format!("{}/{}", derivation_without_index, i); let derivation_path = DerivationPath::from_str(&derivation_with_index).unwrap(); - let derived_xpriv: Xpriv = xprv.xkey.derive_priv(secp, &derivation_path).unwrap(); + let derived_xpriv: Xpriv = xprv.xkey.derive_priv(&derivation_path).unwrap(); pks.push(pk); prvs.push(derived_xpriv); diff --git a/examples/taptree_of_horror/taptree_of_horror.rs b/examples/taptree_of_horror/taptree_of_horror.rs index 45f569756..efc04a72c 100644 --- a/examples/taptree_of_horror/taptree_of_horror.rs +++ b/examples/taptree_of_horror/taptree_of_horror.rs @@ -2,10 +2,9 @@ use std::str::FromStr; use bitcoin::absolute::LockTime; use bitcoin::consensus::encode::serialize; -use bitcoin::hashes::Hash; use bitcoin::hex::{Case, DisplayHex}; use bitcoin::transaction::Version; -use bitcoin::{Address, Amount, Network, Psbt, PublicKey, Sequence, TxIn, TxOut}; +use bitcoin::{Address, Amount, Network, Psbt, PublicKey, Sequence, TxIn, TxOut, Witness}; use helper_fns::{produce_grim_hash, produce_kelly_hash, produce_key_pairs}; use miniscript::descriptor::DescriptorSecretKey; use miniscript::policy::Concrete; @@ -16,8 +15,6 @@ mod helper_fns; pub const KEYS_PER_PERSONA: usize = 9; fn main() { - let secp: &secp256k1::Secp256k1 = &secp256k1::Secp256k1::new(); - // ====== 1. Setup Hardcoded Values for all of the Personas ====== // Define derivation paths that will be used @@ -60,7 +57,7 @@ fn main() { // ====== 2. Derive Keys, Preimages, Hashes, and Timelocks for Policy and Signing ====== let internal_xpub: miniscript::DescriptorPublicKey = - internal_desc_secret.to_public(secp).unwrap(); + internal_desc_secret.to_public().unwrap(); // example of how defining the internal xpriv that can be used for signing. // let internal_xpriv: DescriptorXKey = match internal_desc_secret { @@ -69,20 +66,20 @@ fn main() { // } // .unwrap(); - let (a_pks, a_prvs) = produce_key_pairs(a_descriptor_desc_secret, secp, normal_path, "alice"); - let (b_pks, b_prvs) = produce_key_pairs(b_descriptor_desc_secret, secp, normal_path, "bob"); - let (c_pks, c_prvs) = produce_key_pairs(c_descriptor_desc_secret, secp, normal_path, "charlie"); - let (d_pks, d_prvs) = produce_key_pairs(d_descriptor_desc_secret, secp, weird_path, "dave"); - let (e_pks, e_prvs) = produce_key_pairs(e_descriptor_desc_secret, secp, normal_path, "eve"); - let (f_pks, f_prvs) = produce_key_pairs(f_descriptor_desc_secret, secp, normal_path, "frank"); - let (h_pks, h_prvs) = produce_key_pairs(h_descriptor_desc_secret, secp, normal_path, "heather"); - let (i_pks, i_prvs) = produce_key_pairs(i_descriptor_desc_secret, secp, unhardened_path, "ian"); - let (j_pks, j_prvs) = produce_key_pairs(j_descriptor_desc_secret, secp, normal_path, "judy"); - let (l_pks, l_prvs) = produce_key_pairs(l_descriptor_desc_secret, secp, normal_path, "liam"); + let (a_pks, a_prvs) = produce_key_pairs(a_descriptor_desc_secret, normal_path, "alice"); + let (b_pks, b_prvs) = produce_key_pairs(b_descriptor_desc_secret, normal_path, "bob"); + let (c_pks, c_prvs) = produce_key_pairs(c_descriptor_desc_secret, normal_path, "charlie"); + let (d_pks, d_prvs) = produce_key_pairs(d_descriptor_desc_secret, weird_path, "dave"); + let (e_pks, e_prvs) = produce_key_pairs(e_descriptor_desc_secret, normal_path, "eve"); + let (f_pks, f_prvs) = produce_key_pairs(f_descriptor_desc_secret, normal_path, "frank"); + let (h_pks, h_prvs) = produce_key_pairs(h_descriptor_desc_secret, normal_path, "heather"); + let (i_pks, i_prvs) = produce_key_pairs(i_descriptor_desc_secret, unhardened_path, "ian"); + let (j_pks, j_prvs) = produce_key_pairs(j_descriptor_desc_secret, normal_path, "judy"); + let (l_pks, l_prvs) = produce_key_pairs(l_descriptor_desc_secret, normal_path, "liam"); let (s_pks, _s_prvs) = - produce_key_pairs(s_descriptor_desc_secret, secp, normal_path, "s_backup1"); + produce_key_pairs(s_descriptor_desc_secret, normal_path, "s_backup1"); let (x_pks, _x_prvs) = - produce_key_pairs(x_descriptor_desc_secret, secp, normal_path, "x_backup2"); + produce_key_pairs(x_descriptor_desc_secret, normal_path, "x_backup2"); // For this example we are grabbing the 9 keys for each persona let [a0, a1, a2, a3, a4, a5, a6, a7, a8]: [PublicKey; KEYS_PER_PERSONA] = @@ -202,8 +199,6 @@ fn main() { // ====== 4. Construct an Unsigned Transaction from the Tapscript ====== - let secp: &secp256k1::Secp256k1 = &secp256k1::Secp256k1::new(); - let tx_in = TxIn { previous_output: bitcoin::OutPoint { txid: "8888888899999999aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffff" @@ -211,20 +206,21 @@ fn main() { .unwrap(), vout: 0, }, + script_sig: bitcoin::ScriptSigBuf::new(), sequence: Sequence(0), // sequence: Sequence(40), - ..Default::default() + witness: Witness::default(), }; - let prev_amount = Amount::from_sat(100_000_000); + let prev_amount = Amount::from_sat_u32(100_000_000); let witness_utxo = - TxOut { value: prev_amount, script_pubkey: derived_descriptor.clone().script_pubkey() }; + TxOut { amount: prev_amount, script_pubkey: derived_descriptor.clone().script_pubkey() }; let destination_address = Address::from_str("bcrt1p2tl8zasepqe3j6m7hx4tdmqzndddr5wa9ugglpdzgenjwv42rkws66dk5a") .unwrap(); let destination_output: TxOut = TxOut { - value: bitcoin::Amount::from_sat(99_999_000), + amount: bitcoin::Amount::from_sat_u32(99_999_000), script_pubkey: destination_address.assume_checked().script_pubkey(), }; @@ -233,8 +229,8 @@ fn main() { let unsigned_tx = bitcoin::Transaction { version: Version::TWO, lock_time: LockTime::from_time(time).unwrap(), - input: vec![tx_in], - output: vec![destination_output], + inputs: vec![tx_in], + outputs: vec![destination_output], }; let unsigned_tx_test_string = serialize(&unsigned_tx).to_hex_string(Case::Lower); @@ -250,19 +246,19 @@ fn main() { // ====== 5. Sign and Create a Spending Transaction ====== // this is how you would sign for an internal key spend - //let _res = psbt.sign(&intneral_xpriv.xkey, secp).unwrap(); + //let _res = psbt.sign(&intneral_xpriv.xkey).unwrap(); // how you would sign using the leaf that uses index 0 keys - let _res = psbt.sign(&a_prvs[0], secp).unwrap(); - let _res = psbt.sign(&b_prvs[0], secp).unwrap(); - let _res = psbt.sign(&c_prvs[0], secp).unwrap(); - let _res = psbt.sign(&d_prvs[0], secp).unwrap(); - let _res = psbt.sign(&e_prvs[0], secp).unwrap(); - let _res = psbt.sign(&f_prvs[0], secp).unwrap(); - let _res = psbt.sign(&h_prvs[0], secp).unwrap(); - let _res = psbt.sign(&i_prvs[0], secp).unwrap(); - let _res = psbt.sign(&j_prvs[0], secp).unwrap(); - let _res = psbt.sign(&l_prvs[0], secp).unwrap(); + let _res = psbt.sign(&a_prvs[0]).unwrap(); + let _res = psbt.sign(&b_prvs[0]).unwrap(); + let _res = psbt.sign(&c_prvs[0]).unwrap(); + let _res = psbt.sign(&d_prvs[0]).unwrap(); + let _res = psbt.sign(&e_prvs[0]).unwrap(); + let _res = psbt.sign(&f_prvs[0]).unwrap(); + let _res = psbt.sign(&h_prvs[0]).unwrap(); + let _res = psbt.sign(&i_prvs[0]).unwrap(); + let _res = psbt.sign(&j_prvs[0]).unwrap(); + let _res = psbt.sign(&l_prvs[0]).unwrap(); psbt.inputs[0] .sha256_preimages @@ -273,7 +269,7 @@ fn main() { .insert(grim.1, grim.0.to_byte_array().to_vec()); // Finalize PSBT now that we have all the required signatures and hash preimages. - psbt.finalize_mut(secp).unwrap(); + psbt.finalize_mut().unwrap(); // Now extract the tx let signed_tx = psbt.extract_tx().unwrap(); diff --git a/examples/verify_tx.rs b/examples/verify_tx.rs index f2a63f447..2e1c5a6ab 100644 --- a/examples/verify_tx.rs +++ b/examples/verify_tx.rs @@ -5,7 +5,7 @@ use std::str::FromStr; use miniscript::bitcoin::consensus::Decodable; -use miniscript::bitcoin::secp256k1::Secp256k1; +use miniscript::bitcoin::script::ScriptPubKeyBuf; use miniscript::bitcoin::{absolute, sighash, Sequence}; use miniscript::interpreter::KeySigPair; @@ -19,8 +19,8 @@ fn main() { let interpreter = miniscript::Interpreter::from_txdata( &spk_input_1, - &tx.input[0].script_sig, - &tx.input[0].witness, + &tx.inputs[0].script_sig, + &tx.inputs[0].witness, Sequence::ZERO, absolute::LockTime::ZERO, ) @@ -63,13 +63,12 @@ fn main() { // as having participated in the script println!("\n\nExample two:\n"); - let secp = Secp256k1::new(); // We can set prevouts to be empty list because this is a legacy transaction // and this information is not required for sighash computation. let prevouts = sighash::Prevouts::All::(&[]); - for elem in interpreter.iter(&secp, &tx, 0, &prevouts) { + for elem in interpreter.iter(&tx, 0, &prevouts) { if let miniscript::interpreter::SatisfiedConstraint::PublicKey { key_sig } = elem.expect("no evaluation error") { @@ -82,14 +81,12 @@ fn main() { // // Same, but with the wrong signature hash, to demonstrate what happens // given an apparently invalid script. - let secp = Secp256k1::new(); let message = secp256k1::Message::from_digest([0x01; 32]); let iter = interpreter.iter_custom(Box::new(|key_sig: &KeySigPair| { let (pk, ecdsa_sig) = key_sig.as_ecdsa().expect("Ecdsa Sig"); ecdsa_sig.sighash_type == bitcoin::sighash::EcdsaSighashType::All - && secp - .verify_ecdsa(&message, &ecdsa_sig.signature, &pk.inner) + && secp256k1::ecdsa::verify(&ecdsa_sig.signature, message, &pk.inner) .is_ok() })); @@ -161,8 +158,8 @@ fn hard_coded_transaction() -> bitcoin::Transaction { bitcoin::Transaction::consensus_decode(&mut &tx_bytes[..]).expect("decode transaction") } -fn hard_coded_script_pubkey() -> bitcoin::ScriptBuf { - bitcoin::ScriptBuf::from(vec![ +fn hard_coded_script_pubkey() -> ScriptPubKeyBuf { + ScriptPubKeyBuf::from(vec![ 0xa9, 0x14, 0x92, 0x09, 0xa8, 0xf9, 0x0c, 0x58, 0x4b, 0xb5, 0x97, 0x4d, 0x58, 0x68, 0x72, 0x49, 0xe5, 0x32, 0xde, 0x59, 0xf4, 0xbc, 0x87, ]) diff --git a/examples/xpub_descriptors.rs b/examples/xpub_descriptors.rs index 2f9478ff8..3404f5db4 100644 --- a/examples/xpub_descriptors.rs +++ b/examples/xpub_descriptors.rs @@ -4,7 +4,6 @@ use std::str::FromStr; -use miniscript::bitcoin::secp256k1::{Secp256k1, Verification}; use miniscript::bitcoin::{Address, Network}; use miniscript::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey}; @@ -12,25 +11,22 @@ const XPUB_1: &str = "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapS const XPUB_2: &str = "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"; fn main() { - // For deriving from descriptors, we need to provide a secp context. - let secp = Secp256k1::verification_only(); - // P2WSH and single xpubs. - let _ = p2wsh(&secp); + let _ = p2wsh(); // P2WSH-P2SH and ranged xpubs. - let _ = p2sh_p2wsh(&secp); + let _ = p2sh_p2wsh(); } /// Parses a P2WSH descriptor, returns the associated address. -fn p2wsh(secp: &Secp256k1) -> Address { +fn p2wsh() -> Address { // It does not matter what order the two xpubs go in, the same address will be generated. let s = format!("wsh(sortedmulti(1,{},{}))", XPUB_1, XPUB_2); // let s = format!("wsh(sortedmulti(1,{},{}))", XPUB_2, XPUB_1); let address = Descriptor::::from_str(&s) .unwrap() - .derived_descriptor(secp) + .derived_descriptor() .address(Network::Bitcoin) .unwrap(); @@ -45,14 +41,14 @@ fn p2wsh(secp: &Secp256k1) -> Address { } /// Parses a P2SH-P2WSH descriptor, returns the associated address. -fn p2sh_p2wsh(secp: &Secp256k1) -> Address { +fn p2sh_p2wsh() -> Address { // It does not matter what order the two xpubs go in, the same address will be generated. let s = format!("sh(wsh(sortedmulti(1,{}/1/0/*,{}/0/0/*)))", XPUB_1, XPUB_2); // let s = format!("sh(wsh(sortedmulti(1,{}/1/0/*,{}/0/0/*)))", XPUB_2, XPUB_1); let address = Descriptor::::from_str(&s) .unwrap() - .derived_descriptor(secp, 5) + .derived_descriptor(5) .unwrap() .address(Network::Bitcoin) .unwrap(); diff --git a/fuzz/fuzz_targets/parse_descriptor_priv.rs b/fuzz/fuzz_targets/parse_descriptor_priv.rs index 98bfb992c..94f07f0fe 100644 --- a/fuzz/fuzz_targets/parse_descriptor_priv.rs +++ b/fuzz/fuzz_targets/parse_descriptor_priv.rs @@ -6,9 +6,8 @@ use miniscript::Descriptor; fn do_test(data: &[u8]) { let data_str = String::from_utf8_lossy(data); - let secp = &secp256k1::Secp256k1::signing_only(); - if let Ok((desc, _)) = Descriptor::parse_descriptor(secp, &data_str) { + if let Ok((desc, _)) = Descriptor::parse_descriptor(&data_str) { let _output = desc.to_string(); let _sanity_check = desc.sanity_check(); } diff --git a/src/benchmarks.rs b/src/benchmarks.rs index f79b3509b..a0ce9b0c7 100644 --- a/src/benchmarks.rs +++ b/src/benchmarks.rs @@ -9,7 +9,7 @@ use core::str::FromStr; -use bitcoin::secp256k1::{Secp256k1, SecretKey}; +use bitcoin::secp256k1::SecretKey; use test::{black_box, Bencher}; use crate::descriptor::{SinglePub, SinglePubKey}; @@ -19,15 +19,13 @@ use crate::{Descriptor, DescriptorPublicKey}; type Desc = Descriptor; fn keygen(n: u32) -> DescriptorPublicKey { - let secp = Secp256k1::new(); - let mut sk = [0; 32]; sk[31] = n as u8; sk[30] = (n >> 8) as u8; sk[29] = (n >> 16) as u8; sk[28] = (n >> 24) as u8; - let sk = SecretKey::from_slice(&sk).unwrap(); - let pk = bitcoin::PublicKey { inner: sk.public_key(&secp), compressed: true }; + let sk = SecretKey::from_secret_bytes(sk).unwrap(); + let pk = bitcoin::PublicKey { inner: sk.public_key(), compressed: true }; DescriptorPublicKey::Single(SinglePub { origin: None, key: SinglePubKey::FullKey(pk) }) } diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index b41ee2850..106cc305c 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -9,8 +9,8 @@ use core::fmt; -use bitcoin::script::{self, PushBytes}; -use bitcoin::{Address, Network, ScriptBuf, Weight}; +use bitcoin::script::{self, PushBytes, ScriptPubKeyBuf, ScriptSigBuf}; +use bitcoin::{Address, Network, Weight}; use crate::descriptor::{write_descriptor, DefiniteDescriptorKey}; use crate::expression::{self, FromTree}; @@ -103,18 +103,18 @@ impl Bare { impl Bare { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { self.ms.encode() } + pub fn script_pubkey(&self) -> ScriptPubKeyBuf { self.ms.encode() } /// Obtains the underlying miniscript for this descriptor. - pub fn inner_script(&self) -> ScriptBuf { self.script_pubkey() } + pub fn inner_script(&self) -> ScriptPubKeyBuf { self.script_pubkey() } /// Obtains the pre bip-340 signature script code for this descriptor. - pub fn ecdsa_sighash_script_code(&self) -> ScriptBuf { self.script_pubkey() } + pub fn ecdsa_sighash_script_code(&self) -> ScriptPubKeyBuf { self.script_pubkey() } /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is /// possible to construct one using the `satisfier`. - pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { @@ -127,7 +127,7 @@ impl Bare { /// Returns satisfying, possibly malleable, witness and scriptSig with /// minimum weight to spend an output controlled by the given descriptor if /// it is possible to construct one using the `satisfier`. - pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { @@ -267,7 +267,7 @@ impl Pkh { impl Pkh { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { + pub fn script_pubkey(&self) -> ScriptPubKeyBuf { // Fine to hard code the `Network` here because we immediately call // `script_pubkey` which does not use the `network` field of `Address`. let addr = self.address(Network::Bitcoin); @@ -280,15 +280,15 @@ impl Pkh { } /// Obtains the underlying miniscript for this descriptor. - pub fn inner_script(&self) -> ScriptBuf { self.script_pubkey() } + pub fn inner_script(&self) -> ScriptPubKeyBuf { self.script_pubkey() } /// Obtains the pre bip-340 signature script code for this descriptor. - pub fn ecdsa_sighash_script_code(&self) -> ScriptBuf { self.script_pubkey() } + pub fn ecdsa_sighash_script_code(&self) -> ScriptPubKeyBuf { self.script_pubkey() } /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is /// possible to construct one using the `satisfier`. - pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { @@ -298,7 +298,7 @@ impl Pkh { // serialize() does not allocate here sig.serialize().as_ref(), ) - .push_key(&self.pk.to_public_key()) + .push_key(self.pk.to_public_key()) .into_script(); let witness = vec![]; Ok((witness, script_sig)) @@ -310,7 +310,7 @@ impl Pkh { /// Returns satisfying, possibly malleable, witness and scriptSig with /// minimum weight to spend an output controlled by the given descriptor if /// it is possible to construct one using the `satisfier`. - pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index 241f931ee..bbda44c4a 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -6,10 +6,9 @@ use core::str::FromStr; #[cfg(feature = "std")] use std::error; -use bitcoin::bip32::{self, XKeyIdentifier}; -use bitcoin::hashes::{hash160, ripemd160, sha256, Hash, HashEngine}; +use bitcoin::bip32; +use bitcoin::hashes::{hash160, ripemd160, sha256}; use bitcoin::key::{PublicKey, XOnlyPublicKey}; -use bitcoin::secp256k1::{Secp256k1, Signing, Verification}; use bitcoin::NetworkKind; use crate::prelude::*; @@ -166,7 +165,7 @@ impl fmt::Display for DescriptorSecretKey { /// handling of `bip32::Xpub` and `bip32::Xpriv`. pub trait InnerXKey: fmt::Display + FromStr { /// Returns the fingerprint of the key - fn xkey_fingerprint(&self, secp: &Secp256k1) -> bip32::Fingerprint; + fn xkey_fingerprint(&self) -> bip32::Fingerprint; /// Returns whether hardened steps can be derived on the key /// @@ -175,7 +174,7 @@ pub trait InnerXKey: fmt::Display + FromStr { } impl InnerXKey for bip32::Xpub { - fn xkey_fingerprint(&self, _secp: &Secp256k1) -> bip32::Fingerprint { + fn xkey_fingerprint(&self) -> bip32::Fingerprint { self.fingerprint() } @@ -183,8 +182,8 @@ impl InnerXKey for bip32::Xpub { } impl InnerXKey for bip32::Xpriv { - fn xkey_fingerprint(&self, secp: &Secp256k1) -> bip32::Fingerprint { - self.fingerprint(secp) + fn xkey_fingerprint(&self) -> bip32::Fingerprint { + self.fingerprint() } fn can_derive_hardened() -> bool { true } @@ -203,8 +202,8 @@ pub enum Wildcard { impl SinglePriv { /// Returns the public key of this key. - fn to_public(&self, secp: &Secp256k1) -> SinglePub { - let pub_key = self.key.public_key(secp); + fn to_public(&self) -> SinglePub { + let pub_key = self.key.public_key(); SinglePub { origin: self.origin.clone(), key: SinglePubKey::FullKey(pub_key) } } @@ -217,9 +216,8 @@ impl DescriptorXKey { /// If the key already has an origin, the derivation steps applied will be appended to the path /// already present, otherwise this key will be treated as a master key and an origin will be /// added with this key's fingerprint and the derivation steps applied. - fn to_public( + fn to_public( &self, - secp: &Secp256k1, ) -> Result, DescriptorKeyParseError> { let unhardened = self .derivation_path @@ -234,17 +232,17 @@ impl DescriptorXKey { let xprv = self .xkey - .derive_priv(secp, &hardened_path) + .derive_priv(&hardened_path) .map_err(DescriptorKeyParseError::DeriveHardenedKey)?; - let xpub = bip32::Xpub::from_priv(secp, &xprv); + let xpub = bip32::Xpub::from_priv(&xprv); let origin = match &self.origin { Some((fingerprint, path)) => { Some((*fingerprint, path.into_iter().chain(hardened_path).copied().collect())) } None if !hardened_path.is_empty() => { - Some((self.xkey.fingerprint(secp), hardened_path.into())) + Some((self.xkey.fingerprint(), hardened_path.into())) } None => None, }; @@ -263,9 +261,8 @@ impl DescriptorMultiXKey { /// are shared among all derivation paths before turning it into a public key. /// /// Errors if there are hardened derivation steps that are not shared among all paths. - fn to_public( + fn to_public( &self, - secp: &Secp256k1, ) -> Result, DescriptorKeyParseError> { let deriv_paths = self.derivation_paths.paths(); @@ -309,16 +306,16 @@ impl DescriptorMultiXKey { let xprv = self .xkey - .derive_priv(secp, &hardened_path) + .derive_priv(&hardened_path) .map_err(DescriptorKeyParseError::DeriveHardenedKey)?; - let xpub = bip32::Xpub::from_priv(secp, &xprv); + let xpub = bip32::Xpub::from_priv(&xprv); let origin = match &self.origin { Some((fingerprint, path)) => { Some((*fingerprint, path.into_iter().chain(hardened_path).copied().collect())) } None if !hardened_path.is_empty() => { - Some((self.xkey.fingerprint(secp), hardened_path.into())) + Some((self.xkey.fingerprint(), hardened_path.into())) } None => None, }; @@ -413,22 +410,22 @@ impl fmt::Display for MalformedKeyDataKind { #[non_exhaustive] pub enum DescriptorKeyParseError { /// Error while parsing a BIP32 extended private key - Bip32Xpriv(bip32::Error), + Bip32Xpriv(bip32::ParseError), /// Error while parsing a BIP32 extended public key - Bip32Xpub(bip32::Error), + Bip32Xpub(bip32::ParseError), /// Error while parsing a derivation index DerivationIndexError { /// The invalid index index: String, - /// The underlying parse error - err: bitcoin::bip32::Error, + /// The underlying parse error (as string for compatibility) + err: String, }, /// Error deriving the hardened private key. - DeriveHardenedKey(bip32::Error), + DeriveHardenedKey(bip32::DerivationError), /// Error indicating the key data was malformed MalformedKeyData(MalformedKeyDataKind), /// Error while parsing the master derivation path. - MasterDerivationPath(bip32::Error), + MasterDerivationPath(bip32::ParseError), /// Error indicating a malformed master fingerprint (invalid hex). MasterFingerprint { /// The invalid fingerprint @@ -442,8 +439,8 @@ pub enum DescriptorKeyParseError { FullPublicKey(bitcoin::key::ParsePublicKeyError), /// Error while parsing a WIF private key. WifPrivateKey(bitcoin::key::FromWifError), - /// Error while parsing an X-only public key (Secp256k1 error). - XonlyPublicKey(bitcoin::secp256k1::Error), + /// Error while parsing an X-only public key. + XonlyPublicKey(bitcoin::key::ParseXOnlyPublicKeyError), } impl fmt::Display for DescriptorKeyParseError { @@ -472,17 +469,14 @@ impl fmt::Display for DescriptorKeyParseError { impl error::Error for DescriptorKeyParseError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { - Self::Bip32Xpriv(err) - | Self::Bip32Xpub(err) - | Self::DerivationIndexError { err, .. } - | Self::DeriveHardenedKey(err) - | Self::MasterDerivationPath(err) => Some(err), + Self::Bip32Xpriv(err) | Self::Bip32Xpub(err) | Self::MasterDerivationPath(err) => Some(err), + Self::DeriveHardenedKey(err) => Some(err), Self::MasterFingerprint { err, .. } => Some(err), Self::NonDefiniteKey(err) => Some(err), Self::FullPublicKey(err) => Some(err), Self::WifPrivateKey(err) => Some(err), Self::XonlyPublicKey(err) => Some(err), - Self::MalformedKeyData(_) => None, + Self::DerivationIndexError { .. } | Self::MalformedKeyData(_) => None, } } } @@ -532,15 +526,14 @@ impl DescriptorSecretKey { /// /// It will return an error if the key is a "multi-xpriv" that includes /// hardened derivation steps not shared for all paths. - pub fn to_public( + pub fn to_public( &self, - secp: &Secp256k1, ) -> Result { let pk = match self { - DescriptorSecretKey::Single(prv) => DescriptorPublicKey::Single(prv.to_public(secp)), - DescriptorSecretKey::XPrv(xprv) => DescriptorPublicKey::XPub(xprv.to_public(secp)?), + DescriptorSecretKey::Single(prv) => DescriptorPublicKey::Single(prv.to_public()), + DescriptorSecretKey::XPrv(xprv) => DescriptorPublicKey::XPub(xprv.to_public()?), DescriptorSecretKey::MultiXPrv(xprv) => { - DescriptorPublicKey::MultiXPub(xprv.to_public(secp)?) + DescriptorPublicKey::MultiXPub(xprv.to_public()?) } }; @@ -723,15 +716,21 @@ impl DescriptorPublicKey { if let Some((fingerprint, _)) = single.origin { fingerprint } else { - let mut engine = XKeyIdentifier::engine(); + use bitcoin::hashes::HashEngine as _; + + // FIXME: Should we support this usecase for `XKeyIdentifier`? I.e., should one + // be able to hash arbitrary data into it without having to know the inner hash? + let mut engine = hash160::Hash::engine(); match single.key { SinglePubKey::FullKey(pk) => { pk.write_into(&mut engine).expect("engines don't error") } SinglePubKey::XOnly(x_only_pk) => engine.input(&x_only_pk.serialize()), - }; + } + let hash = engine.finalize(); + // FIXME: This is also a bit klunky. bip32::Fingerprint::from( - &XKeyIdentifier::from_engine(engine)[..4] + &hash.as_byte_array()[..4] .try_into() .expect("4 byte slice"), ) @@ -988,8 +987,10 @@ fn parse_key_origin(s: &str) -> Result<(&str, Option), Descrip })?; let origin_path = raw_origin .map(bip32::ChildNumber::from_str) - .collect::>() - .map_err(DescriptorKeyParseError::MasterDerivationPath)?; + .collect::>() + .map_err(|_e| DescriptorKeyParseError::MalformedKeyData( + MalformedKeyDataKind::InvalidMultiIndexStep + ))?; let key = parts .next() @@ -1073,7 +1074,7 @@ fn parse_xkey_deriv( bip32::ChildNumber::from_str(s).map_err(|err| { DescriptorKeyParseError::DerivationIndexError { index: s.to_owned(), - err, + err: err.to_string(), } }) }) @@ -1086,7 +1087,7 @@ fn parse_xkey_deriv( .map(|i| vec![i]) .map_err(|err| DescriptorKeyParseError::DerivationIndexError { index: p.to_owned(), - err, + err: err.to_string(), }), ) } @@ -1143,8 +1144,6 @@ impl DescriptorXKey { /// use miniscript::bitcoin::bip32; /// use miniscript::descriptor::DescriptorPublicKey; /// - /// let ctx = miniscript::bitcoin::secp256k1::Secp256k1::signing_only(); - /// /// let key = DescriptorPublicKey::from_str("[d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*").or(Err(()))?; /// let xpub = match key { /// DescriptorPublicKey::XPub(xpub) => xpub, @@ -1155,31 +1154,30 @@ impl DescriptorXKey { /// xpub.matches(&( /// bip32::Fingerprint::from_str("d34db33f").or(Err(()))?, /// bip32::DerivationPath::from_str("m/44'/0'/0'/1/42").or(Err(()))? - /// ), &ctx), + /// )), /// Some(bip32::DerivationPath::from_str("m/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(()))? - /// ), &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(()))? - /// ), &ctx), + /// )), /// None /// ); /// # Ok(()) /// # } /// # body().unwrap() /// ``` - pub fn matches( + pub fn matches( &self, keysource: &bip32::KeySource, - secp: &Secp256k1, ) -> Option { let (fingerprint, path) = keysource; @@ -1188,7 +1186,7 @@ impl DescriptorXKey { (fingerprint, path.into_iter().chain(&self.derivation_path).collect()) } None => ( - self.xkey.xkey_fingerprint(secp), + self.xkey.xkey_fingerprint(), self.derivation_path.into_iter().collect::>(), ), }; @@ -1251,7 +1249,7 @@ impl DefiniteDescriptorKey { /// /// Will return an error if the descriptor key has any hardened derivation steps in its path. To /// avoid this error you should replace any such public keys first with [`crate::Descriptor::translate_pk`]. - pub fn derive_public_key(&self, secp: &Secp256k1) -> bitcoin::PublicKey { + pub fn derive_public_key(&self) -> bitcoin::PublicKey { match self.0 { DescriptorPublicKey::Single(ref pk) => match pk.key { SinglePubKey::FullKey(pk) => pk, @@ -1261,9 +1259,9 @@ impl DefiniteDescriptorKey { Wildcard::Unhardened | Wildcard::Hardened => { unreachable!("impossible by construction of DefiniteDescriptorKey") } - Wildcard::None => match xpk.xkey.derive_pub(secp, &xpk.derivation_path.as_ref()) { + Wildcard::None => match xpk.xkey.derive_pub(&xpk.derivation_path.as_ref()) { Ok(xpub) => bitcoin::PublicKey::new(xpub.public_key), - Err(bip32::Error::CannotDeriveFromHardenedKey) => { + Err(bip32::DerivationError::CannotDeriveHardenedChild) => { unreachable!("impossible by construction of DefiniteDescriptorKey") } Err(e) => unreachable!("cryptographically unreachable: {}", e), @@ -1339,8 +1337,7 @@ impl MiniscriptKey for DefiniteDescriptorKey { impl ToPublicKey for DefiniteDescriptorKey { fn to_public_key(&self) -> bitcoin::PublicKey { - let secp = Secp256k1::verification_only(); - self.derive_public_key(&secp) + self.derive_public_key() } fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash } @@ -1491,35 +1488,33 @@ mod test { #[test] fn test_deriv_on_xprv() { - let secp = secp256k1::Secp256k1::signing_only(); - let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0'/1'/2").unwrap(); - let public_key = secret_key.to_public(&secp).unwrap(); + let public_key = secret_key.to_public().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(), "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(); + let public_key = secret_key.to_public().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(), "0'/1'/2'"); let secret_key = DescriptorSecretKey::from_str("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0/1/2").unwrap(); - let public_key = secret_key.to_public(&secp).unwrap(); + let public_key = secret_key.to_public().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(), "0/1/2"); let secret_key = DescriptorSecretKey::from_str("[aabbccdd]tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/0/1/2").unwrap(); - let public_key = secret_key.to_public(&secp).unwrap(); + let public_key = secret_key.to_public().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(), "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(); + let public_key = secret_key.to_public().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(), "90'/0'/1'/2"); @@ -1557,7 +1552,6 @@ mod test { #[test] fn multipath_extended_keys() { - let secp = secp256k1::Secp256k1::signing_only(); // We can have a key in a descriptor that has multiple paths let xpub = get_multipath_xpub("tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi/2/<0;1;42;9854>", 4); @@ -1715,7 +1709,7 @@ mod test { get_multipath_xprv(&DescriptorSecretKey::MultiXPrv(xprv.clone()).to_string()) ); let desc_key = DescriptorSecretKey::from_str("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/<0';1>/8h/*'").unwrap(); - assert!(desc_key.to_public(&secp).is_err()); + assert!(desc_key.to_public().is_err()); assert!(desc_key.is_multipath()); assert_eq!(desc_key.into_single_keys(), vec![DescriptorSecretKey::from_str("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/0'/8h/*'").unwrap(), DescriptorSecretKey::from_str("[abcdef00/0'/1']tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/9478'/1/8h/*'").unwrap()]); @@ -1734,16 +1728,15 @@ mod test { #[test] fn test_multixprv_to_public() { - let secp = secp256k1::Secp256k1::signing_only(); // Works if all hardended derivation steps are part of the shared path let xprv = get_multipath_xprv("[01020304/5]tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1'/2'/3/<4;5>/6"); - let xpub = DescriptorPublicKey::MultiXPub(xprv.to_public(&secp).unwrap()); // wrap in a DescriptorPublicKey to have Display + let xpub = DescriptorPublicKey::MultiXPub(xprv.to_public().unwrap()); // wrap in a DescriptorPublicKey to have Display assert_eq!(xpub.to_string(), "[01020304/5/1'/2']tpubDBTRkEMEFkUbk3WTz6CFSULyswkTPpPr38AWibf5TVkB5GxuBxbSbmdFGr3jmswwemknyYxAGoX7BJnKfyPy4WXaHmcrxZhfzFwoUFvFtm5/3/<4;5>/6"); // Fails if they're part of the multi-path specifier or following it - get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/2/<3';4'>/5").to_public(&secp).unwrap_err(); - get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/2/<3;4>/5/6'").to_public(&secp).unwrap_err(); + get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/2/<3';4'>/5").to_public().unwrap_err(); + get_multipath_xprv("tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/2/<3;4>/5/6'").to_public().unwrap_err(); } #[test] diff --git a/src/descriptor/key_map.rs b/src/descriptor/key_map.rs index 3e193ec87..77198bcf2 100644 --- a/src/descriptor/key_map.rs +++ b/src/descriptor/key_map.rs @@ -5,7 +5,6 @@ use core::iter; use bitcoin::psbt::{GetKey, GetKeyError, KeyRequest}; -use bitcoin::secp256k1::{Secp256k1, Signing}; use bitcoin::PrivateKey; #[cfg(doc)] @@ -31,12 +30,11 @@ impl KeyMap { /// Inserts secret key into key map returning the associated public key. #[inline] - pub fn insert( + pub fn insert( &mut self, - secp: &Secp256k1, sk: DescriptorSecretKey, ) -> Result { - let pk = sk.to_public(secp)?; + let pk = sk.to_public()?; if !self.map.contains_key(&pk) { self.map.insert(pk.clone(), sk); } @@ -81,16 +79,15 @@ impl iter::Extend<(DescriptorPublicKey, DescriptorSecretKey)> for KeyMap { impl GetKey for KeyMap { type Error = GetKeyError; - fn get_key( + fn get_key( &self, - key_request: KeyRequest, - secp: &Secp256k1, + key_request: &KeyRequest, ) -> Result, Self::Error> { Ok(self .map .iter() .find_map(|(_desc_pk, desc_sk)| -> Option { - match desc_sk.get_key(key_request.clone(), secp) { + match desc_sk.get_key(key_request) { Ok(Some(pk)) => Some(pk), // When looking up keys in a map, we eat errors on individual keys, on // the assumption that some other key in the map might not error. @@ -103,24 +100,23 @@ impl GetKey for KeyMap { impl GetKey for DescriptorSecretKey { type Error = GetKeyError; - fn get_key( + fn get_key( &self, - key_request: KeyRequest, - secp: &Secp256k1, + key_request: &KeyRequest, ) -> Result, Self::Error> { match (self, key_request) { (DescriptorSecretKey::Single(single_priv), key_request) => { let sk = single_priv.key; - let pk = sk.public_key(secp); + let pk = sk.public_key(); let pubkey_map = BTreeMap::from([(pk, sk)]); - pubkey_map.get_key(key_request, secp) + pubkey_map.get_key(key_request) } (DescriptorSecretKey::XPrv(descriptor_xkey), KeyRequest::Pubkey(public_key)) => { let xpriv = descriptor_xkey .xkey - .derive_priv(secp, &descriptor_xkey.derivation_path) + .derive_priv(&descriptor_xkey.derivation_path) .map_err(GetKeyError::Bip32)?; - let pk = xpriv.private_key.public_key(secp); + let pk = xpriv.private_key.public_key(); if public_key.inner.eq(&pk) { Ok(Some(xpriv.to_priv())) @@ -132,11 +128,11 @@ impl GetKey for DescriptorSecretKey { DescriptorSecretKey::XPrv(descriptor_xkey), ref key_request @ KeyRequest::Bip32(ref key_source), ) => { - if let Some(key) = descriptor_xkey.xkey.get_key(key_request.clone(), secp)? { + if let Some(key) = descriptor_xkey.xkey.get_key(key_request)? { return Ok(Some(key)); } - if let Some(matched_path) = descriptor_xkey.matches(key_source, secp) { + if let Some(matched_path) = descriptor_xkey.matches(key_source) { let (_, full_path) = key_source; let derivation_path = &full_path[matched_path.len()..]; @@ -144,7 +140,7 @@ impl GetKey for DescriptorSecretKey { return Ok(Some( descriptor_xkey .xkey - .derive_priv(secp, &derivation_path) + .derive_priv(&derivation_path) .map_err(GetKeyError::Bip32)? .to_priv(), )); @@ -161,7 +157,7 @@ impl GetKey for DescriptorSecretKey { ) => { for desc_sk in &desc_multi_sk.clone().into_single_keys() { // If any key is an error, then all of them will, so here we propagate errors with ?. - if let Some(pk) = desc_sk.get_key(key_request.clone(), secp)? { + if let Some(pk) = desc_sk.get_key(key_request)? { return Ok(Some(pk)); } } @@ -183,8 +179,6 @@ mod tests { #[test] fn get_key_single_key() { - let secp = Secp256k1::new(); - let descriptor_sk_s = "[90b6a706/44'/0'/0'/0/0]cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij"; @@ -195,12 +189,12 @@ mod tests { let want_sk = single.key; let descriptor_s = format!("wpkh({})", descriptor_sk_s); - let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(&descriptor_s).unwrap(); - let pk = want_sk.public_key(&secp); + let pk = want_sk.public_key(); let request = KeyRequest::Pubkey(pk); let got_sk = keymap - .get_key(request, &secp) + .get_key(&request) .expect("get_key call errored") .expect("failed to find the key"); assert_eq!(got_sk, want_sk) @@ -208,12 +202,10 @@ mod tests { #[test] fn get_key_xpriv_single_key_xpriv() { - let secp = Secp256k1::new(); - let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"; let xpriv = s.parse::().unwrap(); - let xpriv_fingerprint = xpriv.fingerprint(&secp); + let xpriv_fingerprint = xpriv.fingerprint(); // Sanity check. { @@ -228,12 +220,12 @@ mod tests { let want_sk = xpriv.to_priv(); let descriptor_s = format!("wpkh([{}]{})", xpriv_fingerprint, xpriv); - let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(&descriptor_s).unwrap(); - let pk = want_sk.public_key(&secp); + let pk = want_sk.public_key(); let request = KeyRequest::Pubkey(pk); let got_sk = keymap - .get_key(request, &secp) + .get_key(&request) .expect("get_key call errored") .expect("failed to find the key"); assert_eq!(got_sk, want_sk) @@ -241,14 +233,12 @@ mod tests { #[test] fn get_key_xpriv_child_depth_one() { - let secp = Secp256k1::new(); - let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"; let master = s.parse::().unwrap(); - let master_fingerprint = master.fingerprint(&secp); + let master_fingerprint = master.fingerprint(); let child_number = ChildNumber::from_hardened_idx(44).unwrap(); - let child = master.derive_priv(&secp, &[child_number]).unwrap(); + let child = master.derive_priv(&[child_number]).unwrap(); // Sanity check. { @@ -263,12 +253,12 @@ mod tests { let want_sk = child.to_priv(); let descriptor_s = format!("wpkh({}/44')", s); - let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(&descriptor_s).unwrap(); - let pk = want_sk.public_key(&secp); + let pk = want_sk.public_key(); let request = KeyRequest::Pubkey(pk); let got_sk = keymap - .get_key(request, &secp) + .get_key(&request) .expect("get_key call errored") .expect("failed to find the key"); assert_eq!(got_sk, want_sk) @@ -276,16 +266,14 @@ mod tests { #[test] fn get_key_xpriv_with_path() { - let secp = Secp256k1::new(); - let s = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"; let master = s.parse::().unwrap(); - let master_fingerprint = master.fingerprint(&secp); + let master_fingerprint = master.fingerprint(); let first_external_child = "44'/0'/0'/0/0"; let derivation_path = first_external_child.into_derivation_path().unwrap(); - let child = master.derive_priv(&secp, &derivation_path).unwrap(); + let child = master.derive_priv(&derivation_path).unwrap(); // Sanity check. { @@ -301,12 +289,12 @@ mod tests { let want_sk = child.to_priv(); let descriptor_s = format!("wpkh({}/44'/0'/0'/0/*)", s); - let (_, keymap) = Descriptor::parse_descriptor(&secp, &descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(&descriptor_s).unwrap(); let key_source = (master_fingerprint, derivation_path); let request = KeyRequest::Bip32(key_source); let got_sk = keymap - .get_key(request, &secp) + .get_key(&request) .expect("get_key call errored") .expect("failed to find the key"); @@ -315,10 +303,8 @@ mod tests { #[test] fn get_key_xpriv_with_key_origin() { - let secp = Secp256k1::new(); - let descriptor_str = "wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"; - let (_descriptor_pk, keymap) = Descriptor::parse_descriptor(&secp, descriptor_str).unwrap(); + let (_descriptor_pk, keymap) = Descriptor::parse_descriptor(descriptor_str).unwrap(); let descriptor_sk = DescriptorSecretKey::from_str("[d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*").unwrap(); let xpriv = match descriptor_sk { @@ -329,7 +315,7 @@ mod tests { let expected_deriv_path: DerivationPath = (&[ChildNumber::Normal { index: 0 }][..]).into(); let expected_pk = xpriv .xkey - .derive_priv(&secp, &expected_deriv_path) + .derive_priv(&expected_deriv_path) .unwrap() .to_priv(); @@ -338,7 +324,7 @@ mod tests { let key_request = KeyRequest::Bip32((fp, derivation_path)); let pk = keymap - .get_key(key_request, &secp) + .get_key(&key_request) .expect("get_key should not fail") .expect("get_key should return a `PrivateKey`"); @@ -347,52 +333,46 @@ mod tests { #[test] fn get_key_keymap_no_match() { - let secp = Secp256k1::new(); - // Create a keymap with one key let descriptor_s = "wpkh(cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij)"; - let (_, keymap) = Descriptor::parse_descriptor(&secp, descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(descriptor_s).unwrap(); // Request a different public key that doesn't exist in the keymap let different_sk = PrivateKey::from_str("cNJFgo1driFnPcBdBX8BrJrpxchBWXwXCvNH5SoSkdcF6JXXwHMm").unwrap(); - let different_pk = different_sk.public_key(&secp); + let different_pk = different_sk.public_key(); let request = KeyRequest::Pubkey(different_pk); - let result = keymap.get_key(request, &secp).unwrap(); + let result = keymap.get_key(&request).unwrap(); assert!(result.is_none(), "Should return None when no matching key is found"); } #[test] fn get_key_descriptor_secret_key_xonly_not_supported() { - let secp = Secp256k1::new(); - let descriptor_sk = DescriptorSecretKey::from_str("xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").unwrap(); // Create an x-only public key request let sk = PrivateKey::from_str("cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij").unwrap(); - let xonly_pk = sk.public_key(&secp).inner.x_only_public_key().0; - let request = KeyRequest::XOnlyPubkey(xonly_pk); + let xonly_pk = sk.public_key().inner.x_only_public_key().0; + let request = KeyRequest::XOnlyPubkey(xonly_pk.into()); - let result = descriptor_sk.get_key(request.clone(), &secp); + let result = descriptor_sk.get_key(&request); assert!(matches!(result, Err(GetKeyError::NotSupported))); // Also test with KeyMap let descriptor_s = "wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi)"; - let (_, keymap) = Descriptor::parse_descriptor(&secp, descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(descriptor_s).unwrap(); // While requesting an x-only key from an individual xpriv, that's an error. // But from a keymap, which might have both x-only keys and regular xprivs, // we treat errors as "key not found". - let result = keymap.get_key(request, &secp); + let result = keymap.get_key(&request); assert!(matches!(result, Ok(None))); } #[test] fn get_key_descriptor_secret_key_xonly_multipath() { - let secp = Secp256k1::new(); - let descriptor_sk = DescriptorSecretKey::from_str("[d34db33f/84h/0h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/<0;1>").unwrap(); // Request with a different fingerprint @@ -400,29 +380,29 @@ mod tests { let path = DerivationPath::from_str("84'/1'/0'/0").unwrap(); let request = KeyRequest::Bip32((different_fingerprint, path)); - let result = descriptor_sk.get_key(request.clone(), &secp).unwrap(); + let result = descriptor_sk.get_key(&request).unwrap(); assert!(result.is_none(), "Should return None when fingerprint doesn't match"); // Create an x-only public key request -- now we get "not supported". let sk = PrivateKey::from_str("cMk8gWmj1KpjdYnAWwsEDekodMYhbyYBhG8gMtCCxucJ98JzcNij").unwrap(); - let xonly_pk = sk.public_key(&secp).inner.x_only_public_key().0; - let request_x = KeyRequest::XOnlyPubkey(xonly_pk); + let xonly_pk = sk.public_key().inner.x_only_public_key().0; + let request_x = KeyRequest::XOnlyPubkey(xonly_pk.into()); - let result = descriptor_sk.get_key(request_x.clone(), &secp); + let result = descriptor_sk.get_key(&request_x); assert!(matches!(result, Err(GetKeyError::NotSupported))); // Also test with KeyMap; as in the previous test, the error turns to None. let descriptor_s = "wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/<0;1>/*)"; - let (_, keymap) = Descriptor::parse_descriptor(&secp, descriptor_s).unwrap(); + let (_, keymap) = Descriptor::parse_descriptor(descriptor_s).unwrap(); - let result = keymap.get_key(request.clone(), &secp).unwrap(); + let result = keymap.get_key(&request).unwrap(); assert!(result.is_none(), "Should return None when fingerprint doesn't match"); - let result = keymap.get_key(request, &secp).unwrap(); + let result = keymap.get_key(&request).unwrap(); assert!(result.is_none(), "Should return None when fingerprint doesn't match"); - let result = descriptor_sk.get_key(request_x.clone(), &secp); + let result = descriptor_sk.get_key(&request_x); assert!(matches!(result, Err(GetKeyError::NotSupported))); - let result = keymap.get_key(request_x, &secp).unwrap(); + let result = keymap.get_key(&request_x).unwrap(); assert!(result.is_none(), "Should return None even on error"); } } diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 81bad54c8..7232fb6fc 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -16,8 +16,9 @@ use core::ops::Range; use core::str::{self, FromStr}; use bitcoin::hashes::{hash160, ripemd160, sha256}; +use bitcoin::script::{ScriptPubKey, ScriptPubKeyBuf, ScriptSigBuf}; use bitcoin::{ - secp256k1, Address, Network, Script, ScriptBuf, TxIn, Weight, Witness, WitnessVersion, + Address, Network, TxIn, Weight, Witness, WitnessVersion, }; use sync::Arc; @@ -462,7 +463,7 @@ impl Descriptor { } /// Computes the scriptpubkey of the descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { + pub fn script_pubkey(&self) -> ScriptPubKeyBuf { match *self { Descriptor::Bare(ref bare) => bare.script_pubkey(), Descriptor::Pkh(ref pkh) => pkh.script_pubkey(), @@ -480,14 +481,14 @@ impl Descriptor { /// This is used in Segwit transactions to produce an unsigned transaction /// whose txid will not change during signing (since only the witness data /// will change). - pub fn unsigned_script_sig(&self) -> ScriptBuf { + pub fn unsigned_script_sig(&self) -> ScriptSigBuf { match *self { - Descriptor::Bare(_) => ScriptBuf::new(), - Descriptor::Pkh(_) => ScriptBuf::new(), - Descriptor::Wpkh(_) => ScriptBuf::new(), - Descriptor::Wsh(_) => ScriptBuf::new(), + Descriptor::Bare(_) => ScriptSigBuf::new(), + Descriptor::Pkh(_) => ScriptSigBuf::new(), + Descriptor::Wpkh(_) => ScriptSigBuf::new(), + Descriptor::Wsh(_) => ScriptSigBuf::new(), Descriptor::Sh(ref sh) => sh.unsigned_script_sig(), - Descriptor::Tr(_) => ScriptBuf::new(), + Descriptor::Tr(_) => ScriptSigBuf::new(), } } @@ -497,13 +498,13 @@ impl Descriptor { /// /// # Errors /// If the descriptor is a taproot descriptor. - pub fn explicit_script(&self) -> Result { + pub fn explicit_script(&self) -> Result { match *self { Descriptor::Bare(ref bare) => Ok(bare.script_pubkey()), Descriptor::Pkh(ref pkh) => Ok(pkh.script_pubkey()), Descriptor::Wpkh(ref wpkh) => Ok(wpkh.script_pubkey()), - Descriptor::Wsh(ref wsh) => Ok(wsh.inner_script()), - Descriptor::Sh(ref sh) => Ok(sh.inner_script()), + Descriptor::Wsh(ref wsh) => Ok(ScriptPubKeyBuf::from_bytes(wsh.inner_script().into_bytes())), + Descriptor::Sh(ref sh) => Ok(ScriptPubKeyBuf::from_bytes(sh.inner_script().into_bytes())), Descriptor::Tr(_) => Err(Error::TrNoScriptCode), } } @@ -515,13 +516,16 @@ impl Descriptor { /// /// # Errors /// If the descriptor is a taproot descriptor. - pub fn script_code(&self) -> Result { + // FIXME: I don't know what script type this function should return. + // Is this something to do with `primitives::script::ScriptHashableTag` (I'm still confused + // because that trait mentions redeemScript but I expected it to say witnessScript?) + pub fn script_code(&self) -> Result { match *self { Descriptor::Bare(ref bare) => Ok(bare.ecdsa_sighash_script_code()), Descriptor::Pkh(ref pkh) => Ok(pkh.ecdsa_sighash_script_code()), Descriptor::Wpkh(ref wpkh) => Ok(wpkh.ecdsa_sighash_script_code()), - Descriptor::Wsh(ref wsh) => Ok(wsh.ecdsa_sighash_script_code()), - Descriptor::Sh(ref sh) => Ok(sh.ecdsa_sighash_script_code()), + Descriptor::Wsh(ref wsh) => Ok(ScriptPubKeyBuf::from_bytes(wsh.ecdsa_sighash_script_code().into_bytes())), + Descriptor::Sh(ref sh) => Ok(ScriptPubKeyBuf::from_bytes(sh.ecdsa_sighash_script_code().into_bytes())), Descriptor::Tr(_) => Err(Error::TrNoScriptCode), } } @@ -529,7 +533,7 @@ impl Descriptor { /// Returns satisfying non-malleable witness and scriptSig to spend an /// output controlled by the given descriptor if it possible to /// construct one using the satisfier S. - pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { @@ -546,7 +550,7 @@ impl Descriptor { /// Returns a possilbly mallable satisfying non-malleable witness and scriptSig to spend an /// output controlled by the given descriptor if it possible to /// construct one using the satisfier S. - pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { @@ -679,20 +683,19 @@ impl Descriptor { } /// Convert all the public keys in the descriptor to [`bitcoin::PublicKey`] by deriving them or - /// otherwise converting them. All [`bitcoin::secp256k1::XOnlyPublicKey`]s are converted to by adding a + /// otherwise converting them. All [`bitcoin::XOnlyPublicKey`]s are converted to by adding a /// default(0x02) y-coordinate. /// /// This is a shorthand for: /// /// ``` - /// # use miniscript::{Descriptor, DescriptorPublicKey, bitcoin::secp256k1::Secp256k1}; + /// # use miniscript::{Descriptor, DescriptorPublicKey}; /// # use core::str::FromStr; /// # let descriptor = Descriptor::::from_str("tr(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)") /// .expect("Valid ranged descriptor"); /// # let index = 42; - /// # let secp = Secp256k1::verification_only(); - /// let derived_descriptor = descriptor.at_derivation_index(index).unwrap().derived_descriptor(&secp); - /// # assert_eq!(descriptor.derived_descriptor(&secp, index).unwrap(), derived_descriptor); + /// let derived_descriptor = descriptor.at_derivation_index(index).unwrap().derived_descriptor(); + /// # assert_eq!(descriptor.derived_descriptor(index).unwrap(), derived_descriptor); /// ``` /// /// and is only here really here for backwards compatibility. @@ -705,31 +708,28 @@ impl Descriptor { /// /// This function will return an error for multi-path descriptors /// or if hardened derivation is attempted, - pub fn derived_descriptor( + pub fn derived_descriptor( &self, - secp: &secp256k1::Secp256k1, index: u32, ) -> Result, NonDefiniteKeyError> { - Ok(self.at_derivation_index(index)?.derived_descriptor(secp)) + Ok(self.at_derivation_index(index)?.derived_descriptor()) } /// Parse a descriptor that may contain secret keys /// /// Internally turns every secret key found into the corresponding public key and then returns a /// a descriptor that only contains public keys and a map to lookup the secret key given a public key. - pub fn parse_descriptor( - secp: &secp256k1::Secp256k1, + pub fn parse_descriptor( s: &str, ) -> Result<(Descriptor, KeyMap), Error> { - fn parse_key( + fn parse_key( s: &str, key_map: &mut KeyMap, - secp: &secp256k1::Secp256k1, ) -> Result { match DescriptorSecretKey::from_str(s) { Ok(sk) => { let pk = key_map - .insert(secp, sk) + .insert(sk) .map_err(|e| Error::Unexpected(e.to_string()))?; Ok(pk) } @@ -743,16 +743,16 @@ impl Descriptor { } } - let mut keymap_pk = KeyMapWrapper(KeyMap::new(), secp); + let mut keymap_pk = KeyMapWrapper(KeyMap::new()); - struct KeyMapWrapper<'a, C: secp256k1::Signing>(KeyMap, &'a secp256k1::Secp256k1); + struct KeyMapWrapper(KeyMap); - impl Translator for KeyMapWrapper<'_, C> { + impl Translator for KeyMapWrapper { type TargetPk = DescriptorPublicKey; type Error = Error; fn pk(&mut self, pk: &String) -> Result { - parse_key(pk, &mut self.0, self.1) + parse_key(pk, &mut self.0) } fn sha256(&mut self, sha256: &String) -> Result { @@ -841,16 +841,15 @@ impl Descriptor { /// descriptor at that index. If the descriptor is non-derivable then it will simply check the /// script pubkey against the descriptor and return it if it matches (in this case the index /// returned will be meaningless). - pub fn find_derivation_index_for_spk( + pub fn find_derivation_index_for_spk( &self, - secp: &secp256k1::Secp256k1, - script_pubkey: &Script, + script_pubkey: &ScriptPubKey, range: Range, ) -> Result)>, NonDefiniteKeyError> { let range = if self.has_wildcard() { range } else { 0..1 }; for i in range { - let concrete = self.derived_descriptor(secp, i)?; + let concrete = self.derived_descriptor(i)?; if &concrete.script_pubkey() == script_pubkey { return Ok(Some((i, concrete))); } @@ -955,45 +954,42 @@ impl Descriptor { impl Descriptor { /// Convert all the public keys in the descriptor to [`bitcoin::PublicKey`] by deriving them or - /// otherwise converting them. All [`bitcoin::secp256k1::XOnlyPublicKey`]s are converted to by adding a + /// otherwise converting them. All [`bitcoin::XOnlyPublicKey`]s are converted to by adding a /// default(0x02) y-coordinate. /// /// # Examples /// /// ``` /// use miniscript::descriptor::{Descriptor, DescriptorPublicKey}; - /// use miniscript::bitcoin::secp256k1; /// use std::str::FromStr; /// /// // test from bip 86 - /// let secp = secp256k1::Secp256k1::verification_only(); /// let descriptor = Descriptor::::from_str("tr(xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)") /// .expect("Valid ranged descriptor"); - /// let result = descriptor.at_derivation_index(0).unwrap().derived_descriptor(&secp); + /// let result = descriptor.at_derivation_index(0).unwrap().derived_descriptor(); /// assert_eq!(result.to_string(), "tr(03cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115)#6qm9h8ym"); /// ``` /// /// # Errors /// /// This function will return an error if hardened derivation is attempted. - pub fn derived_descriptor( + pub fn derived_descriptor( &self, - secp: &secp256k1::Secp256k1, ) -> Descriptor { - struct Derivator<'a, C: secp256k1::Verification>(&'a secp256k1::Secp256k1); + struct Derivator; - impl Translator for Derivator<'_, C> { + impl Translator for Derivator { type TargetPk = bitcoin::PublicKey; type Error = core::convert::Infallible; fn pk(&mut self, pk: &DefiniteDescriptorKey) -> Result { - Ok(pk.derive_public_key(self.0)) + Ok(pk.derive_public_key()) } translate_hash_clone!(DefiniteDescriptorKey); } - let derived = self.translate_pk(&mut Derivator(secp)); + let derived = self.translate_pk(&mut Derivator); match derived { Ok(derived) => derived, // Impossible to hit, since deriving keys does not change any Miniscript-relevant @@ -1112,8 +1108,7 @@ mod tests { use bitcoin::blockdata::opcodes::all::{OP_CLTV, OP_CSV}; use bitcoin::blockdata::script::Instruction; use bitcoin::blockdata::{opcodes, script}; - use bitcoin::hashes::Hash; - use bitcoin::script::PushBytes; + use bitcoin::script::{PushBytes, ScriptPubKeyBuf, ScriptSigBuf, WitnessScriptExt, ScriptExt, ScriptBufExt}; use bitcoin::sighash::EcdsaSighashType; use bitcoin::{bip32, PublicKey, Sequence, XOnlyPublicKey}; @@ -1214,7 +1209,7 @@ mod tests { let pk = StdDescriptor::from_str(TEST_PK).unwrap(); assert_eq!( pk.script_pubkey(), - ScriptBuf::from(vec![ + ScriptPubKeyBuf::from(vec![ 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xac, @@ -1367,13 +1362,15 @@ mod tests { #[test] fn satisfy() { - let secp = secp256k1::Secp256k1::new(); - let sk = - secp256k1::SecretKey::from_slice(&b"sally was a secret key, she said"[..]).unwrap(); - let pk = bitcoin::PublicKey::new(secp256k1::PublicKey::from_secret_key(&secp, &sk)); - let msg = secp256k1::Message::from_digest_slice(&b"michael was a message, amusingly"[..]) - .expect("32 bytes"); - let sig = secp.sign_ecdsa(&msg, &sk); + let sk = secp256k1::SecretKey::from_secret_bytes( + *b"sally was a secret key, she said", + ) + .unwrap(); + let pk = bitcoin::PublicKey::new(secp256k1::PublicKey::from_secret_key(&sk)); + let msg = secp256k1::Message::from_digest( + *b"michael was a message, amusingly", + ); + let sig = secp256k1::ecdsa::sign(msg, &sk); let mut sigser = sig.serialize_der().to_vec(); sigser.push(0x01); // sighash_all @@ -1402,8 +1399,8 @@ mod tests { let ms = ms_str!("c:pk_k({})", pk); let mut txin = bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: bitcoin::ScriptBuf::new(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: ScriptSigBuf::new(), sequence: Sequence::from_height(100), witness: Witness::default(), }; @@ -1413,7 +1410,7 @@ mod tests { assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, script_sig: script::Builder::new() .push_slice(<&PushBytes>::try_from(sigser.as_slice()).unwrap()) .into_script(), @@ -1421,40 +1418,40 @@ mod tests { witness: Witness::default(), } ); - assert_eq!(bare.unsigned_script_sig(), bitcoin::ScriptBuf::new()); + assert_eq!(bare.unsigned_script_sig(), ScriptSigBuf::new()); let pkh = Descriptor::new_pkh(pk).unwrap(); pkh.satisfy(&mut txin, &satisfier).expect("satisfaction"); assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, script_sig: script::Builder::new() .push_slice(<&PushBytes>::try_from(sigser.as_slice()).unwrap()) - .push_key(&pk) + .push_key(pk) .into_script(), sequence: Sequence::from_height(100), witness: Witness::default(), } ); - assert_eq!(pkh.unsigned_script_sig(), bitcoin::ScriptBuf::new()); + assert_eq!(pkh.unsigned_script_sig(), ScriptSigBuf::new()); let wpkh = Descriptor::new_wpkh(pk).unwrap(); wpkh.satisfy(&mut txin, &satisfier).expect("satisfaction"); assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: bitcoin::ScriptBuf::new(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: ScriptSigBuf::new(), sequence: Sequence::from_height(100), witness: Witness::from_slice(&[sigser.clone(), pk.to_bytes()]), } ); - assert_eq!(wpkh.unsigned_script_sig(), bitcoin::ScriptBuf::new()); + assert_eq!(wpkh.unsigned_script_sig(), ScriptSigBuf::new()); let shwpkh = Descriptor::new_sh_wpkh(pk).unwrap(); shwpkh.satisfy(&mut txin, &satisfier).expect("satisfaction"); - let redeem_script = script::Builder::new() + let redeem_script: script::RedeemScriptBuf = script::Builder::new() .push_opcode(opcodes::all::OP_PUSHBYTES_0) .push_slice( hash160::Hash::from_str("d1b2a1faf62e73460af885c687dee3b7189cd8ab") @@ -1465,7 +1462,7 @@ mod tests { assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, script_sig: script::Builder::new() .push_slice(<&PushBytes>::try_from(redeem_script.as_bytes()).unwrap()) .into_script(), @@ -1486,16 +1483,16 @@ mod tests { assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, script_sig: script::Builder::new() .push_slice(<&PushBytes>::try_from(sigser.as_slice()).unwrap()) - .push_slice(<&PushBytes>::try_from(ms.encode().as_bytes()).unwrap()) + .push_slice(<&PushBytes>::try_from(ms.encode::().as_bytes()).unwrap()) .into_script(), sequence: Sequence::from_height(100), witness: Witness::default(), } ); - assert_eq!(sh.unsigned_script_sig(), bitcoin::ScriptBuf::new()); + assert_eq!(sh.unsigned_script_sig(), ScriptSigBuf::new()); let ms = ms_str!("c:pk_k({})", pk); @@ -1504,31 +1501,32 @@ mod tests { assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: bitcoin::ScriptBuf::new(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: ScriptSigBuf::new(), sequence: Sequence::from_height(100), - witness: Witness::from_slice(&[sigser.clone(), ms.encode().into_bytes()]), + witness: Witness::from_slice(&[sigser.clone(), ms.encode::().into_bytes()]), } ); - assert_eq!(wsh.unsigned_script_sig(), bitcoin::ScriptBuf::new()); + assert_eq!(wsh.unsigned_script_sig(), ScriptSigBuf::new()); let shwsh = Descriptor::new_sh_wsh(ms.clone()).unwrap(); shwsh.satisfy(&mut txin, &satisfier).expect("satisfaction"); + let wsh_script = ms.encode().to_p2wsh().unwrap(); assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, script_sig: script::Builder::new() - .push_slice(<&PushBytes>::try_from(ms.encode().to_p2wsh().as_bytes()).unwrap()) + .push_slice(<&PushBytes>::try_from(wsh_script.as_bytes()).unwrap()) .into_script(), sequence: Sequence::from_height(100), - witness: Witness::from_slice(&[sigser.clone(), ms.encode().into_bytes()]), + witness: Witness::from_slice(&[sigser.clone(), ms.encode::().into_bytes()]), } ); assert_eq!( shwsh.unsigned_script_sig(), script::Builder::new() - .push_slice(<&PushBytes>::try_from(ms.encode().to_p2wsh().as_bytes()).unwrap()) + .push_slice(<&PushBytes>::try_from(wsh_script.as_bytes()).unwrap()) .into_script() ); } @@ -1538,7 +1536,7 @@ mod tests { let descriptor = Descriptor::::from_str("wsh(after(1000))").unwrap(); let script = descriptor.explicit_script().unwrap(); - let actual_instructions: Vec<_> = script.instructions().collect(); + let actual_instructions: Vec<_> = script.as_script().instructions().collect(); let check = actual_instructions.last().unwrap(); assert_eq!(check, &Ok(Instruction::Op(OP_CLTV))) @@ -1549,7 +1547,7 @@ mod tests { let descriptor = Descriptor::::from_str("wsh(older(1000))").unwrap(); let script = descriptor.explicit_script().unwrap(); - let actual_instructions: Vec<_> = script.instructions().collect(); + let actual_instructions: Vec<_> = script.as_script().instructions().collect(); let check = actual_instructions.last().unwrap(); assert_eq!(check, &Ok(Instruction::Op(OP_CSV))) @@ -1598,7 +1596,7 @@ mod tests { ); assert_eq!( descriptor.spend_info().merkle_root().unwrap().to_string(), - "e1597abcb76f7cbc0792cf04a9c2d4f39caed1ede0afef772064126f28c69b09" + "1f52e6084135fde476cd08f9e86743ce666ea52298175b2eb11f155e01c9ea50" ); } @@ -1664,8 +1662,8 @@ mod tests { .unwrap(); let mut txin = bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: bitcoin::ScriptBuf::new(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: ScriptSigBuf::new(), sequence: Sequence::ZERO, witness: Witness::default(), }; @@ -1855,7 +1853,6 @@ mod tests { #[test] fn test_sortedmulti() { fn _test_sortedmulti(raw_desc_one: &str, raw_desc_two: &str, raw_addr_expected: &str) { - let secp_ctx = secp256k1::Secp256k1::verification_only(); let index = 5; // Parse descriptor @@ -1870,13 +1867,13 @@ mod tests { let addr_one = desc_one .at_derivation_index(index) .unwrap() - .derived_descriptor(&secp_ctx) + .derived_descriptor() .address(bitcoin::Network::Bitcoin) .unwrap(); let addr_two = desc_two .at_derivation_index(index) .unwrap() - .derived_descriptor(&secp_ctx) + .derived_descriptor() .address(bitcoin::Network::Bitcoin) .unwrap(); let addr_expected = bitcoin::Address::from_str(raw_addr_expected) @@ -1910,17 +1907,16 @@ mod tests { #[test] fn test_parse_descriptor() { - let secp = &secp256k1::Secp256k1::signing_only(); - let (descriptor, key_map) = Descriptor::parse_descriptor(secp, "wpkh(tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/44'/0'/0'/0/*)").unwrap(); + let (descriptor, key_map) = Descriptor::parse_descriptor("wpkh(tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/44'/0'/0'/0/*)").unwrap(); assert_eq!(descriptor.to_string(), "wpkh([2cbe2a6d/44'/0'/0']tpubDCvNhURocXGZsLNqWcqD3syHTqPXrMSTwi8feKVwAcpi29oYKsDD3Vex7x2TDneKMVN23RbLprfxB69v94iYqdaYHsVz3kPR37NQXeqouVz/0/*)#nhdxg96s"); assert_eq!(key_map.len(), 1); // https://github.com/bitcoin/bitcoin/blob/7ae86b3c6845873ca96650fc69beb4ae5285c801/src/test/descriptor_tests.cpp#L355-L360 macro_rules! check_invalid_checksum { - ($secp: ident,$($desc: expr),*) => { + ($($desc: expr),*) => { use crate::{ParseError, ParseTreeError}; $( - match Descriptor::parse_descriptor($secp, $desc) { + match Descriptor::parse_descriptor($desc) { Err(Error::Parse(ParseError::Tree(ParseTreeError::Checksum(_)))) => {}, Err(e) => panic!("Expected bad checksum for {}, got '{}'", $desc, e), _ => panic!("Invalid checksum treated as valid: {}", $desc), @@ -1928,7 +1924,7 @@ mod tests { )* }; } - check_invalid_checksum!(secp, + check_invalid_checksum!( "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#", "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfyq", @@ -1942,8 +1938,8 @@ mod tests { "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))##tjq09x4t" ); - Descriptor::parse_descriptor(secp, "sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy").expect("Valid descriptor with checksum"); - Descriptor::parse_descriptor(secp, "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t").expect("Valid descriptor with checksum"); + Descriptor::parse_descriptor("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy").expect("Valid descriptor with checksum"); + Descriptor::parse_descriptor("sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t").expect("Valid descriptor with checksum"); } #[test] @@ -1970,10 +1966,9 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))"; #[test] fn parse_with_secrets() { - let secp = &secp256k1::Secp256k1::signing_only(); let descriptor_str = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)#v20xlvm9"; let (descriptor, keymap) = - Descriptor::::parse_descriptor(secp, descriptor_str).unwrap(); + Descriptor::::parse_descriptor(descriptor_str).unwrap(); let expected = "wpkh([a12b02f4/44'/0'/0']xpub6BzhLAQUDcBUfHRQHZxDF2AbcJqp4Kaeq6bzJpXrjrWuK26ymTFwkEFbxPra2bJ7yeZKbDjfDeFwxe93JMqpo5SsPJH6dZdvV9kMzJkAZ69/0/*)#u37l7u8u"; assert_eq!(expected, descriptor.to_string()); @@ -2011,9 +2006,8 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))"; #[test] fn test_find_derivation_index_for_spk() { - let secp = secp256k1::Secp256k1::verification_only(); let descriptor = Descriptor::from_str("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)").unwrap(); - let script_at_0_1 = ScriptBuf::from_hex( + let script_at_0_1 = ScriptPubKeyBuf::from_hex( "5120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb", ) .unwrap(); @@ -2022,13 +2016,13 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))"; ) .unwrap(); - assert_eq!(descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..1), Ok(None)); + assert_eq!(descriptor.find_derivation_index_for_spk(&script_at_0_1, 0..1), Ok(None)); assert_eq!( - descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..2), + descriptor.find_derivation_index_for_spk(&script_at_0_1, 0..2), Ok(Some((1, expected_concrete.clone()))) ); assert_eq!( - descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..10), + descriptor.find_derivation_index_for_spk(&script_at_0_1, 0..10), Ok(Some((1, expected_concrete))) ); } @@ -2190,7 +2184,7 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))"; "02015e4cb53458bf813db8c79968e76e10d13ed6426a23fa71c2f41ba021c2a7ab", ) .unwrap(); - let x_only_key = bitcoin::key::XOnlyPublicKey::from_str( + let x_only_key = bitcoin::XOnlyPublicKey::from_str( "015e4cb53458bf813db8c79968e76e10d13ed6426a23fa71c2f41ba021c2a7ab", ) .unwrap(); @@ -2236,14 +2230,12 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))"; #[test] fn regression_806() { - let secp = secp256k1::Secp256k1::signing_only(); type Desc = Descriptor; // OK Desc::from_str("pkh(111111111111111111111111111111110000008375319363688624584A111111)") .unwrap_err(); // ERR: crashes in translate_pk Desc::parse_descriptor( - &secp, "pkh(111111111111111111111111111111110000008375319363688624584A111111)", ) .unwrap_err(); diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index a78867fba..52054c5d5 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -8,7 +8,8 @@ use core::convert::TryFrom; use core::fmt; -use bitcoin::{Address, Network, ScriptBuf, Weight}; +use bitcoin::script::{ScriptPubKeyBuf, ScriptSigBuf, WitnessScriptBuf, WitnessScriptExt}; +use bitcoin::{Address, Network, Weight}; use super::SortedMultiVec; use crate::descriptor::{write_descriptor, DefiniteDescriptorKey}; @@ -144,18 +145,27 @@ impl Wsh { impl Wsh { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { self.inner_script().to_p2wsh() } + pub fn script_pubkey(&self) -> ScriptPubKeyBuf { + self.inner_script().to_p2wsh().expect("valid witness script") + } /// Obtains the corresponding script pubkey for this descriptor. pub fn address(&self, network: Network) -> Address { match self.inner { - WshInner::SortedMulti(ref smv) => Address::p2wsh(&smv.encode(), network), - WshInner::Ms(ref ms) => Address::p2wsh(&ms.encode(), network), + WshInner::SortedMulti(ref smv) => { + // FIXME: Do we bubble up the error or is Claude's expect message correct? + Address::p2wsh(&smv.encode(), network) + .expect("Miniscript descriptors produce valid witness scripts") + } + WshInner::Ms(ref ms) => { + Address::p2wsh(&ms.encode(), network) + .expect("Miniscript descriptors produce valid witness scripts") + } } } /// Obtains the underlying miniscript for this descriptor. - pub fn inner_script(&self) -> ScriptBuf { + pub fn inner_script(&self) -> WitnessScriptBuf { match self.inner { WshInner::SortedMulti(ref smv) => smv.encode(), WshInner::Ms(ref ms) => ms.encode(), @@ -163,12 +173,12 @@ impl Wsh { } /// Obtains the pre bip-340 signature script code for this descriptor. - pub fn ecdsa_sighash_script_code(&self) -> ScriptBuf { self.inner_script() } + pub fn ecdsa_sighash_script_code(&self) -> WitnessScriptBuf { self.inner_script() } /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is /// possible to construct one using the `satisfier`. - pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { @@ -178,14 +188,14 @@ impl Wsh { }; let witness_script = self.inner_script(); witness.push(witness_script.into_bytes()); - let script_sig = ScriptBuf::new(); + let script_sig = ScriptSigBuf::new(); Ok((witness, script_sig)) } /// Returns satisfying, possibly malleable, witness and scriptSig with /// minimum weight to spend an output controlled by the given descriptor if /// it is possible to construct one using the `satisfier`. - pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { @@ -194,7 +204,7 @@ impl Wsh { WshInner::Ms(ref ms) => ms.satisfy_malleable(satisfier)?, }; witness.push(self.inner_script().into_bytes()); - let script_sig = ScriptBuf::new(); + let script_sig = ScriptSigBuf::new(); Ok((witness, script_sig)) } } @@ -374,12 +384,12 @@ impl Wpkh { impl Wpkh { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { + pub fn script_pubkey(&self) -> ScriptPubKeyBuf { let pk = self.pk.to_public_key(); let compressed = bitcoin::key::CompressedPublicKey::try_from(pk) .expect("wpkh descriptors have compressed keys"); - let addr = Address::p2wpkh(&compressed, Network::Bitcoin); + let addr = Address::p2wpkh(compressed, Network::Bitcoin); addr.script_pubkey() } @@ -389,14 +399,14 @@ impl Wpkh { let compressed = bitcoin::key::CompressedPublicKey::try_from(pk) .expect("Rust Miniscript types don't allow uncompressed pks in segwit descriptors"); - Address::p2wpkh(&compressed, network) + Address::p2wpkh(compressed, network) } /// Obtains the underlying miniscript for this descriptor. - pub fn inner_script(&self) -> ScriptBuf { self.script_pubkey() } + pub fn inner_script(&self) -> ScriptPubKeyBuf { self.script_pubkey() } /// Obtains the pre bip-340 signature script code for this descriptor. - pub fn ecdsa_sighash_script_code(&self) -> ScriptBuf { + pub fn ecdsa_sighash_script_code(&self) -> ScriptPubKeyBuf { // For SegWit outputs, it is defined by bip-0143 (quoted below) and is different from // the previous txo's scriptPubKey. // The item 5: @@ -408,13 +418,13 @@ impl Wpkh { /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is /// possible to construct one using the `satisfier`. - pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { if let Some(sig) = satisfier.lookup_ecdsa_sig(&self.pk) { let sig_vec = sig.to_vec(); - let script_sig = ScriptBuf::new(); + let script_sig = ScriptSigBuf::new(); let witness = vec![sig_vec, self.pk.to_public_key().to_bytes()]; Ok((witness, script_sig)) } else { @@ -425,7 +435,7 @@ impl Wpkh { /// Returns satisfying, possibly malleable, witness and scriptSig with /// minimum weight to spend an output controlled by the given descriptor if /// it is possible to construct one using the `satisfier`. - pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index 4acb5fa73..fc22a2908 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -10,8 +10,8 @@ use core::convert::TryFrom; use core::fmt; -use bitcoin::script::PushBytes; -use bitcoin::{script, Address, Network, ScriptBuf, Weight}; +use bitcoin::script::{self, PushBytes, RedeemScriptBuf, ScriptExt, ScriptPubKeyBuf, ScriptSigBuf, WitnessScriptExt}; +use bitcoin::{Address, Network, Weight}; use super::{SortedMultiVec, Wpkh, Wsh}; use crate::descriptor::{write_descriptor, DefiniteDescriptorKey}; @@ -274,12 +274,13 @@ impl Sh { impl Sh { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { + pub fn script_pubkey(&self) -> ScriptPubKeyBuf { + // FIXME: Do we bubble up the error or is Claude's expect message correct? match self.inner { - ShInner::Wsh(ref wsh) => wsh.script_pubkey().to_p2sh(), - ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey().to_p2sh(), - ShInner::SortedMulti(ref smv) => smv.encode().to_p2sh(), - ShInner::Ms(ref ms) => ms.encode().to_p2sh(), + ShInner::Wsh(ref wsh) => wsh.script_pubkey().to_p2sh().expect("valid p2sh script"), + ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey().to_p2sh().expect("valid p2sh script"), + ShInner::SortedMulti(ref smv) => smv.encode::().to_p2sh().expect("valid p2sh script"), + ShInner::Ms(ref ms) => ms.encode::().to_p2sh().expect("valid p2sh script"), } } @@ -293,37 +294,37 @@ impl Sh { } fn address_fallible(&self, network: Network) -> Result { - let script = match self.inner { - ShInner::Wsh(ref wsh) => wsh.script_pubkey(), - ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey(), - ShInner::SortedMulti(ref smv) => smv.encode(), - ShInner::Ms(ref ms) => ms.encode(), + // FIXME: Do we bubble up the error or is Claude's expect message correct? + let address = match self.inner { + ShInner::Wsh(ref wsh) => Address::p2sh(&wsh.script_pubkey(), network).expect("valid p2sh script"), + ShInner::Wpkh(ref wpkh) => Address::p2sh(&wpkh.script_pubkey(), network).expect("valid p2sh script"), + ShInner::SortedMulti(ref smv) => Address::p2sh(&smv.encode::(), network).expect("valid p2sh script"), + ShInner::Ms(ref ms) => Address::p2sh(&ms.encode::(), network).expect("valid p2sh script"), }; - let address = Address::p2sh(&script, network)?; Ok(address) } /// Obtain the underlying miniscript for this descriptor - pub fn inner_script(&self) -> ScriptBuf { + pub fn inner_script(&self) -> RedeemScriptBuf { match self.inner { - ShInner::Wsh(ref wsh) => wsh.inner_script(), - ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey(), - ShInner::SortedMulti(ref smv) => smv.encode(), - ShInner::Ms(ref ms) => ms.encode(), + ShInner::Wsh(ref wsh) => RedeemScriptBuf::from_bytes(wsh.script_pubkey().into_bytes()), + ShInner::Wpkh(ref wpkh) => RedeemScriptBuf::from_bytes(wpkh.script_pubkey().into_bytes()), + ShInner::SortedMulti(ref smv) => smv.encode::(), + ShInner::Ms(ref ms) => ms.encode::(), } } /// Obtains the pre bip-340 signature script code for this descriptor. - pub fn ecdsa_sighash_script_code(&self) -> ScriptBuf { + pub fn ecdsa_sighash_script_code(&self) -> RedeemScriptBuf { match self.inner { // - For P2WSH witness program, if the witnessScript does not contain any `OP_CODESEPARATOR`, // the `scriptCode` is the `witnessScript` serialized as scripts inside CTxOut. - ShInner::Wsh(ref wsh) => wsh.ecdsa_sighash_script_code(), - ShInner::SortedMulti(ref smv) => smv.encode(), - ShInner::Wpkh(ref wpkh) => wpkh.ecdsa_sighash_script_code(), + ShInner::Wsh(ref wsh) => RedeemScriptBuf::from_bytes(wsh.ecdsa_sighash_script_code().into_bytes()), + ShInner::SortedMulti(ref smv) => smv.encode::(), + ShInner::Wpkh(ref wpkh) => RedeemScriptBuf::from_bytes(wpkh.ecdsa_sighash_script_code().into_bytes()), // For "legacy" P2SH outputs, it is defined as the txo's redeemScript. - ShInner::Ms(ref ms) => ms.encode(), + ShInner::Ms(ref ms) => ms.encode::(), } } @@ -334,11 +335,12 @@ impl Sh { /// This is used in Segwit transactions to produce an unsigned transaction /// whose txid will not change during signing (since only the witness data /// will change). - pub fn unsigned_script_sig(&self) -> ScriptBuf { + pub fn unsigned_script_sig(&self) -> ScriptSigBuf { match self.inner { ShInner::Wsh(ref wsh) => { // wsh explicit must contain exactly 1 element - let witness_script = wsh.inner_script().to_p2wsh(); + // FIXME: Do we bubble up the error or is Claude's expect message correct? + let witness_script = wsh.inner_script().to_p2wsh().expect("valid witness script"); let push_bytes = <&PushBytes>::try_from(witness_script.as_bytes()) .expect("Witness script is not too large"); script::Builder::new().push_slice(push_bytes).into_script() @@ -349,14 +351,14 @@ impl Sh { <&PushBytes>::try_from(redeem_script.as_bytes()).expect("Script not too large"); script::Builder::new().push_slice(push_bytes).into_script() } - ShInner::SortedMulti(..) | ShInner::Ms(..) => ScriptBuf::new(), + ShInner::SortedMulti(..) | ShInner::Ms(..) => ScriptSigBuf::new(), } } /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is /// possible to construct one using the `satisfier`. - pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { @@ -372,14 +374,14 @@ impl Sh { } ShInner::SortedMulti(ref smv) => { let mut script_witness = smv.satisfy(satisfier)?; - script_witness.push(smv.encode().into_bytes()); + script_witness.push(smv.encode::().into_bytes()); let script_sig = witness_to_scriptsig(&script_witness); let witness = vec![]; Ok((witness, script_sig)) } ShInner::Ms(ref ms) => { let mut script_witness = ms.satisfy(satisfier)?; - script_witness.push(ms.encode().into_bytes()); + script_witness.push(ms.encode::().into_bytes()); let script_sig = witness_to_scriptsig(&script_witness); let witness = vec![]; Ok((witness, script_sig)) @@ -390,7 +392,7 @@ impl Sh { /// Returns satisfying, possibly malleable, witness and scriptSig with /// minimum weight to spend an output controlled by the given descriptor if /// it is possible to construct one using the `satisfier`. - pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { @@ -402,7 +404,7 @@ impl Sh { } ShInner::Ms(ref ms) => { let mut script_witness = ms.satisfy_malleable(satisfier)?; - script_witness.push(ms.encode().into_bytes()); + script_witness.push(ms.encode::().into_bytes()); let script_sig = witness_to_scriptsig(&script_witness); let witness = vec![]; Ok((witness, script_sig)) diff --git a/src/descriptor/sortedmulti.rs b/src/descriptor/sortedmulti.rs index 5ba952ff0..a417fb35a 100644 --- a/src/descriptor/sortedmulti.rs +++ b/src/descriptor/sortedmulti.rs @@ -136,7 +136,7 @@ impl SortedMultiVec { } /// Encode as a Bitcoin script - pub fn encode(&self) -> script::ScriptBuf + pub fn encode(&self) -> script::ScriptBuf where Pk: ToPublicKey, { diff --git a/src/descriptor/tr/mod.rs b/src/descriptor/tr/mod.rs index 203e3cee2..2fbe40567 100644 --- a/src/descriptor/tr/mod.rs +++ b/src/descriptor/tr/mod.rs @@ -3,7 +3,8 @@ use core::{cmp, fmt, hash}; use bitcoin::taproot::{TAPROOT_CONTROL_BASE_SIZE, TAPROOT_CONTROL_NODE_SIZE}; -use bitcoin::{opcodes, Address, Network, ScriptBuf, Weight}; +use bitcoin::script::{ScriptPubKeyBuf, ScriptSigBuf, TapScriptBuf}; +use bitcoin::{opcodes, Address, Network, Weight}; use sync::Arc; use super::checksum; @@ -267,7 +268,7 @@ impl Tr { impl Tr { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { + pub fn script_pubkey(&self) -> ScriptPubKeyBuf { let output_key = self.spend_info().output_key(); let builder = bitcoin::blockdata::script::Builder::new(); builder @@ -285,7 +286,7 @@ impl Tr { /// Returns satisfying non-malleable witness and scriptSig with minimum /// weight to spend an output controlled by the given descriptor if it is /// possible to construct one using the `satisfier`. - pub fn get_satisfaction(&self, satisfier: &S) -> Result<(Vec>, ScriptBuf), Error> + pub fn get_satisfaction(&self, satisfier: &S) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { @@ -293,7 +294,7 @@ impl Tr { .try_completing(satisfier) .expect("the same satisfier should manage to complete the template"); if let Witness::Stack(stack) = satisfaction.stack { - Ok((stack, ScriptBuf::new())) + Ok((stack, ScriptSigBuf::new())) } else { Err(Error::CouldNotSatisfy) } @@ -305,7 +306,7 @@ impl Tr { pub fn get_satisfaction_mall( &self, satisfier: &S, - ) -> Result<(Vec>, ScriptBuf), Error> + ) -> Result<(Vec>, ScriptSigBuf), Error> where S: Satisfier, { @@ -313,7 +314,7 @@ impl Tr { .try_completing(satisfier) .expect("the same satisfier should manage to complete the template"); if let Witness::Stack(stack) = satisfaction.stack { - Ok((stack, ScriptBuf::new())) + Ok((stack, ScriptSigBuf::new())) } else { Err(Error::CouldNotSatisfy) } @@ -503,7 +504,7 @@ where _ => unreachable!(), }; - let script = ScriptBuf::from(leaf.script()); + let script = TapScriptBuf::from(leaf.script()); let control_block = leaf.control_block().clone(); wit.push(Placeholder::TapScript(script)); diff --git a/src/descriptor/tr/spend_info.rs b/src/descriptor/tr/spend_info.rs index b0d23121d..c62adbf3c 100644 --- a/src/descriptor/tr/spend_info.rs +++ b/src/descriptor/tr/spend_info.rs @@ -7,9 +7,8 @@ //! use bitcoin::key::{Parity, TapTweak as _, TweakedPublicKey, UntweakedPublicKey}; -use bitcoin::secp256k1::Secp256k1; -use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash, TaprootMerkleBranch}; -use bitcoin::{Script, ScriptBuf}; +use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash, TaprootMerkleBranchBuf}; +use bitcoin::script::{TapScript, TapScriptBuf}; use crate::miniscript::context::Tap; use crate::prelude::Vec; @@ -138,16 +137,16 @@ impl TrSpendInfo { /// Constructs a [`TrSpendInfo`] for a [`super::Tr`]. pub fn from_tr(tr: &super::Tr) -> Self { - let internal_key = tr.internal_key().to_x_only_pubkey(); + // FIXME: Does this highlight an API hole in the new `bitcoin::XOnlyPublicKey`? + let internal_key: UntweakedPublicKey = tr.internal_key().to_x_only_pubkey().into(); let nodes = match tr.tap_tree() { Some(tree) => Self::nodes_from_tap_tree(tree), None => vec![], }; - let secp = Secp256k1::verification_only(); let (output_key, output_key_parity) = - internal_key.tap_tweak(&secp, nodes.first().map(|node| node.sibling_hash)); + internal_key.tap_tweak(nodes.first().map(|node| node.sibling_hash)); TrSpendInfo { internal_key, output_key, output_key_parity, nodes } } @@ -204,7 +203,7 @@ impl TrSpendInfo { builder = builder .add_leaf_with_ver( leaf.depth(), - ScriptBuf::from(leaf.script()), + TapScriptBuf::from(leaf.script()), leaf.leaf_version(), ) .expect("iterating through tree in correct DFS order") @@ -222,7 +221,7 @@ struct TrSpendInfoNode { #[derive(Debug)] struct LeafData { - script: ScriptBuf, + script: TapScriptBuf, miniscript: Arc>, leaf_hash: TapLeafHash, } @@ -280,7 +279,7 @@ impl<'sp, Pk: MiniscriptKey> Iterator for TrSpendInfoIter<'sp, Pk> { leaf_version: LeafVersion::TapScript, output_key_parity: self.spend_info.output_key_parity, internal_key: self.spend_info.internal_key, - merkle_branch: TaprootMerkleBranch::try_from(merkle_stack) + merkle_branch: TaprootMerkleBranchBuf::try_from(merkle_stack) .expect("merkle stack guaranteed to be within allowable length"), }, }); @@ -296,7 +295,7 @@ impl<'sp, Pk: MiniscriptKey> Iterator for TrSpendInfoIter<'sp, Pk> { /// Item yielded from a [`TrSpendInfoIter`]. #[derive(Clone, PartialEq, Eq, Debug)] pub struct TrSpendInfoIterItem<'tr, Pk: MiniscriptKey> { - script: &'tr Script, + script: &'tr TapScript, miniscript: &'tr Arc>, leaf_hash: TapLeafHash, control_block: ControlBlock, @@ -305,7 +304,7 @@ pub struct TrSpendInfoIterItem<'tr, Pk: MiniscriptKey> { impl<'sp, Pk: MiniscriptKey> TrSpendInfoIterItem<'sp, Pk> { /// The Tapscript of this leaf. #[inline] - pub fn script(&self) -> &'sp Script { self.script } + pub fn script(&self) -> &'sp TapScript { self.script } /// The Tapscript of this leaf, in Miniscript form. #[inline] @@ -369,11 +368,10 @@ mod tests { #[derive(PartialEq, Eq, Debug)] struct ExpectedLeaf { leaf_hash: TapLeafHash, - branch: TaprootMerkleBranch, + branch: TaprootMerkleBranchBuf, } fn test_cases() -> Vec<(String, ExpectedTree, Vec)> { - let secp = Secp256k1::verification_only(); let pk = "03cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115" .parse::() .unwrap(); @@ -391,8 +389,9 @@ mod tests { // Empty tree let merkle_root = None; - let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + // FIXME: Does this highlight an API hole in the new `bitcoin::XOnlyPublicKey`? + let internal_key: UntweakedPublicKey = pk.to_x_only_pubkey().into(); + let (output_key, output_key_parity) = internal_key.tap_tweak(merkle_root); ret.push(( format!("tr({pk})"), ExpectedTree { internal_key, output_key, output_key_parity, merkle_root }, @@ -401,14 +400,14 @@ mod tests { // Single-leaf tree let merkle_root = Some(TapNodeHash::from(zero_hash)); - let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + let internal_key: UntweakedPublicKey = pk.to_x_only_pubkey().into(); + let (output_key, output_key_parity) = internal_key.tap_tweak(merkle_root); ret.push(( format!("tr({pk},0)"), ExpectedTree { internal_key, output_key, output_key_parity, merkle_root }, vec![ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![]).unwrap(), + branch: TaprootMerkleBranchBuf::try_from(vec![]).unwrap(), }], )); @@ -418,20 +417,20 @@ mod tests { .parse() .unwrap(), ); - let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + let internal_key: UntweakedPublicKey = pk.to_x_only_pubkey().into(); + let (output_key, output_key_parity) = internal_key.tap_tweak(merkle_root); ret.push(( format!("tr({pk},{{0,0}})"), ExpectedTree { internal_key, output_key, output_key_parity, merkle_root }, vec![ ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![TapNodeHash::from(zero_hash)]) + branch: TaprootMerkleBranchBuf::try_from(vec![TapNodeHash::from(zero_hash)]) .unwrap(), }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![TapNodeHash::from(zero_hash)]) + branch: TaprootMerkleBranchBuf::try_from(vec![TapNodeHash::from(zero_hash)]) .unwrap(), }, ], @@ -443,20 +442,20 @@ mod tests { .parse() .unwrap(), ); - let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + let internal_key: UntweakedPublicKey = pk.to_x_only_pubkey().into(); + let (output_key, output_key_parity) = internal_key.tap_tweak(merkle_root); ret.push(( format!("tr({pk},{{0,1}})"), ExpectedTree { internal_key, output_key, output_key_parity, merkle_root }, vec![ ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![TapNodeHash::from(one_hash)]) + branch: TaprootMerkleBranchBuf::try_from(vec![TapNodeHash::from(one_hash)]) .unwrap(), }, ExpectedLeaf { leaf_hash: one_hash, - branch: TaprootMerkleBranch::try_from(vec![TapNodeHash::from(zero_hash)]) + branch: TaprootMerkleBranchBuf::try_from(vec![TapNodeHash::from(zero_hash)]) .unwrap(), }, ], @@ -468,8 +467,8 @@ mod tests { .parse() .unwrap(), ); - let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + let internal_key: UntweakedPublicKey = pk.to_x_only_pubkey().into(); + let (output_key, output_key_parity) = internal_key.tap_tweak(merkle_root); ret.push(( format!("tr({pk},{{0,{{0,tv:0}}}})"), @@ -477,7 +476,7 @@ mod tests { vec![ ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "573d619569d58a36b52187e56f168650ac17f66a9a3afaf054900a04001019b3" .parse::() .unwrap(), @@ -486,7 +485,7 @@ mod tests { }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "64ac241466a5e7032586718ff7465716f77a88d89946ce472daa4c3d0b81148f" .parse::() .unwrap(), @@ -498,7 +497,7 @@ mod tests { leaf_hash: "64ac241466a5e7032586718ff7465716f77a88d89946ce472daa4c3d0b81148f" .parse() .unwrap(), - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ TapNodeHash::from(zero_hash), TapNodeHash::from(zero_hash), ]) @@ -513,8 +512,8 @@ mod tests { .parse() .unwrap(), ); - let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + let internal_key: UntweakedPublicKey = pk.to_x_only_pubkey().into(); + let (output_key, output_key_parity) = internal_key.tap_tweak(merkle_root); ret.push(( format!("tr({pk},{{uuu:0,{{0,uu:0}}}})"), @@ -524,7 +523,7 @@ mod tests { leaf_hash: "6498e1d56640a272493d1d87549f3347dc448ca674556a2110cdfe100e3c238b" .parse() .unwrap(), - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "7e3e98bab404812c8eebd21c5d825527676b8e9f261f7ad479f3a08a83a43fb4" .parse::() .unwrap(), @@ -533,7 +532,7 @@ mod tests { }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "19417c32bc6ca7e0f6e65b006ac305107c6add73c8bef31181037e6faaa55e7f" .parse::() .unwrap(), @@ -547,7 +546,7 @@ mod tests { leaf_hash: "19417c32bc6ca7e0f6e65b006ac305107c6add73c8bef31181037e6faaa55e7f" .parse() .unwrap(), - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ TapNodeHash::from(zero_hash), "6498e1d56640a272493d1d87549f3347dc448ca674556a2110cdfe100e3c238b" .parse::() @@ -564,8 +563,8 @@ mod tests { .parse() .unwrap(), ); - let internal_key = pk.to_x_only_pubkey(); - let (output_key, output_key_parity) = internal_key.tap_tweak(&secp, merkle_root); + let internal_key: UntweakedPublicKey = pk.to_x_only_pubkey().into(); + let (output_key, output_key_parity) = internal_key.tap_tweak(merkle_root); ret.push(( format!("tr({pk},{{{{0,{{uuu:0,0}}}},{{0,uu:0}}}})"), @@ -573,7 +572,7 @@ mod tests { vec![ ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "57e3b7d414075ff4864deec9efa99db4462c038706306e02c58e02e957c8a51e" .parse::() .unwrap(), @@ -587,7 +586,7 @@ mod tests { leaf_hash: "6498e1d56640a272493d1d87549f3347dc448ca674556a2110cdfe100e3c238b" .parse() .unwrap(), - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ TapNodeHash::from(zero_hash), TapNodeHash::from(zero_hash), "7e3e98bab404812c8eebd21c5d825527676b8e9f261f7ad479f3a08a83a43fb4" @@ -598,7 +597,7 @@ mod tests { }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "6498e1d56640a272493d1d87549f3347dc448ca674556a2110cdfe100e3c238b" .parse::() .unwrap(), @@ -611,7 +610,7 @@ mod tests { }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "19417c32bc6ca7e0f6e65b006ac305107c6add73c8bef31181037e6faaa55e7f" .parse::() .unwrap(), @@ -625,7 +624,7 @@ mod tests { leaf_hash: "19417c32bc6ca7e0f6e65b006ac305107c6add73c8bef31181037e6faaa55e7f" .parse() .unwrap(), - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ TapNodeHash::from(zero_hash), "e034d7d8b221034861bf3893c63cb0ff60d28a7a00090d0dc57c26fec91983cb" .parse::() diff --git a/src/descriptor/tr/taptree.rs b/src/descriptor/tr/taptree.rs index 27e860390..512afc69c 100644 --- a/src/descriptor/tr/taptree.rs +++ b/src/descriptor/tr/taptree.rs @@ -188,7 +188,7 @@ pub struct TapTreeIterItem<'tr, Pk: MiniscriptKey> { impl<'tr, Pk: MiniscriptKey> TapTreeIterItem<'tr, Pk> { /// The Tapscript in the leaf. /// - /// To obtain a [`bitcoin::Script`] from this node, call [`Miniscript::encode`] + /// To obtain a [`bitcoin::script::ScriptBuf`] from this node, call [`Miniscript::encode`] /// on the returned value. #[inline] pub fn miniscript(&self) -> &'tr Arc> { self.node } @@ -216,7 +216,7 @@ impl TapTreeIterItem<'_, Pk> { /// all (or many) of the leaves of the tree, you may instead want to call /// [`super::Tr::spend_info`] and use the [`super::TrSpendInfo::leaves`] iterator instead. #[inline] - pub fn compute_script(&self) -> bitcoin::ScriptBuf { self.node.encode() } + pub fn compute_script(&self) -> bitcoin::script::TapScriptBuf { self.node.encode() } /// Computes the [`TapLeafHash`] of the leaf. /// diff --git a/src/interpreter/error.rs b/src/interpreter/error.rs index 4e47932a6..28f5dfa55 100644 --- a/src/interpreter/error.rs +++ b/src/interpreter/error.rs @@ -33,7 +33,7 @@ pub enum Error { /// General Interpreter error. CouldNotEvaluate, /// ECDSA Signature related error - EcdsaSig(bitcoin::ecdsa::Error), + EcdsaSig(bitcoin::ecdsa::DecodeError), /// We expected a push (including a `OP_1` but no other numeric pushes) ExpectedPush, /// The preimage to the hash function must be exactly 32 bytes. @@ -53,7 +53,7 @@ pub enum Error { /// ecdsa Signature failed to verify InvalidEcdsaSignature(bitcoin::PublicKey), /// Signature failed to verify - InvalidSchnorrSignature(bitcoin::key::XOnlyPublicKey), + InvalidSchnorrSignature(bitcoin::XOnlyPublicKey), /// Last byte of this signature isn't a standard sighash type NonStandardSighash(Vec), /// Miniscript error @@ -247,8 +247,8 @@ impl From for Error { } #[doc(hidden)] -impl From for Error { - fn from(e: bitcoin::ecdsa::Error) -> Error { Error::EcdsaSig(e) } +impl From for Error { + fn from(e: bitcoin::ecdsa::DecodeError) -> Error { Error::EcdsaSig(e) } } #[doc(hidden)] @@ -268,7 +268,7 @@ pub enum PkEvalErrInner { /// Full Key FullKey(bitcoin::PublicKey), /// XOnly Key - XOnlyKey(bitcoin::key::XOnlyPublicKey), + XOnlyKey(bitcoin::XOnlyPublicKey), } impl From for PkEvalErrInner { diff --git a/src/interpreter/inner.rs b/src/interpreter/inner.rs index b65e26a7f..c892c3e56 100644 --- a/src/interpreter/inner.rs +++ b/src/interpreter/inner.rs @@ -1,7 +1,9 @@ // Written in 2019 by Sanket Kanjular and Andrew Poelstra // SPDX-License-Identifier: CC0-1.0 -use bitcoin::hashes::{hash160, sha256, Hash}; +use bitcoin::blockdata::script::{ScriptBufExt as _, ScriptPubKeyBufExt as _, ScriptPubKeyExt as _}; +use bitcoin::hashes::{hash160, sha256}; +use bitcoin::script::{ScriptExt as _, ScriptPubKey, ScriptPubKeyBuf, ScriptSig}; use bitcoin::taproot::{ControlBlock, TAPROOT_ANNEX_PREFIX}; use bitcoin::Witness; @@ -43,7 +45,7 @@ fn script_from_stack_elem( ) -> Result, Error> { match *elem { stack::Element::Push(sl) => { - Miniscript::decode_consensus(bitcoin::Script::from_bytes(sl)).map_err(Error::from) + Miniscript::decode_consensus(ScriptPubKey::from_bytes(sl)).map_err(Error::from) } stack::Element::Satisfied => Ok(Miniscript::TRUE), stack::Element::Dissatisfied => Ok(Miniscript::FALSE), @@ -91,10 +93,10 @@ pub(super) enum Inner { /// Tr outputs don't have script code and return None. #[allow(clippy::collapsible_else_if)] pub(super) fn from_txdata<'txin>( - spk: &bitcoin::Script, - script_sig: &'txin bitcoin::Script, + spk: &ScriptPubKey, + script_sig: &'txin ScriptSig, witness: &'txin Witness, -) -> Result<(Inner, Stack<'txin>, Option), Error> { +) -> Result<(Inner, Stack<'txin>, Option), Error> { let mut ssig_stack: Stack = script_sig .instructions_minimal() .map(stack::Element::from_instruction) @@ -126,11 +128,12 @@ pub(super) fn from_txdata<'txin>( Err(Error::NonEmptyWitness) } else { match ssig_stack.pop() { + // FIXME: Andrew to check that we are happy with the new more-restrictive hashes API. Some(elem) => { let pk = pk_from_stack_elem(&elem, false)?; - if *spk - == bitcoin::ScriptBuf::new_p2pkh(&pk.to_pubkeyhash(SigType::Ecdsa).into()) - { + let hash160 = pk.to_pubkeyhash(SigType::Ecdsa); + let pkh = bitcoin::key::PubkeyHash::from_byte_array(hash160.to_byte_array()); + if *spk == ScriptPubKeyBuf::new_p2pkh(pkh) { Ok(( Inner::PublicKey(pk.into(), PubkeyType::Pkh), ssig_stack, @@ -152,11 +155,13 @@ pub(super) fn from_txdata<'txin>( Some(elem) => { let pk = pk_from_stack_elem(&elem, true)?; let hash160 = pk.to_pubkeyhash(SigType::Ecdsa); - if *spk == bitcoin::ScriptBuf::new_p2wpkh(&hash160.into()) { + let wpkh = bitcoin::key::WPubkeyHash::from_byte_array(hash160.to_byte_array()); + let pkh = bitcoin::key::PubkeyHash::from_byte_array(hash160.to_byte_array()); + if *spk == ScriptPubKeyBuf::new_p2wpkh(wpkh) { Ok(( Inner::PublicKey(pk.into(), PubkeyType::Wpkh), wit_stack, - Some(bitcoin::ScriptBuf::new_p2pkh(&hash160.into())), // bip143, why.. + Some(ScriptPubKeyBuf::new_p2pkh(pkh)), // bip143, why.. )) } else { Err(Error::IncorrectWPubkeyHash) @@ -176,7 +181,8 @@ pub(super) fn from_txdata<'txin>( let script = miniscript.encode(); let miniscript = miniscript.to_no_checks_ms(); let scripthash = sha256::Hash::hash(script.as_bytes()); - if *spk == bitcoin::ScriptBuf::new_p2wsh(&scripthash.into()) { + let wscript_hash = bitcoin::script::WScriptHash::from_byte_array(scripthash.to_byte_array()); + if *spk == ScriptPubKeyBuf::new_p2wsh(wscript_hash) { Ok((Inner::Script(miniscript, ScriptType::Wsh), wit_stack, Some(script))) } else { Err(Error::IncorrectWScriptHash) @@ -190,7 +196,8 @@ pub(super) fn from_txdata<'txin>( if !ssig_stack.is_empty() { Err(Error::NonEmptyScriptSig) } else { - let output_key = bitcoin::key::XOnlyPublicKey::from_slice(spk[2..].as_bytes()) + let k = <[u8; 32]>::try_from(spk[2..].as_bytes()).expect("32 bytes"); + let output_key = bitcoin::XOnlyPublicKey::from_byte_array(&k) .map_err(|_| Error::XOnlyPublicKeyParseError)?; let has_annex = wit_stack .last() @@ -220,10 +227,8 @@ pub(super) fn from_txdata<'txin>( ControlBlock::decode(ctrl_blk).map_err(Error::ControlBlockParse)?; let tap_script = script_from_stack_elem::(&tap_script)?; let ms = tap_script.to_no_checks_ms(); - // Creating new contexts is cheap - let secp = bitcoin::secp256k1::Secp256k1::verification_only(); let tap_script = tap_script.encode(); - if ctrl_blk.verify_taproot_commitment(&secp, output_key, &tap_script) { + if ctrl_blk.verify_taproot_commitment(output_key, &tap_script) { Ok(( Inner::Script(ms, ScriptType::Tr), wit_stack, @@ -233,7 +238,9 @@ pub(super) fn from_txdata<'txin>( // // In particular, this return value will be put into the `script_code` member of // the `Interpreter` script; the interpreter logic does the right thing with it. - Some(tap_script), + // + // Convert TapScript to ScriptPubKey by going through bytes + Some(ScriptPubKeyBuf::from_bytes(tap_script.into_bytes())), )) } else { Err(Error::ControlBlockVerificationError) @@ -246,8 +253,9 @@ pub(super) fn from_txdata<'txin>( match ssig_stack.pop() { Some(elem) => { if let stack::Element::Push(slice) = elem { - let scripthash = hash160::Hash::hash(slice); - if *spk != bitcoin::ScriptBuf::new_p2sh(&scripthash.into()) { + let hash160 = hash160::Hash::hash(slice); + let scripthash = bitcoin::script::ScriptHash::from_byte_array(hash160.to_byte_array()); + if *spk != ScriptPubKeyBuf::new_p2sh(scripthash) { return Err(Error::IncorrectScriptHash); } // ** p2sh-wrapped wpkh ** @@ -259,14 +267,16 @@ pub(super) fn from_txdata<'txin>( } else { let pk = pk_from_stack_elem(&elem, true)?; let hash160 = pk.to_pubkeyhash(SigType::Ecdsa); + let wpkh = bitcoin::key::WPubkeyHash::from_byte_array(hash160.to_byte_array()); + let pkh = bitcoin::key::PubkeyHash::from_byte_array(hash160.to_byte_array()); if slice - == bitcoin::ScriptBuf::new_p2wpkh(&hash160.into()) + == ScriptPubKeyBuf::new_p2wpkh(wpkh) .as_bytes() { Ok(( Inner::PublicKey(pk.into(), PubkeyType::ShWpkh), wit_stack, - Some(bitcoin::ScriptBuf::new_p2pkh(&hash160.into())), // bip143, why.. + Some(ScriptPubKeyBuf::new_p2pkh(pkh)), // bip143, why.. )) } else { Err(Error::IncorrectWScriptHash) @@ -287,8 +297,9 @@ pub(super) fn from_txdata<'txin>( let script = miniscript.encode(); let miniscript = miniscript.to_no_checks_ms(); let scripthash = sha256::Hash::hash(script.as_bytes()); + let wscript_hash = bitcoin::script::WScriptHash::from_byte_array(scripthash.to_byte_array()); if slice - == bitcoin::ScriptBuf::new_p2wsh(&scripthash.into()) + == ScriptPubKeyBuf::new_p2wsh(wscript_hash) .as_bytes() { Ok(( @@ -310,8 +321,9 @@ pub(super) fn from_txdata<'txin>( let script = miniscript.encode(); let miniscript = miniscript.to_no_checks_ms(); if wit_stack.is_empty() { - let scripthash = hash160::Hash::hash(script.as_bytes()); - if *spk == bitcoin::ScriptBuf::new_p2sh(&scripthash.into()) { + let hash160 = hash160::Hash::hash(script.as_bytes()); + let scripthash = bitcoin::script::ScriptHash::from_byte_array(hash160.to_byte_array()); + if *spk == ScriptPubKeyBuf::new_p2sh(scripthash) { Ok((Inner::Script(miniscript, ScriptType::Sh), ssig_stack, Some(script))) } else { Err(Error::IncorrectScriptHash) @@ -368,25 +380,46 @@ impl ToNoChecks for Miniscript { } } -impl ToNoChecks for Miniscript { +impl ToNoChecks for Miniscript { fn to_no_checks_ms(&self) -> Miniscript { struct TranslateXOnlyPk; - impl Translator for TranslateXOnlyPk { + impl Translator for TranslateXOnlyPk { type TargetPk = BitcoinKey; type Error = core::convert::Infallible; - fn pk(&mut self, pk: &bitcoin::key::XOnlyPublicKey) -> Result { + fn pk(&mut self, pk: &bitcoin::XOnlyPublicKey) -> Result { Ok(BitcoinKey::XOnlyPublicKey(*pk)) } - translate_hash_clone!(bitcoin::key::XOnlyPublicKey); + translate_hash_clone!(bitcoin::XOnlyPublicKey); } self.translate_pk_ctx(&mut TranslateXOnlyPk) .expect("Translation should succeed") } } +// FIXME: Added by Claude, is this correct or should we refactor no that there is a new +// `XOnlyPublicKey` wrapper type in `bitcoin`? +impl ToNoChecks for Miniscript { + fn to_no_checks_ms(&self) -> Miniscript { + struct TranslateSecp256k1XOnlyPk; + + impl Translator for TranslateSecp256k1XOnlyPk { + type TargetPk = BitcoinKey; + type Error = core::convert::Infallible; + + fn pk(&mut self, pk: &bitcoin::secp256k1::XOnlyPublicKey) -> Result { + Ok(BitcoinKey::XOnlyPublicKey(bitcoin::key::XOnlyPublicKey::from(*pk))) + } + + translate_hash_clone!(bitcoin::secp256k1::XOnlyPublicKey); + } + self.translate_pk_ctx(&mut TranslateSecp256k1XOnlyPk) + .expect("Translation should succeed") + } +} + #[cfg(test)] mod tests { @@ -394,23 +427,23 @@ mod tests { use core::str::FromStr; use bitcoin::blockdata::script; - use bitcoin::script::PushBytes; - use bitcoin::ScriptBuf; + use bitcoin::script::{PushBytes, ScriptSigBuf}; + use bitcoin::ScriptPubKeyBuf; use hex; use super::*; struct KeyTestData { - pk_spk: bitcoin::ScriptBuf, - pk_sig: bitcoin::ScriptBuf, - pkh_spk: bitcoin::ScriptBuf, - pkh_sig: bitcoin::ScriptBuf, - pkh_sig_justkey: bitcoin::ScriptBuf, - wpkh_spk: bitcoin::ScriptBuf, + pk_spk: ScriptPubKeyBuf, + pk_sig: ScriptSigBuf, + pkh_spk: ScriptPubKeyBuf, + pkh_sig: ScriptSigBuf, + pkh_sig_justkey: ScriptSigBuf, + wpkh_spk: ScriptPubKeyBuf, wpkh_stack: Witness, wpkh_stack_justkey: Witness, - sh_wpkh_spk: bitcoin::ScriptBuf, - sh_wpkh_sig: bitcoin::ScriptBuf, + sh_wpkh_spk: ScriptPubKeyBuf, + sh_wpkh_sig: ScriptSigBuf, sh_wpkh_stack: Witness, sh_wpkh_stack_justkey: Witness, } @@ -427,24 +460,28 @@ mod tests { .unwrap(); let dummy_sig = <[u8; 48]>::try_from(&dummy_sig_vec[..]).unwrap(); - let pkhash = key.to_pubkeyhash(SigType::Ecdsa).into(); - let wpkhash = key.to_pubkeyhash(SigType::Ecdsa).into(); - let wpkh_spk = bitcoin::ScriptBuf::new_p2wpkh(&wpkhash); - let wpkh_scripthash = hash160::Hash::hash(wpkh_spk.as_bytes()).into(); + let pkhash = bitcoin::key::PubkeyHash::from(key); + + // Create wpkh values using the key's hash, even for uncompressed keys + // (tests need this for proper error detection order) + let key_hash = hash160::Hash::hash(&key.to_bytes()); + let wpkhash = bitcoin::key::WPubkeyHash::from_byte_array(key_hash.to_byte_array()); + let wpkh_spk = ScriptPubKeyBuf::new_p2wpkh(wpkhash); + let wpkh_scripthash = bitcoin::script::ScriptHash::from_byte_array(hash160::Hash::hash(wpkh_spk.as_bytes()).to_byte_array()); KeyTestData { - pk_spk: bitcoin::ScriptBuf::new_p2pk(&key), - pkh_spk: bitcoin::ScriptBuf::new_p2pkh(&pkhash), + pk_spk: ScriptPubKeyBuf::new_p2pk(key), + pkh_spk: ScriptPubKeyBuf::new_p2pkh(pkhash), pk_sig: script::Builder::new().push_slice(dummy_sig).into_script(), pkh_sig: script::Builder::new() .push_slice(dummy_sig) - .push_key(&key) + .push_key(key) .into_script(), - pkh_sig_justkey: script::Builder::new().push_key(&key).into_script(), + pkh_sig_justkey: script::Builder::new().push_key(key).into_script(), wpkh_spk: wpkh_spk.clone(), wpkh_stack: Witness::from_slice(&[dummy_sig_vec.clone(), key.to_bytes()]), wpkh_stack_justkey: Witness::from_slice(&[key.to_bytes()]), - sh_wpkh_spk: bitcoin::ScriptBuf::new_p2sh(&wpkh_scripthash), + sh_wpkh_spk: ScriptPubKeyBuf::new_p2sh(wpkh_scripthash), sh_wpkh_sig: script::Builder::new() .push_slice(<&PushBytes>::try_from(wpkh_spk[..].as_bytes()).unwrap()) .into_script(), @@ -482,7 +519,7 @@ mod tests { let fixed = fixed_test_data(); let comp = KeyTestData::from_key(fixed.pk_comp); let uncomp = KeyTestData::from_key(fixed.pk_uncomp); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptSigBuf::new(); let empty_wit = Witness::default(); // Compressed pk, empty scriptsig @@ -516,15 +553,15 @@ mod tests { // Scriptpubkey has invalid key let mut spk = comp.pk_spk.to_bytes(); spk[1] = 5; - let spk = bitcoin::ScriptBuf::from(spk); - let err = from_txdata(&spk, &bitcoin::ScriptBuf::new(), &empty_wit).unwrap_err(); + let spk = ScriptPubKeyBuf::from(spk); + let err = from_txdata(&spk, &ScriptSigBuf::new(), &empty_wit).unwrap_err(); assert_eq!(err.to_string(), "could not parse pubkey"); // Scriptpubkey has invalid script let mut spk = comp.pk_spk.to_bytes(); spk[0] = 100; - let spk = bitcoin::ScriptBuf::from(spk); - let err = from_txdata(&spk, &bitcoin::ScriptBuf::new(), &empty_wit).unwrap_err(); + let spk = ScriptPubKeyBuf::from(spk); + let err = from_txdata(&spk, &ScriptSigBuf::new(), &empty_wit).unwrap_err(); assert_eq!(&err.to_string()[0..12], "parse error:"); // Witness is nonempty @@ -541,7 +578,7 @@ mod tests { let empty_wit = Witness::default(); // pkh, empty scriptsig; this time it errors out - let err = from_txdata(&comp.pkh_spk, &bitcoin::ScriptBuf::new(), &empty_wit).unwrap_err(); + let err = from_txdata(&comp.pkh_spk, &ScriptSigBuf::new(), &empty_wit).unwrap_err(); assert_eq!(err.to_string(), "unexpected end of stack"); // pkh, wrong pubkey @@ -587,7 +624,7 @@ mod tests { let fixed = fixed_test_data(); let comp = KeyTestData::from_key(fixed.pk_comp); let uncomp = KeyTestData::from_key(fixed.pk_uncomp); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptSigBuf::new(); // wpkh, empty witness; this time it errors out let err = from_txdata(&comp.wpkh_spk, &blank_script, &Witness::default()).unwrap_err(); @@ -615,7 +652,7 @@ mod tests { let (inner, stack, script_code) = from_txdata(&comp.wpkh_spk, &blank_script, &comp.wpkh_stack).expect("parse txdata"); assert_eq!(inner, Inner::PublicKey(fixed.pk_comp.into(), PubkeyType::Wpkh)); - assert_eq!(stack, Stack::from(vec![comp.wpkh_stack.second_to_last().unwrap().into()])); + assert_eq!(stack, Stack::from(vec![(&comp.wpkh_stack.to_vec().iter().rev().nth(1).unwrap().clone()).into()])); assert_eq!(script_code, Some(comp.pkh_spk)); // Scriptsig is nonempty @@ -628,7 +665,7 @@ mod tests { let fixed = fixed_test_data(); let comp = KeyTestData::from_key(fixed.pk_comp); let uncomp = KeyTestData::from_key(fixed.pk_uncomp); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptSigBuf::new(); // sh_wpkh, missing witness or scriptsig let err = from_txdata(&comp.sh_wpkh_spk, &blank_script, &Witness::default()).unwrap_err(); @@ -669,11 +706,11 @@ mod tests { from_txdata(&comp.sh_wpkh_spk, &comp.sh_wpkh_sig, &comp.sh_wpkh_stack) .expect("parse txdata"); assert_eq!(inner, Inner::PublicKey(fixed.pk_comp.into(), PubkeyType::ShWpkh)); - assert_eq!(stack, Stack::from(vec![comp.sh_wpkh_stack.second_to_last().unwrap().into()])); + assert_eq!(stack, Stack::from(vec![(&comp.sh_wpkh_stack.to_vec().iter().rev().nth(1).unwrap().clone()).into()])); assert_eq!(script_code, Some(comp.pkh_spk.clone())); } - fn ms_inner_script(ms: &str) -> (Miniscript, bitcoin::ScriptBuf) { + fn ms_inner_script(ms: &str) -> (Miniscript, ScriptPubKeyBuf) { let ms = Miniscript::::from_str_insane(ms).unwrap(); let spk = ms.encode(); let miniscript = ms.to_no_checks_ms(); @@ -684,7 +721,8 @@ mod tests { fn script_bare() { let preimage = b"12345678----____12345678----____"; let hash = hash160::Hash::hash(&preimage[..]); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptSigBuf::new(); + let blank_spk = ScriptPubKeyBuf::new(); let empty_wit = Witness::default(); let (miniscript, spk) = ms_inner_script(&format!("hash160({})", hash)); @@ -695,7 +733,7 @@ mod tests { assert_eq!(stack, Stack::from(vec![])); assert_eq!(script_code, Some(spk.clone())); - let err = from_txdata(&blank_script, &blank_script, &empty_wit).unwrap_err(); + let err = from_txdata(&blank_spk, &blank_script, &empty_wit).unwrap_err(); assert_eq!(&err.to_string()[0..12], "parse error:"); // nonempty witness @@ -710,22 +748,23 @@ mod tests { let hash = hash160::Hash::hash(&preimage[..]); let (miniscript, redeem_script) = ms_inner_script(&format!("hash160({})", hash)); - let rs_hash = hash160::Hash::hash(redeem_script.as_bytes()).into(); + let rs_hash = bitcoin::script::ScriptHash::from_byte_array(hash160::Hash::hash(redeem_script.as_bytes()).to_byte_array()); - let spk = ScriptBuf::new_p2sh(&rs_hash); + let spk = ScriptPubKeyBuf::new_p2sh(rs_hash); let script_sig = script::Builder::new() .push_slice(<&PushBytes>::try_from(redeem_script.as_bytes()).unwrap()) .into_script(); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptSigBuf::new(); + let incorrect_script = ScriptSigBuf::from(vec![bitcoin::opcodes::all::OP_PUSHNUM_1.to_u8()]); let empty_wit = Witness::default(); // sh without scriptsig let err = from_txdata(&spk, &blank_script, &Witness::default()).unwrap_err(); assert_eq!(&err.to_string(), "unexpected end of stack"); - // with incorrect scriptsig - let err = from_txdata(&spk, &spk, &Witness::default()).unwrap_err(); - assert_eq!(&err.to_string(), "expected push in script"); + // with incorrect scriptsig (OP_PUSHNUM_1 is treated as Miniscript::TRUE) + let err = from_txdata(&spk, &incorrect_script, &Witness::default()).unwrap_err(); + assert_eq!(&err.to_string(), "redeem script did not match scriptpubkey"); // with correct scriptsig let (inner, stack, script_code) = @@ -745,11 +784,11 @@ mod tests { let preimage = b"12345678----____12345678----____"; let hash = hash160::Hash::hash(&preimage[..]); let (miniscript, witness_script) = ms_inner_script(&format!("hash160({})", hash)); - let wit_hash = sha256::Hash::hash(witness_script.as_bytes()).into(); + let wit_hash = bitcoin::script::WScriptHash::from_byte_array(sha256::Hash::hash(witness_script.as_bytes()).to_byte_array()); let wit_stack = Witness::from_slice(&[witness_script.to_bytes()]); - let spk = ScriptBuf::new_p2wsh(&wit_hash); - let blank_script = bitcoin::ScriptBuf::new(); + let spk = ScriptPubKeyBuf::new_p2wsh(wit_hash); + let blank_script = ScriptSigBuf::new(); // wsh without witness let err = from_txdata(&spk, &blank_script, &Witness::default()).unwrap_err(); @@ -780,17 +819,17 @@ mod tests { let preimage = b"12345678----____12345678----____"; let hash = hash160::Hash::hash(&preimage[..]); let (miniscript, witness_script) = ms_inner_script(&format!("hash160({})", hash)); - let wit_hash = sha256::Hash::hash(witness_script.as_bytes()).into(); + let wit_hash = bitcoin::script::WScriptHash::from_byte_array(sha256::Hash::hash(witness_script.as_bytes()).to_byte_array()); let wit_stack = Witness::from_slice(&[witness_script.to_bytes()]); - let redeem_script = ScriptBuf::new_p2wsh(&wit_hash); + let redeem_script = ScriptPubKeyBuf::new_p2wsh(wit_hash); let script_sig = script::Builder::new() .push_slice(<&PushBytes>::try_from(redeem_script.as_bytes()).unwrap()) .into_script(); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptSigBuf::new(); - let rs_hash = hash160::Hash::hash(redeem_script.as_bytes()).into(); - let spk = ScriptBuf::new_p2sh(&rs_hash); + let rs_hash = bitcoin::script::ScriptHash::from_byte_array(hash160::Hash::hash(redeem_script.as_bytes()).to_byte_array()); + let spk = ScriptPubKeyBuf::new_p2sh(rs_hash); // shwsh without witness or scriptsig let err = from_txdata(&spk, &blank_script, &Witness::default()).unwrap_err(); @@ -806,7 +845,8 @@ mod tests { assert_eq!(&err.to_string()[0..12], "parse error:"); // with incorrect scriptsig - let err = from_txdata(&spk, &redeem_script, &wit_stack).unwrap_err(); + let incorrect_sig = ScriptSigBuf::from(redeem_script.to_bytes()); + let err = from_txdata(&spk, &incorrect_sig, &wit_stack).unwrap_err(); assert_eq!(&err.to_string(), "redeem script did not match scriptpubkey"); // with correct witness diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 77ad18136..56510042b 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -11,7 +11,8 @@ use core::fmt; use core::str::FromStr; -use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256}; +use bitcoin::script::{ScriptPubKeyBuf, ScriptSig}; use bitcoin::{absolute, relative, secp256k1, sighash, taproot, Sequence, TxOut, Witness}; use crate::miniscript::context::{NoChecks, SigType}; @@ -34,7 +35,7 @@ pub struct Interpreter<'txin> { stack: Stack<'txin>, /// For non-Taproot spends, the scriptCode; for Taproot script-spends, this /// is the leaf script; for key-spends it is `None`. - script_code: Option, + script_code: Option, sequence: Sequence, lock_time: absolute::LockTime, } @@ -48,7 +49,7 @@ pub enum KeySigPair { /// A Full public key and corresponding Ecdsa signature Ecdsa(bitcoin::PublicKey, bitcoin::ecdsa::Signature), /// A x-only key and corresponding Schnorr signature - Schnorr(bitcoin::key::XOnlyPublicKey, bitcoin::taproot::Signature), + Schnorr(bitcoin::XOnlyPublicKey, bitcoin::taproot::Signature), } impl KeySigPair { @@ -60,10 +61,10 @@ impl KeySigPair { } } - /// Obtain a pair of ([`bitcoin::secp256k1::XOnlyPublicKey`], [`bitcoin::taproot::Signature`]) from [`KeySigPair`] + /// Obtain a pair of ([`bitcoin::XOnlyPublicKey`], [`bitcoin::taproot::Signature`]) from [`KeySigPair`] pub fn as_schnorr( &self, - ) -> Option<(bitcoin::key::XOnlyPublicKey, bitcoin::taproot::Signature)> { + ) -> Option<(bitcoin::XOnlyPublicKey, bitcoin::taproot::Signature)> { match self { KeySigPair::Ecdsa(_, _) => None, KeySigPair::Schnorr(pk, sig) => Some((*pk, *sig)), @@ -88,7 +89,7 @@ enum BitcoinKey { // Full key Fullkey(bitcoin::PublicKey), // Xonly key - XOnlyPublicKey(bitcoin::key::XOnlyPublicKey), + XOnlyPublicKey(bitcoin::XOnlyPublicKey), } impl BitcoinKey { @@ -114,8 +115,8 @@ impl From for BitcoinKey { fn from(pk: bitcoin::PublicKey) -> Self { BitcoinKey::Fullkey(pk) } } -impl From for BitcoinKey { - fn from(xpk: bitcoin::key::XOnlyPublicKey) -> Self { BitcoinKey::XOnlyPublicKey(xpk) } +impl From for BitcoinKey { + fn from(xpk: bitcoin::XOnlyPublicKey) -> Self { BitcoinKey::XOnlyPublicKey(xpk) } } impl MiniscriptKey for BitcoinKey { @@ -140,8 +141,8 @@ impl<'txin> Interpreter<'txin> { /// function; otherwise, it should be a closure containing a sighash and /// secp context, which can actually verify a given signature. pub fn from_txdata( - spk: &bitcoin::ScriptBuf, - script_sig: &'txin bitcoin::Script, + spk: &ScriptPubKeyBuf, + script_sig: &'txin ScriptSig, witness: &'txin Witness, sequence: Sequence, // CSV, relative lock time. lock_time: absolute::LockTime, // CLTV, absolute lock time. @@ -190,9 +191,8 @@ impl<'txin> Interpreter<'txin> { // TODO: Create a good first issue to change this to error // TODO: Requires refactor to remove the script_code logic in order to use the new sighash API. #[allow(deprecated)] // For segwit_signature_hash - pub fn verify_sig>( + pub fn verify_sig>( &self, - secp: &secp256k1::Secp256k1, tx: &bitcoin::Transaction, input_idx: usize, prevouts: &sighash::Prevouts, @@ -224,13 +224,14 @@ impl<'txin> Interpreter<'txin> { sighash.map(|hash| secp256k1::Message::from_digest(hash.to_byte_array())) } else if self.is_segwit_v0() { let amt = match get_prevout(prevouts, input_idx) { - Some(txout) => txout.borrow().value, + Some(txout) => txout.borrow().amount, None => return false, }; // TODO: Don't manually handle the script code. + let witness_script = bitcoin::script::WitnessScript::from_bytes(script_pubkey.as_bytes()); let sighash = cache.p2wsh_signature_hash( input_idx, - script_pubkey, + witness_script, amt, ecdsa_sig.sighash_type, ); @@ -241,7 +242,7 @@ impl<'txin> Interpreter<'txin> { }; let success = msg.map(|msg| { - secp.verify_ecdsa(&msg, &ecdsa_sig.signature, &key.inner) + secp256k1::ecdsa::verify(&ecdsa_sig.signature, msg, &key.inner) .is_ok() }); success.unwrap_or(false) // unwrap_or checks for errors, while success would have checksig results @@ -254,10 +255,11 @@ impl<'txin> Interpreter<'txin> { schnorr_sig.sighash_type, ) } else if self.is_taproot_v1_script_spend() { - let tap_script = self.script_code.as_ref().expect( + let tap_script_pubkey = self.script_code.as_ref().expect( "Internal Hack: Saving leaf script instead\ of script code for script spend", ); + let tap_script = bitcoin::script::TapScript::from_bytes(tap_script_pubkey.as_bytes()); let leaf_hash = taproot::TapLeafHash::from_script( tap_script, taproot::LeafVersion::TapScript, @@ -275,7 +277,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.signature, &msg, xpk) + secp256k1::schnorr::verify(&schnorr_sig.signature, msg.as_ref(), &xpk.into_inner()) .is_ok() }); success.unwrap_or(false) // unwrap_or_default checks for errors, while success would have checksig results @@ -300,14 +302,13 @@ impl<'txin> Interpreter<'txin> { /// - For legacy outputs, no information about prevouts is required /// - For segwitv0 outputs, prevout at corresponding index with correct amount must be provided /// - For taproot outputs, information about all prevouts must be supplied - pub fn iter<'iter, C: secp256k1::Verification, T: Borrow>( + pub fn iter<'iter, T: Borrow>( &'iter self, - secp: &'iter secp256k1::Secp256k1, tx: &'txin bitcoin::Transaction, input_idx: usize, prevouts: &'iter sighash::Prevouts, // actually a 'prevouts, but 'prevouts: 'iter ) -> Iter<'txin, 'iter> { - self.iter_custom(Box::new(move |sig| self.verify_sig(secp, tx, input_idx, prevouts, sig))) + self.iter_custom(Box::new(move |sig| self.verify_sig(tx, input_idx, prevouts, sig))) } /// Creates an iterator over the satisfied spending conditions without checking signatures @@ -1051,8 +1052,6 @@ fn verify_sersig<'txin>( #[cfg(test)] mod tests { - use bitcoin::secp256k1::Secp256k1; - use super::inner::ToNoChecks; use super::*; use crate::miniscript::analyzable::ExtParams; @@ -1065,12 +1064,10 @@ mod tests { Vec>, Vec, secp256k1::Message, - Secp256k1, - Vec, + Vec, Vec, Vec>, ) { - let secp = secp256k1::Secp256k1::new(); let msg = secp256k1::Message::from_digest(*b"Yoda: btc, I trust. HODL I must!"); let mut pks = vec![]; let mut ecdsa_sigs = vec![]; @@ -1085,12 +1082,12 @@ mod tests { sk[1] = (i >> 8) as u8; sk[2] = (i >> 16) as u8; - let sk = secp256k1::SecretKey::from_slice(&sk[..]).expect("secret key"); + let sk = secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"); let pk = bitcoin::PublicKey { - inner: secp256k1::PublicKey::from_secret_key(&secp, &sk), + inner: secp256k1::PublicKey::from_secret_key(&sk), compressed: true, }; - let signature = secp.sign_ecdsa(&msg, &sk); + let signature = secp256k1::ecdsa::sign(msg, &sk); ecdsa_sigs.push(bitcoin::ecdsa::Signature { signature, sighash_type: bitcoin::sighash::EcdsaSighashType::All, @@ -1100,10 +1097,10 @@ mod tests { pks.push(pk); der_sigs.push(sigser); - let keypair = bitcoin::key::Keypair::from_secret_key(&secp, &sk); - let (x_only_pk, _parity) = bitcoin::key::XOnlyPublicKey::from_keypair(&keypair); + let keypair = bitcoin::key::Keypair::from_secret_key(&sk); + let (x_only_pk, _parity) = bitcoin::XOnlyPublicKey::from_keypair(&keypair); x_only_pks.push(x_only_pk); - let schnorr_sig = secp.sign_schnorr_with_aux_rand(&msg, &keypair, &[0u8; 32]); + let schnorr_sig = secp256k1::schnorr::sign_with_aux_rand(b"Yoda: btc, I trust. HODL I must!", &keypair, &[0u8; 32]); let schnorr_sig = bitcoin::taproot::Signature { signature: schnorr_sig, sighash_type: bitcoin::sighash::TapSighashType::Default, @@ -1111,20 +1108,19 @@ mod tests { ser_schnorr_sigs.push(schnorr_sig.to_vec()); schnorr_sigs.push(schnorr_sig); } - (pks, der_sigs, ecdsa_sigs, msg, secp, x_only_pks, schnorr_sigs, ser_schnorr_sigs) + (pks, der_sigs, ecdsa_sigs, msg, x_only_pks, schnorr_sigs, ser_schnorr_sigs) } #[test] fn sat_constraints() { - let (pks, der_sigs, ecdsa_sigs, sighash, secp, xpks, schnorr_sigs, ser_schnorr_sigs) = + let (pks, der_sigs, ecdsa_sigs, sighash, xpks, schnorr_sigs, ser_schnorr_sigs) = setup_keys_sigs(10); - let secp_ref = &secp; let vfyfn = |pksig: &KeySigPair| match pksig { - KeySigPair::Ecdsa(pk, ecdsa_sig) => secp_ref - .verify_ecdsa(&sighash, &ecdsa_sig.signature, &pk.inner) + KeySigPair::Ecdsa(pk, ecdsa_sig) => + secp256k1::ecdsa::verify(&ecdsa_sig.signature, sighash, &pk.inner) .is_ok(), - KeySigPair::Schnorr(xpk, schnorr_sig) => secp_ref - .verify_schnorr(&schnorr_sig.signature, &sighash, xpk) + KeySigPair::Schnorr(xpk, schnorr_sig) => + secp256k1::schnorr::verify(&schnorr_sig.signature, sighash.as_ref(), &xpk.into_inner()) .is_ok(), }; @@ -1564,7 +1560,7 @@ mod tests { } fn x_only_no_checks_ms(ms: &str) -> Miniscript { - let elem: Miniscript = + let elem: Miniscript = Miniscript::from_str_ext(ms, &ExtParams::allow_all()).unwrap(); elem.to_no_checks_ms() } diff --git a/src/interpreter/stack.rs b/src/interpreter/stack.rs index 647a84713..77ce4a8b3 100644 --- a/src/interpreter/stack.rs +++ b/src/interpreter/stack.rs @@ -4,7 +4,7 @@ //! Interpreter stack use bitcoin::blockdata::{opcodes, script}; -use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256}; use bitcoin::{absolute, relative, Sequence}; use super::error::PkEvalErrInner; @@ -152,7 +152,10 @@ impl<'txin> Stack<'txin> { // We don't really store information about which key error. fn bitcoin_key_from_slice(sl: &[u8], sig_type: SigType) -> Option { let key: BitcoinKey = match sig_type { - SigType::Schnorr => bitcoin::key::XOnlyPublicKey::from_slice(sl).ok()?.into(), + SigType::Schnorr => { + let k = <[u8; 32]>::try_from(sl).ok()?; + bitcoin::XOnlyPublicKey::from_byte_array(&k).ok()?.into() + } SigType::Ecdsa => bitcoin::PublicKey::from_slice(sl).ok()?.into(), }; Some(key) diff --git a/src/lib.rs b/src/lib.rs index eac67c5d1..ff06cd745 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -130,7 +130,7 @@ mod util; use core::{fmt, hash, str}; -use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256}; pub use crate::blanket_traits::FromStrKey; pub use crate::descriptor::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey}; @@ -204,6 +204,17 @@ impl MiniscriptKey for bitcoin::secp256k1::XOnlyPublicKey { fn is_x_only_key(&self) -> bool { true } } +// FIXME: Do we want to do this for both the `bitcoin::XOnlyPublicKey` and the sepc +// one or should we refactor to only ever use one of them? +impl MiniscriptKey for bitcoin::XOnlyPublicKey { + type Sha256 = sha256::Hash; + type Hash256 = hash256::Hash; + type Ripemd160 = ripemd160::Hash; + type Hash160 = hash160::Hash; + + fn is_x_only_key(&self) -> bool { true } +} + impl MiniscriptKey for String { type Sha256 = String; // specify hashes as string type Hash256 = String; @@ -217,9 +228,9 @@ pub trait ToPublicKey: MiniscriptKey { fn to_public_key(&self) -> bitcoin::PublicKey; /// Convert an object to x-only pubkey - fn to_x_only_pubkey(&self) -> bitcoin::secp256k1::XOnlyPublicKey { + fn to_x_only_pubkey(&self) -> bitcoin::XOnlyPublicKey { let pk = self.to_public_key(); - bitcoin::secp256k1::XOnlyPublicKey::from(pk.inner) + bitcoin::XOnlyPublicKey::from(pk.inner) } /// Obtain the public key hash for this MiniscriptKey @@ -280,7 +291,28 @@ impl ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey { .expect("Failed to construct 33 Publickey from 0x02 appended x-only key") } - fn to_x_only_pubkey(&self) -> bitcoin::secp256k1::XOnlyPublicKey { *self } + fn to_x_only_pubkey(&self) -> bitcoin::XOnlyPublicKey { bitcoin::XOnlyPublicKey::new(*self) } + + fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash } + + fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { *hash } + + fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash { *hash } + + fn to_hash160(hash: &hash160::Hash) -> hash160::Hash { *hash } +} + +impl ToPublicKey for bitcoin::XOnlyPublicKey { + fn to_public_key(&self) -> bitcoin::PublicKey { + // This code should never be used. + // But is implemented for completeness + let mut data: Vec = vec![0x02]; + data.extend(self.serialize().iter()); + bitcoin::PublicKey::from_slice(&data) + .expect("Failed to construct 33 Publickey from 0x02 appended x-only key") + } + + fn to_x_only_pubkey(&self) -> bitcoin::XOnlyPublicKey { *self } fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash } @@ -438,8 +470,6 @@ pub enum Error { ScriptLexer(crate::miniscript::lex::Error), /// rust-bitcoin address error AddrError(bitcoin::address::ParseError), - /// rust-bitcoin p2sh address error - AddrP2shError(bitcoin::address::P2shError), /// While parsing backward, hit beginning of script UnexpectedStart, /// Got something we were not expecting @@ -512,7 +542,6 @@ impl fmt::Display for Error { match *self { Error::ScriptLexer(ref e) => e.fmt(f), Error::AddrError(ref e) => fmt::Display::fmt(e, f), - Error::AddrP2shError(ref e) => fmt::Display::fmt(e, f), Error::UnexpectedStart => f.write_str("unexpected start of script"), Error::Unexpected(ref s) => write!(f, "unexpected «{}»", s), Error::UnknownWrapper(ch) => write!(f, "unknown wrapper «{}:»", ch), @@ -578,7 +607,6 @@ impl std::error::Error for Error { | MultipathDescLenMismatch => None, ScriptLexer(e) => Some(e), AddrError(e) => Some(e), - AddrP2shError(e) => Some(e), Secp(e) => Some(e), #[cfg(feature = "compiler")] CompilerError(e) => Some(e), @@ -637,11 +665,6 @@ 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)] #[cfg(feature = "compiler")] impl From for Error { @@ -679,7 +702,10 @@ fn push_opcode_size(script_size: usize) -> usize { /// Helper function used by tests #[cfg(test)] -fn hex_script(s: &str) -> bitcoin::ScriptBuf { bitcoin::ScriptBuf::from_hex(s).unwrap() } +fn hex_script(s: &str) -> bitcoin::script::ScriptPubKeyBuf { + use bitcoin::hex::FromHex; + bitcoin::script::ScriptPubKeyBuf::from(Vec::::from_hex(s).unwrap()) +} #[cfg(test)] mod tests { @@ -718,7 +744,7 @@ mod tests { #[test] fn regression_xonly_key_hash() { - use bitcoin::secp256k1::XOnlyPublicKey; + use bitcoin::XOnlyPublicKey; let pk = XOnlyPublicKey::from_str( "cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115", diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index 19611b083..d6a5fc28a 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -7,7 +7,6 @@ //! encoding in Bitcoin script, as well as a datatype. Full details //! are given on the Miniscript website. -use bitcoin::hashes::Hash; use bitcoin::{absolute, opcodes, script}; use crate::miniscript::context::SigType; @@ -22,7 +21,7 @@ trait PushAstElem { Pk: ToPublicKey; } -impl PushAstElem for script::Builder { +impl PushAstElem for script::Builder { fn push_astelem(self, ast: &Miniscript) -> Self where Pk: ToPublicKey, @@ -35,10 +34,12 @@ impl Terminal { /// Encode the element as a fragment of Bitcoin Script. The inverse /// function, from Script to an AST element, is implemented in the /// `parse` module. - pub fn encode(&self, mut builder: script::Builder) -> script::Builder + pub fn encode(&self, mut builder: script::Builder) -> script::Builder where Pk: ToPublicKey, { + // FIXME: Changes done here are semantically correct but all a bit ugly. + // See https://github.com/rust-bitcoin/rust-bitcoin/issues/5262 match *self { Terminal::PkK(ref pk) => builder.push_ms_key::<_, Ctx>(pk), Terminal::PkH(ref pk) => builder @@ -52,41 +53,41 @@ impl Terminal { .push_slice(hash.to_byte_array()) .push_opcode(opcodes::all::OP_EQUALVERIFY), Terminal::After(t) => builder - .push_int(absolute::LockTime::from(t).to_consensus_u32() as i64) + .push_int_unchecked(absolute::LockTime::from(t).to_consensus_u32() as i64) .push_opcode(opcodes::all::OP_CLTV), Terminal::Older(t) => builder - .push_int(t.to_consensus_u32().into()) + .push_int_unchecked(t.to_consensus_u32().into()) .push_opcode(opcodes::all::OP_CSV), Terminal::Sha256(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) - .push_int(32) + .push_int(32).expect("32 is valid i32") .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_SHA256) .push_slice(Pk::to_sha256(h).to_byte_array()) .push_opcode(opcodes::all::OP_EQUAL), Terminal::Hash256(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) - .push_int(32) + .push_int(32).expect("32 is valid i32") .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_HASH256) .push_slice(Pk::to_hash256(h).to_byte_array()) .push_opcode(opcodes::all::OP_EQUAL), Terminal::Ripemd160(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) - .push_int(32) + .push_int(32).expect("32 is valid i32") .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_RIPEMD160) .push_slice(Pk::to_ripemd160(h).to_byte_array()) .push_opcode(opcodes::all::OP_EQUAL), Terminal::Hash160(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) - .push_int(32) + .push_int(32).expect("32 is valid i32") .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_HASH160) .push_slice(Pk::to_hash160(h).to_byte_array()) .push_opcode(opcodes::all::OP_EQUAL), - Terminal::True => builder.push_opcode(opcodes::OP_TRUE), - Terminal::False => builder.push_opcode(opcodes::OP_FALSE), + Terminal::True => builder.push_opcode(opcodes::all::OP_TRUE), + Terminal::False => builder.push_opcode(opcodes::all::OP_FALSE), Terminal::Alt(ref sub) => builder .push_opcode(opcodes::all::OP_TOALTSTACK) .push_astelem(sub) @@ -149,17 +150,17 @@ impl Terminal { builder = builder.push_astelem(sub).push_opcode(opcodes::all::OP_ADD); } builder - .push_int(thresh.k() as i64) + .push_int_unchecked(thresh.k() as i64) .push_opcode(opcodes::all::OP_EQUAL) } Terminal::Multi(ref thresh) => { debug_assert!(Ctx::sig_type() == SigType::Ecdsa); - builder = builder.push_int(thresh.k() as i64); + builder = builder.push_int_unchecked(thresh.k() as i64); for pk in thresh.data() { - builder = builder.push_key(&pk.to_public_key()); + builder = builder.push_key(pk.to_public_key()); } builder - .push_int(thresh.n() as i64) + .push_int_unchecked(thresh.n() as i64) .push_opcode(opcodes::all::OP_CHECKMULTISIG) } Terminal::MultiA(ref thresh) => { @@ -172,7 +173,7 @@ impl Terminal { builder = builder.push_opcode(opcodes::all::OP_CHECKSIGADD); } builder - .push_int(thresh.k() as i64) + .push_int_unchecked(thresh.k() as i64) .push_opcode(opcodes::all::OP_NUMEQUAL) } } diff --git a/src/miniscript/context.rs b/src/miniscript/context.rs index 4fe76a989..2573928e7 100644 --- a/src/miniscript/context.rs +++ b/src/miniscript/context.rs @@ -575,7 +575,7 @@ impl ScriptContext for Segwitv0 { pub enum Tap {} impl ScriptContext for Tap { - type Key = bitcoin::secp256k1::XOnlyPublicKey; + type Key = bitcoin::XOnlyPublicKey; fn check_terminal_non_malleable( _frag: &Terminal, ) -> Result<(), ScriptContextError> { diff --git a/src/miniscript/decode.rs b/src/miniscript/decode.rs index 213ac8266..178917392 100644 --- a/src/miniscript/decode.rs +++ b/src/miniscript/decode.rs @@ -9,7 +9,7 @@ use core::{fmt, mem}; #[cfg(feature = "std")] use std::error; -use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256}; use sync::Arc; use crate::iter::TreeLike; @@ -36,9 +36,10 @@ impl ParseableKey for bitcoin::PublicKey { } } -impl ParseableKey for bitcoin::secp256k1::XOnlyPublicKey { +impl ParseableKey for bitcoin::XOnlyPublicKey { fn from_slice(sl: &[u8]) -> Result { - bitcoin::secp256k1::XOnlyPublicKey::from_slice(sl).map_err(KeyError::XOnly) + let k = <[u8; 32]>::try_from(sl).map_err(KeyError::XOnlyTooShort)?; + bitcoin::XOnlyPublicKey::from_byte_array(&k).map_err(KeyError::XOnly) } } @@ -49,7 +50,7 @@ mod private { // Implement for those same types, but no others. impl Sealed for bitcoin::PublicKey {} - impl Sealed for bitcoin::secp256k1::XOnlyPublicKey {} + impl Sealed for bitcoin::XOnlyPublicKey {} } #[derive(Copy, Clone, Debug)] @@ -700,18 +701,22 @@ fn is_and_v(tokens: &mut TokenIter) -> bool { } /// Decoding error while parsing keys -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub enum KeyError { /// Bitcoin PublicKey parse error Full(bitcoin::key::FromSliceError), + /// + /// Xonly key material to short. + XOnlyTooShort(core::array::TryFromSliceError), /// Xonly key parse Error - XOnly(bitcoin::secp256k1::Error), + XOnly(bitcoin::key::ParseXOnlyPublicKeyError), } impl fmt::Display for KeyError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Full(e) => e.fmt(f), + Self::XOnlyTooShort(e) => e.fmt(f), Self::XOnly(e) => e.fmt(f), } } @@ -722,6 +727,7 @@ impl error::Error for KeyError { fn cause(&self) -> Option<&(dyn error::Error + 'static)> { match self { Self::Full(e) => Some(e), + Self::XOnlyTooShort(e) => Some(e), Self::XOnly(e) => Some(e), } } diff --git a/src/miniscript/iter.rs b/src/miniscript/iter.rs index 0ac48e651..d87fc0ed1 100644 --- a/src/miniscript/iter.rs +++ b/src/miniscript/iter.rs @@ -203,7 +203,7 @@ impl Iterator for PkIter<'_, Pk, Ctx> { /// dependent libraries for their own tasts based on Miniscript AST #[cfg(test)] pub mod test { - use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; + use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d}; use super::Miniscript; use crate::miniscript::context::Segwitv0; @@ -219,7 +219,6 @@ pub mod test { /// Generate a deterministic list of public keys of the given length. pub fn gen_secp_pubkeys(n: usize) -> Vec { let mut ret = Vec::with_capacity(n); - let secp = secp256k1::Secp256k1::new(); let mut sk = [0; 32]; for i in 1..n + 1 { @@ -228,8 +227,7 @@ pub mod test { sk[2] = (i >> 16) as u8; ret.push(secp256k1::PublicKey::from_secret_key( - &secp, - &secp256k1::SecretKey::from_slice(&sk[..]).unwrap(), + &secp256k1::SecretKey::from_secret_bytes(sk).unwrap(), )); } ret diff --git a/src/miniscript/lex.rs b/src/miniscript/lex.rs index 1df1f2dd4..855461fa7 100644 --- a/src/miniscript/lex.rs +++ b/src/miniscript/lex.rs @@ -8,6 +8,7 @@ use core::fmt; use bitcoin::blockdata::{opcodes, script}; +use bitcoin::blockdata::script::ScriptExt as _; use bitcoin::hex::DisplayHex as _; use crate::prelude::*; @@ -93,7 +94,7 @@ impl Iterator for TokenIter { } /// Tokenize a script -pub fn lex(script: &'_ script::Script) -> Result, Error> { +pub fn lex(script: &'_ script::Script) -> Result, Error> { let mut ret = Vec::with_capacity(script.len()); for ins in script.instructions_minimal() { @@ -215,7 +216,7 @@ pub fn lex(script: &'_ script::Script) -> Result, Error> { ret.push(Token::Bytes65(bytes)); } else { // check minimality of the number - match script::read_scriptint(bytes.as_bytes()) { + match bytes.read_scriptint() { Ok(v) if v >= 0 => { ret.push(Token::Num(v as u32)); } diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index fea98b5bb..6c8f0835e 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -338,7 +338,7 @@ impl Miniscript { pub fn as_inner(&self) -> &Terminal { &self.node } /// Encode as a Bitcoin script - pub fn encode(&self) -> script::ScriptBuf + pub fn encode(&self) -> script::ScriptBuf where Pk: ToPublicKey, { @@ -525,13 +525,13 @@ impl Miniscript { /// It may make sense to use this method when parsing Script that is already /// embedded in the chain. While it is inadvisable to use insane Miniscripts, /// once it's on the chain you don't have much choice anymore. - pub fn decode_consensus(script: &script::Script) -> Result, Error> { + pub fn decode_consensus(script: &script::Script) -> Result, Error> { Miniscript::decode_with_ext(script, &ExtParams::allow_all()) } /// Attempt to decode a Miniscript from Script, specifying which validation parameters to apply. - pub fn decode_with_ext( - script: &script::Script, + pub fn decode_with_ext( + script: &script::Script, ext: &ExtParams, ) -> Result, Error> { let tokens = lex(script)?; @@ -561,29 +561,34 @@ impl Miniscript { /// /// ```rust /// use miniscript::{Miniscript, Segwitv0, Tap}; - /// use miniscript::bitcoin::secp256k1::XOnlyPublicKey; + /// use miniscript::bitcoin::XOnlyPublicKey; + /// use bitcoin::script::{TapScriptBuf, WitnessScriptBuf}; + /// use bitcoin::hex::FromHex; /// /// type Segwitv0Script = Miniscript; /// type TapScript = Miniscript; /// /// // parse x-only miniscript in Taproot context - /// let tapscript_ms = TapScript::decode(&bitcoin::ScriptBuf::from_hex( - /// "202788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac", - /// ).expect("Even length hex")) + /// let tapscript_ms = TapScript::decode(&TapScriptBuf::from( + /// Vec::::from_hex("202788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac") + /// .expect("Even length hex") + /// )) /// .expect("Xonly keys are valid only in taproot context"); /// // tapscript fails decoding when we use them with compressed keys - /// let err = TapScript::decode(&bitcoin::ScriptBuf::from_hex( - /// "21022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac", - /// ).expect("Even length hex")) + /// let err = TapScript::decode(&TapScriptBuf::from( + /// Vec::::from_hex("21022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac") + /// .expect("Even length hex") + /// )) /// .expect_err("Compressed keys cannot be used in Taproot context"); /// // Segwitv0 succeeds decoding with full keys. - /// Segwitv0Script::decode(&bitcoin::ScriptBuf::from_hex( - /// "21022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac", - /// ).expect("Even length hex")) + /// Segwitv0Script::decode(&WitnessScriptBuf::from( + /// Vec::::from_hex("21022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac") + /// .expect("Even length hex") + /// )) /// .expect("Compressed keys are allowed in Segwit context"); /// /// ``` - pub fn decode(script: &script::Script) -> Result, Error> { + pub fn decode(script: &script::Script) -> Result, Error> { let ms = Self::decode_with_ext(script, &ExtParams::sane())?; Ok(ms) } @@ -1040,6 +1045,7 @@ serde_string_impl_pk!(Miniscript, "a miniscript", Ctx; ScriptContext); /// Provides a Double SHA256 `Hash` type that displays forwards. pub mod hash256 { + use core::fmt; use bitcoin::hashes::{hash_newtype, sha256d}; hash_newtype! { @@ -1047,6 +1053,33 @@ pub mod hash256 { #[hash_newtype(forward)] pub struct Hash(sha256d::Hash); } + + impl Hash { + /// Hashes the given data to produce a hash256. + pub fn hash(data: &[u8]) -> Self { + Hash(sha256d::Hash::hash(data)) + } + } + + impl fmt::Debug for Hash { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + + impl fmt::Display for Hash { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } + } + + impl core::str::FromStr for Hash { + type Err = bitcoin::hashes::hex::HexToArrayError; + + fn from_str(s: &str) -> Result { + Ok(Hash(sha256d::Hash::from_str(s)?)) + } + } } #[cfg(test)] @@ -1055,8 +1088,8 @@ mod tests { use core::str; use core::str::FromStr; - use bitcoin::hashes::{hash160, sha256, Hash}; - use bitcoin::secp256k1::XOnlyPublicKey; + use bitcoin::hashes::{hash160, sha256}; + use bitcoin::script; use bitcoin::taproot::TapLeafHash; use sync::Arc; @@ -1070,11 +1103,10 @@ mod tests { }; type Segwitv0Script = Miniscript; - type Tapscript = Miniscript; + type Tapscript = Miniscript; fn pubkeys(n: usize) -> Vec { let mut ret = Vec::with_capacity(n); - let secp = secp256k1::Secp256k1::new(); let mut sk = [0; 32]; for i in 1..n + 1 { sk[0] = i as u8; @@ -1083,8 +1115,7 @@ mod tests { let pk = bitcoin::PublicKey { inner: secp256k1::PublicKey::from_secret_key( - &secp, - &secp256k1::SecretKey::from_slice(&sk[..]).expect("secret key"), + &secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"), ), compressed: true, }; @@ -1148,7 +1179,7 @@ mod tests { fn script_rtt>>(script: Segwitv0Script, expected_hex: Str1) { assert_eq!(script.ty.corr.base, types::Base::B); - let bitcoin_script = script.encode(); + let bitcoin_script: script::WitnessScriptBuf = script.encode(); assert_eq!(bitcoin_script.len(), script.script_size()); if let Some(expected) = expected_hex.into() { assert_eq!(format!("{:x}", bitcoin_script), expected); @@ -1161,7 +1192,7 @@ mod tests { fn roundtrip(tree: &Segwitv0Script, s: &str) { assert_eq!(tree.ty.corr.base, types::Base::B); - let ser = tree.encode(); + let ser: script::WitnessScriptBuf = tree.encode(); assert_eq!(ser.len(), tree.script_size()); assert_eq!(ser.to_string(), s); let deser = @@ -1181,7 +1212,7 @@ mod tests { let ms: Result = Miniscript::from_str_insane(ms); match (ms, valid) { (Ok(ms), true) => { - assert_eq!(format!("{:x}", ms.encode()), expected_hex); + assert_eq!(format!("{:x}", ms.encode::()), expected_hex); assert_eq!(ms.ty.mall.non_malleable, non_mal); assert_eq!(ms.ty.mall.safe, need_sig); assert_eq!(ms.ext.static_ops + ms.ext.sat_data.unwrap().max_exec_op_count, ops); @@ -1213,7 +1244,7 @@ mod tests { 11, 1, ); - ms_attributes_test("t:and_v(vu:hash256(131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b),v:sha256(ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5))", "6382012088aa20131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b876700686982012088a820ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc58851", true, true, false, 12, 3); + ms_attributes_test("t:and_v(vu:hash256(131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b),v:sha256(ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5))", "6382012088aa201bc6ce16e2dd3eee5035a5b0b7b2c3b740a07683816013d84c44012c55721713876700686982012088a820ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc58851", true, true, false, 12, 3); ms_attributes_test("t:andor(multi(3,02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e,03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556,02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13),v:older(4194305),v:sha256(9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2))", "532102d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e2103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a14602975562102e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd1353ae6482012088a8209267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2886703010040b2696851", true, true, false, 13, 5); ms_attributes_test("or_d(multi(1,02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9),or_b(multi(3,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01,032fa2104d6b38d11b0230010559879124e42ab8dfeff5ff29dc9cdadd4ecacc3f,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a),su:after(500000)))", "512102f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f951ae73645321022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a0121032fa2104d6b38d11b0230010559879124e42ab8dfeff5ff29dc9cdadd4ecacc3f2103d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a53ae7c630320a107b16700689b68", true, true, false, 15, 7); ms_attributes_test("or_d(sha256(38df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b6),and_n(un:after(499999999),older(4194305)))", "82012088a82038df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b68773646304ff64cd1db19267006864006703010040b26868", true, false, false, 16, 1); @@ -1221,21 +1252,21 @@ mod tests { ms_attributes_test("j:and_b(multi(2,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97),s:or_i(older(1),older(4252898)))", "82926352210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c9752ae7c6351b26703e2e440b2689a68", true, false, true, 14, 4); ms_attributes_test("and_b(older(16),s:or_d(sha256(e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f),n:after(1567547623)))", "60b27c82012088a820e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f87736404e7e06e5db192689a", true, false, false, 12, 1); ms_attributes_test("j:and_v(v:hash160(20195b5a3d650c17f0f29f91c33f8f6335193d07),or_d(sha256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),older(16)))", "82926382012088a91420195b5a3d650c17f0f29f91c33f8f6335193d078882012088a82096de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c4787736460b26868", true, false, false, 16, 2); - ms_attributes_test("and_b(hash256(32ba476771d01e37807990ead8719f08af494723de1d228f2c2c07cc0aa40bac),a:and_b(hash256(131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b),a:older(1)))", "82012088aa2032ba476771d01e37807990ead8719f08af494723de1d228f2c2c07cc0aa40bac876b82012088aa20131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b876b51b26c9a6c9a", true, true, false, 15, 2); + ms_attributes_test("and_b(hash256(32ba476771d01e37807990ead8719f08af494723de1d228f2c2c07cc0aa40bac),a:and_b(hash256(131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b),a:older(1)))", "82012088aa20ac0ba40acc072c2c8f221dde234749af089f71d8ea907980371ed0716747ba32876b82012088aa201bc6ce16e2dd3eee5035a5b0b7b2c3b740a07683816013d84c44012c55721713876b51b26c9a6c9a", true, true, false, 15, 2); ms_attributes_test("thresh(2,multi(2,03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7,036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00),a:multi(1,036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00),ac:pk_k(022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01))", "522103a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c721036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a0052ae6b5121036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a0051ae6c936b21022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01ac6c935287", true, true, true, 13, 6); ms_attributes_test("and_n(sha256(d1ec675902ef1633427ca360b290b0b3045a0d9058ddb5e648b4c3c3224c5c68),t:or_i(v:older(4252898),v:older(144)))", "82012088a820d1ec675902ef1633427ca360b290b0b3045a0d9058ddb5e648b4c3c3224c5c68876400676303e2e440b26967029000b269685168", true, false, false, 14, 2); ms_attributes_test("or_d(nd:and_v(v:older(4252898),v:older(4252898)),sha256(38df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b6))", "766303e2e440b26903e2e440b2696892736482012088a82038df1c1f64a24a77b23393bca50dff872e31edc4f3b5aa3b90ad0b82f4f089b68768", true, false, false, 15, 2); ms_attributes_test("c:and_v(or_c(sha256(9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2),v:multi(1,02c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db)),pk_k(03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe))", "82012088a8209267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed28764512102c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db51af682103acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbeac", true, false, true, 9, 2); ms_attributes_test("c:and_v(or_c(multi(2,036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00,02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5),v:ripemd160(1b0f3c404d12075c68c938f9f60ebea4f74941a0)),pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))", "5221036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a002102352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d552ae6482012088a6141b0f3c404d12075c68c938f9f60ebea4f74941a088682103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556ac", true, true, true, 10, 5); - ms_attributes_test("and_v(andor(hash256(8a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b25),v:hash256(939894f70e6c3a25da75da0cc2071b4076d9b006563cf635986ada2e93c0d735),v:older(50000)),after(499999999))", "82012088aa208a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b2587640350c300b2696782012088aa20939894f70e6c3a25da75da0cc2071b4076d9b006563cf635986ada2e93c0d735886804ff64cd1db1", true, false, false, 14, 2); - ms_attributes_test("andor(hash256(5f8d30e655a7ba0d7596bb3ddfb1d2d20390d23b1845000e1e118b3be1b3f040),j:and_v(v:hash160(3a2bff0da9d96868e66abc4427bea4691cf61ccd),older(4194305)),ripemd160(44d90e2d3714c8663b632fcf0f9d5f22192cc4c8))", "82012088aa205f8d30e655a7ba0d7596bb3ddfb1d2d20390d23b1845000e1e118b3be1b3f040876482012088a61444d90e2d3714c8663b632fcf0f9d5f22192cc4c8876782926382012088a9143a2bff0da9d96868e66abc4427bea4691cf61ccd8803010040b26868", true, false, false, 20, 2); + ms_attributes_test("and_v(andor(hash256(8a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b25),v:hash256(939894f70e6c3a25da75da0cc2071b4076d9b006563cf635986ada2e93c0d735),v:older(50000)),after(499999999))", "82012088aa20254b29e4c70d1e72c3b4acf8dc74ebafe2e98549a6536fdeaa8ea492cad9358a87640350c300b2696782012088aa2035d7c0932eda6a9835f63c5606b0d976401b07c20cda75da253a6c0ef7949893886804ff64cd1db1", true, false, false, 14, 2); + ms_attributes_test("andor(hash256(5f8d30e655a7ba0d7596bb3ddfb1d2d20390d23b1845000e1e118b3be1b3f040),j:and_v(v:hash160(3a2bff0da9d96868e66abc4427bea4691cf61ccd),older(4194305)),ripemd160(44d90e2d3714c8663b632fcf0f9d5f22192cc4c8))", "82012088aa2040f0b3e13b8b111e0e0045183bd29003d2d2b1df3dbb96750dbaa755e6308d5f876482012088a61444d90e2d3714c8663b632fcf0f9d5f22192cc4c8876782926382012088a9143a2bff0da9d96868e66abc4427bea4691cf61ccd8803010040b26868", true, false, false, 20, 2); ms_attributes_test("or_i(c:and_v(v:after(500000),pk_k(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)),sha256(d9147961436944f43cd99d28b2bbddbf452ef872b30c8279e255e7daafc7f946))", "630320a107b1692102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5ac6782012088a820d9147961436944f43cd99d28b2bbddbf452ef872b30c8279e255e7daafc7f9468768", true, true, false, 10, 2); ms_attributes_test("thresh(2,c:pk_h(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),s:sha256(e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f),a:hash160(dd69735817e0e3f6f826a9238dc2e291184f0131))", "76a91420d637c1a6404d2227f3561fdbaff5a680dba64888ac7c82012088a820e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f87936b82012088a914dd69735817e0e3f6f826a9238dc2e291184f0131876c935287", true, false, false, 18, 4); ms_attributes_test("and_n(sha256(9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2),uc:and_v(v:older(144),pk_k(03fe72c435413d33d48ac09c9161ba8b09683215439d62b7940502bda8b202e6ce)))", "82012088a8209267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed28764006763029000b2692103fe72c435413d33d48ac09c9161ba8b09683215439d62b7940502bda8b202e6ceac67006868", true, false, true, 13, 3); ms_attributes_test("and_n(c:pk_k(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),and_b(l:older(4252898),a:older(16)))", "2103daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729ac64006763006703e2e440b2686b60b26c9a68", true, true, true, 12, 2); ms_attributes_test("c:or_i(and_v(v:older(16),pk_h(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729)),pk_h(02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5))", "6360b26976a91420d637c1a6404d2227f3561fdbaff5a680dba648886776a9148f9dff39a81ee4abcbad2ad8bafff090415a2be88868ac", true, true, true, 12, 3); ms_attributes_test("or_d(c:pk_h(02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5),andor(c:pk_k(024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97),older(2016),after(1567547623)))", "76a9148f9dff39a81ee4abcbad2ad8bafff090415a2be888ac736421024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97ac6404e7e06e5db16702e007b26868", true, true, false, 13, 3); - ms_attributes_test("c:andor(ripemd160(6ad07d21fd5dfc646f0b30577045ce201616b9ba),pk_h(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),and_v(v:hash256(8a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b25),pk_h(02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5)))", "82012088a6146ad07d21fd5dfc646f0b30577045ce201616b9ba876482012088aa208a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b258876a9148f9dff39a81ee4abcbad2ad8bafff090415a2be8886776a91420d637c1a6404d2227f3561fdbaff5a680dba6488868ac", true, false, true, 18, 3); + ms_attributes_test("c:andor(ripemd160(6ad07d21fd5dfc646f0b30577045ce201616b9ba),pk_h(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),and_v(v:hash256(8a35d9ca92a48eaade6f53a64985e9e2afeb74dcf8acb4c3721e0dc7e4294b25),pk_h(02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5)))", "82012088a6146ad07d21fd5dfc646f0b30577045ce201616b9ba876482012088aa20254b29e4c70d1e72c3b4acf8dc74ebafe2e98549a6536fdeaa8ea492cad9358a8876a9148f9dff39a81ee4abcbad2ad8bafff090415a2be8886776a91420d637c1a6404d2227f3561fdbaff5a680dba6488868ac", true, false, true, 18, 3); ms_attributes_test("c:andor(u:ripemd160(6ad07d21fd5dfc646f0b30577045ce201616b9ba),pk_h(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),or_i(pk_h(024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97),pk_h(02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5)))", "6382012088a6146ad07d21fd5dfc646f0b30577045ce201616b9ba87670068646376a914385defb0ed10fe95817943ed37b4984f8f4255d6886776a9148f9dff39a81ee4abcbad2ad8bafff090415a2be888686776a91420d637c1a6404d2227f3561fdbaff5a680dba6488868ac", true, false, true, 23, 4); ms_attributes_test("c:or_i(andor(c:pk_h(02352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5),pk_h(024ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97),pk_h(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729)),pk_k(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))", "6376a9148f9dff39a81ee4abcbad2ad8bafff090415a2be888ac6476a91420d637c1a6404d2227f3561fdbaff5a680dba648886776a914385defb0ed10fe95817943ed37b4984f8f4255d68868672103fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a146029755668ac", true, true, true, 17, 5); } @@ -1293,10 +1324,10 @@ mod tests { #[test] fn true_false() { - roundtrip(&ms_str!("1"), "OP_PUSHNUM_1"); - roundtrip(&ms_str!("tv:1"), "OP_PUSHNUM_1 OP_VERIFY OP_PUSHNUM_1"); + roundtrip(&ms_str!("1"), "OP_1"); + roundtrip(&ms_str!("tv:1"), "OP_1 OP_VERIFY OP_1"); roundtrip(&ms_str!("0"), "OP_0"); - roundtrip(&ms_str!("andor(0,1,0)"), "OP_0 OP_NOTIF OP_0 OP_ELSE OP_PUSHNUM_1 OP_ENDIF"); + roundtrip(&ms_str!("andor(0,1,0)"), "OP_0 OP_NOTIF OP_0 OP_ELSE OP_1 OP_ENDIF"); assert!(Segwitv0Script::from_str("1()").is_err()); assert!(Segwitv0Script::from_str("tv:1()").is_err()); @@ -1306,19 +1337,19 @@ mod tests { fn verify_parse() { let ms = "and_v(v:hash160(20195b5a3d650c17f0f29f91c33f8f6335193d07),or_d(sha256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),older(16)))"; let ms: Segwitv0Script = Miniscript::from_str_insane(ms).unwrap(); - assert_eq!(ms, Segwitv0Script::decode_consensus(&ms.encode()).unwrap()); + assert_eq!(ms, Segwitv0Script::decode_consensus(&ms.encode::()).unwrap()); let ms = "and_v(v:sha256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),or_d(sha256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),older(16)))"; let ms: Segwitv0Script = Miniscript::from_str_insane(ms).unwrap(); - assert_eq!(ms, Segwitv0Script::decode_consensus(&ms.encode()).unwrap()); + assert_eq!(ms, Segwitv0Script::decode_consensus(&ms.encode::()).unwrap()); let ms = "and_v(v:ripemd160(20195b5a3d650c17f0f29f91c33f8f6335193d07),or_d(sha256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),older(16)))"; let ms: Segwitv0Script = Miniscript::from_str_insane(ms).unwrap(); - assert_eq!(ms, Segwitv0Script::decode_consensus(&ms.encode()).unwrap()); + assert_eq!(ms, Segwitv0Script::decode_consensus(&ms.encode::()).unwrap()); let ms = "and_v(v:hash256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),or_d(sha256(96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47),older(16)))"; let ms: Segwitv0Script = Miniscript::from_str_insane(ms).unwrap(); - assert_eq!(ms, Segwitv0Script::decode_consensus(&ms.encode()).unwrap()); + assert_eq!(ms, Segwitv0Script::decode_consensus(&ms.encode::()).unwrap()); } #[test] @@ -1329,7 +1360,7 @@ mod tests { string_rtt( script, - "[B/onduesm]pk(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "[B/onduesm]pk(PublicKey { compressed: true, inner: 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa })", "pk(028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa)" ); @@ -1337,7 +1368,7 @@ mod tests { string_rtt( script, - "[B/onduesm]pk(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "[B/onduesm]pk(PublicKey { compressed: true, inner: 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa })", "pk(028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa)" ); @@ -1345,7 +1376,7 @@ mod tests { string_rtt( script, - "[B/onufsm]t[V/onfsm]v:[B/onduesm]pk(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "[B/onufsm]t[V/onfsm]v:[B/onduesm]pk(PublicKey { compressed: true, inner: 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa })", "tv:pk(028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa)" ); @@ -1353,7 +1384,7 @@ mod tests { string_display_debug_test( script, - "[B/nduesm]pkh(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "[B/nduesm]pkh(PublicKey { compressed: true, inner: 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa })", "pkh(028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa)", ); @@ -1361,7 +1392,7 @@ mod tests { string_display_debug_test( script, - "[B/nduesm]pkh(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "[B/nduesm]pkh(PublicKey { compressed: true, inner: 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa })", "pkh(028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa)", ); @@ -1369,7 +1400,7 @@ mod tests { string_display_debug_test( script, - "[B/nufsm]t[V/nfsm]v:[B/nduesm]pkh(PublicKey { compressed: true, inner: PublicKey(aa4c32e50fb34a95a372940ae3654b692ea35294748c3dd2c08b29f87ba9288c8294efcb73dc719e45b91c45f084e77aebc07c1ff3ed8f37935130a36304a340) })", + "[B/nufsm]t[V/nfsm]v:[B/nduesm]pkh(PublicKey { compressed: true, inner: 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa })", "tv:pkh(028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa)", ); } @@ -1380,7 +1411,7 @@ mod tests { let tree: &Segwitv0Script = &ms_str!("c:pk_h({})", keys[5]); assert_eq!(tree.ty.corr.base, types::Base::B); - let ser = tree.encode(); + let ser: script::WitnessScriptBuf = tree.encode(); let s = "\ OP_DUP OP_HASH160 OP_PUSHBYTES_20 \ 7e5a2a6a7610ca4ea78bd65a087bd75b1870e319 \ @@ -1395,7 +1426,7 @@ mod tests { ); roundtrip( &ms_str!("multi(3,{},{},{},{},{})", keys[0], keys[1], keys[2], keys[3], keys[4]), - "OP_PUSHNUM_3 OP_PUSHBYTES_33 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa OP_PUSHBYTES_33 03ab1ac1872a38a2f196bed5a6047f0da2c8130fe8de49fc4d5dfb201f7611d8e2 OP_PUSHBYTES_33 039729247032c0dfcf45b4841fcd72f6e9a2422631fc3466cf863e87154754dd40 OP_PUSHBYTES_33 032564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa OP_PUSHBYTES_33 0289637f97580a796e050791ad5a2f27af1803645d95df021a3c2d82eb8c2ca7ff OP_PUSHNUM_5 OP_CHECKMULTISIG" + "OP_3 OP_PUSHBYTES_33 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa OP_PUSHBYTES_33 03ab1ac1872a38a2f196bed5a6047f0da2c8130fe8de49fc4d5dfb201f7611d8e2 OP_PUSHBYTES_33 039729247032c0dfcf45b4841fcd72f6e9a2422631fc3466cf863e87154754dd40 OP_PUSHBYTES_33 032564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa OP_PUSHBYTES_33 0289637f97580a796e050791ad5a2f27af1803645d95df021a3c2d82eb8c2ca7ff OP_5 OP_CHECKMULTISIG" ); // Liquid policy @@ -1405,13 +1436,13 @@ mod tests { keys[1].to_string(), keys[3].to_string(), keys[4].to_string()), - "OP_PUSHNUM_2 OP_PUSHBYTES_33 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa \ + "OP_2 OP_PUSHBYTES_33 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa \ OP_PUSHBYTES_33 03ab1ac1872a38a2f196bed5a6047f0da2c8130fe8de49fc4d5dfb201f7611d8e2 \ - OP_PUSHNUM_2 OP_CHECKMULTISIG \ + OP_2 OP_CHECKMULTISIG \ OP_IFDUP OP_NOTIF \ - OP_PUSHNUM_2 OP_PUSHBYTES_33 032564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa \ + OP_2 OP_PUSHBYTES_33 032564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa \ OP_PUSHBYTES_33 0289637f97580a796e050791ad5a2f27af1803645d95df021a3c2d82eb8c2ca7ff \ - OP_PUSHNUM_2 OP_CHECKMULTISIGVERIFY \ + OP_2 OP_CHECKMULTISIGVERIFY \ OP_PUSHBYTES_2 1027 OP_CSV \ OP_ENDIF" ); @@ -1447,13 +1478,13 @@ mod tests { roundtrip( &ms_str!("multi(3,{},{},{},{},{})", keys[0], keys[1], keys[2], keys[3], keys[4]), - "OP_PUSHNUM_3 \ + "OP_3 \ OP_PUSHBYTES_33 028c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa \ OP_PUSHBYTES_33 03ab1ac1872a38a2f196bed5a6047f0da2c8130fe8de49fc4d5dfb201f7611d8e2 \ OP_PUSHBYTES_33 039729247032c0dfcf45b4841fcd72f6e9a2422631fc3466cf863e87154754dd40 \ OP_PUSHBYTES_33 032564fe9b5beef82d3703a607253f31ef8ea1b365772df434226aee642651b3fa \ OP_PUSHBYTES_33 0289637f97580a796e050791ad5a2f27af1803645d95df021a3c2d82eb8c2ca7ff \ - OP_PUSHNUM_5 OP_CHECKMULTISIG", + OP_5 OP_CHECKMULTISIG", ); roundtrip( @@ -1462,11 +1493,11 @@ mod tests { vu:hash256(131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b),\ v:sha256(ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5)\ )"), - "OP_IF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_HASH256 OP_PUSHBYTES_32 131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b OP_EQUAL OP_ELSE OP_0 OP_ENDIF OP_VERIFY OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_SHA256 OP_PUSHBYTES_32 ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5 OP_EQUALVERIFY OP_PUSHNUM_1" + "OP_IF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_HASH256 OP_PUSHBYTES_32 1bc6ce16e2dd3eee5035a5b0b7b2c3b740a07683816013d84c44012c55721713 OP_EQUAL OP_ELSE OP_0 OP_ENDIF OP_VERIFY OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_SHA256 OP_PUSHBYTES_32 ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5 OP_EQUALVERIFY OP_1" ); roundtrip( &ms_str!("and_n(pk(03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729),and_b(l:older(4252898),a:older(16)))"), - "OP_PUSHBYTES_33 03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729 OP_CHECKSIG OP_NOTIF OP_0 OP_ELSE OP_IF OP_0 OP_ELSE OP_PUSHBYTES_3 e2e440 OP_CSV OP_ENDIF OP_TOALTSTACK OP_PUSHNUM_16 OP_CSV OP_FROMALTSTACK OP_BOOLAND OP_ENDIF" + "OP_PUSHBYTES_33 03daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729 OP_CHECKSIG OP_NOTIF OP_0 OP_ELSE OP_IF OP_0 OP_ELSE OP_PUSHBYTES_3 e2e440 OP_CSV OP_ENDIF OP_TOALTSTACK OP_16 OP_CSV OP_FROMALTSTACK OP_BOOLAND OP_ENDIF" ); roundtrip( &ms_str!( @@ -1479,12 +1510,12 @@ mod tests { v:older(4194305),\ v:sha256(9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2)\ )"), - "OP_PUSHNUM_3 OP_PUSHBYTES_33 02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e \ + "OP_3 OP_PUSHBYTES_33 02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e \ OP_PUSHBYTES_33 03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556 \ OP_PUSHBYTES_33 02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13 \ - OP_PUSHNUM_3 OP_CHECKMULTISIG OP_NOTIF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_SHA256 \ + OP_3 OP_CHECKMULTISIG OP_NOTIF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_SHA256 \ OP_PUSHBYTES_32 9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2 OP_EQUALVERIFY \ - OP_ELSE OP_PUSHBYTES_3 010040 OP_CSV OP_VERIFY OP_ENDIF OP_PUSHNUM_1" + OP_ELSE OP_PUSHBYTES_3 010040 OP_CSV OP_VERIFY OP_ENDIF OP_1" ); roundtrip( &ms_str!( @@ -1493,16 +1524,16 @@ mod tests { v:sha256(ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5)\ )"), "\ - OP_IF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_HASH256 OP_PUSHBYTES_32 131772552c01444cd81360818376a040b7c3b2b7b0a53550ee3edde216cec61b OP_EQUAL \ + OP_IF OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_HASH256 OP_PUSHBYTES_32 1bc6ce16e2dd3eee5035a5b0b7b2c3b740a07683816013d84c44012c55721713 OP_EQUAL \ OP_ELSE OP_0 OP_ENDIF OP_VERIFY OP_SIZE OP_PUSHBYTES_1 20 OP_EQUALVERIFY OP_SHA256 OP_PUSHBYTES_32 ec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5 OP_EQUALVERIFY \ - OP_PUSHNUM_1\ + OP_1\ " ); // Thresh bug with equal verify roundtrip roundtrip( &ms_str!("tv:thresh(1,pk(02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e))", ), - "OP_PUSHBYTES_33 02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e OP_CHECKSIG OP_PUSHNUM_1 OP_EQUALVERIFY OP_PUSHNUM_1", + "OP_PUSHBYTES_33 02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e OP_CHECKSIG OP_1 OP_EQUALVERIFY OP_1", ); } @@ -1613,12 +1644,22 @@ mod tests { .translate_pk(&mut StrXOnlyKeyTranslator::new()) .unwrap(); // script rtt test - assert_eq!( - Miniscript::::decode_consensus(&tap_ms.encode()).unwrap(), - tap_ms - ); + // + // Claud wrote: Note: decode_consensus not available for bitcoin::key::XOnlyPublicKey + // + // FIXME: We should be able to un-comment this, I _think_ we can't because of + // + // **Taken from** ./context.rs + // impl ScriptContext for Tap { + // FIXME: Does this have to change to `bitcoin::XOnlyPublicKey`. + // type Key = bitcoin::secp256k1::XOnlyPublicKey; + // + // assert_eq!( + // Miniscript::::decode_consensus(&tap_ms.encode()).unwrap(), + // tap_ms + // ); assert_eq!(tap_ms.script_size(), 104); - assert_eq!(tap_ms.encode().len(), tap_ms.script_size()); + assert_eq!(tap_ms.encode::().len(), tap_ms.script_size()); // Test satisfaction code struct SimpleSatisfier(secp256k1::schnorr::Signature); @@ -1654,9 +1695,9 @@ mod tests { ) .unwrap(); let ms_trans = ms.translate_pk(&mut StrKeyTranslator::new()).unwrap(); - let enc = ms_trans.encode(); + let enc: script::WitnessScriptBuf = ms_trans.encode(); let ms = Miniscript::::decode_consensus(&enc).unwrap(); - assert_eq!(ms_trans.encode(), ms.encode()); + assert_eq!(ms_trans.encode::(), ms.encode::()); } #[test] @@ -1666,7 +1707,7 @@ mod tests { "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c", ) .unwrap(); - let hash160 = pk.pubkey_hash().to_raw_hash(); + let hash160 = hash160::Hash::from_byte_array(pk.pubkey_hash().to_byte_array()); let ms_str = &format!("c:expr_raw_pkh({})", hash160); type SegwitMs = Miniscript; @@ -1675,7 +1716,7 @@ mod tests { SegwitMs::from_str_insane(ms_str).unwrap_err(); let ms = SegwitMs::from_str_ext(ms_str, &ExtParams::allow_all()).unwrap(); - let script = ms.encode(); + let script: script::WitnessScriptBuf = ms.encode(); // The same test, but parsing from script SegwitMs::decode(&script).unwrap_err(); SegwitMs::decode_with_ext(&script, &ExtParams::insane()).unwrap_err(); @@ -1867,7 +1908,7 @@ mod tests { #[test] fn test_script_parse_dos() { - let mut script = bitcoin::script::Builder::new().push_opcode(bitcoin::opcodes::OP_TRUE); + let mut script: bitcoin::script::Builder = bitcoin::script::Builder::new().push_opcode(bitcoin::opcodes::all::OP_1); for _ in 0..10000 { script = script.push_opcode(bitcoin::opcodes::all::OP_0NOTEQUAL); } diff --git a/src/miniscript/satisfy.rs b/src/miniscript/satisfy.rs index 027aabd7f..e28ae2466 100644 --- a/src/miniscript/satisfy.rs +++ b/src/miniscript/satisfy.rs @@ -9,9 +9,10 @@ use core::{cmp, fmt, mem}; use bitcoin::hashes::hash160; -use bitcoin::key::XOnlyPublicKey; +use bitcoin::XOnlyPublicKey; use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash}; -use bitcoin::{absolute, relative, ScriptBuf, Sequence}; +use bitcoin::script::TapScriptBuf; +use bitcoin::{absolute, relative, Sequence}; use sync::Arc; use super::context::SigType; @@ -49,14 +50,14 @@ pub trait Satisfier { /// Obtain a reference to the control block for a ver and script fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { None } /// Given a raw `Pkh`, lookup corresponding [`bitcoin::PublicKey`] fn lookup_raw_pkh_pk(&self, _: &hash160::Hash) -> Option { None } - /// Given a raw `Pkh`, lookup corresponding [`bitcoin::secp256k1::XOnlyPublicKey`] + /// Given a raw `Pkh`, lookup corresponding [`bitcoin::XOnlyPublicKey`] fn lookup_raw_pkh_x_only_pk(&self, _: &hash160::Hash) -> Option { None } /// Given a keyhash, look up the EC signature and the associated key. @@ -247,7 +248,7 @@ macro_rules! impl_satisfier_for_map_hash_tapleafhash_to_key_taproot_sig { pk_hash: &(hash160::Hash, TapLeafHash), ) -> Option<(XOnlyPublicKey, bitcoin::taproot::Signature)> { self.get(pk_hash) - .map(|&(ref pk, sig)| (pk.to_x_only_pubkey(), sig)) + .map(|&(ref pk, sig)| (pk.to_x_only_pubkey().into(), sig)) } } }; @@ -303,7 +304,7 @@ impl> Satisfier for &S { fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { (**self).lookup_tap_control_block_map() } @@ -363,7 +364,7 @@ impl> Satisfier for &mut S fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { (**self).lookup_tap_control_block_map() } @@ -473,7 +474,7 @@ macro_rules! impl_tuple_satisfier { fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { let &($(ref $ty,)*) = self; $( if let Some(result) = $ty.lookup_tap_control_block_map() { @@ -602,7 +603,7 @@ pub enum Placeholder { /// \ PushZero, /// Taproot leaf script - TapScript(ScriptBuf), + TapScript(TapScriptBuf), /// Taproot control block TapControlBlock(ControlBlock), } diff --git a/src/plan.rs b/src/plan.rs index c3bfd5618..e6785d4ce 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -19,10 +19,11 @@ use core::iter::FromIterator; use bitcoin::hashes::{hash160, ripemd160, sha256}; -use bitcoin::key::XOnlyPublicKey; -use bitcoin::script::PushBytesBuf; +use bitcoin::script::{PushBytesBuf, WScriptHash}; use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash}; -use bitcoin::{absolute, bip32, psbt, relative, ScriptBuf, WitnessVersion}; +use bitcoin::script::{ScriptPubKeyBuf, ScriptSigBuf, TapScriptBuf}; +use bitcoin::blockdata::script::ScriptPubKeyBufExt; +use bitcoin::{absolute, bip32, psbt, relative, WitnessVersion, XOnlyPublicKey}; use crate::descriptor::{self, Descriptor, DescriptorType, KeyMap}; use crate::miniscript::hash256; @@ -56,7 +57,7 @@ pub trait AssetProvider { /// Given a raw `Pkh`, lookup corresponding [`bitcoin::PublicKey`] fn provider_lookup_raw_pkh_pk(&self, _: &hash160::Hash) -> Option { None } - /// Given a raw `Pkh`, lookup corresponding [`bitcoin::secp256k1::XOnlyPublicKey`] + /// Given a raw `Pkh`, lookup corresponding [`bitcoin::XOnlyPublicKey`] fn provider_lookup_raw_pkh_x_only_pk(&self, _: &hash160::Hash) -> Option { None } @@ -267,7 +268,7 @@ impl Plan { pub fn satisfy>( &self, stfr: &Sat, - ) -> Result<(Vec>, ScriptBuf), Error> { + ) -> Result<(Vec>, ScriptSigBuf), Error> { use bitcoin::blockdata::script::Builder; let stack = self @@ -295,7 +296,7 @@ impl Plan { DescriptorType::Wpkh | DescriptorType::Wsh | DescriptorType::WshSortedMulti - | DescriptorType::Tr => (stack, ScriptBuf::new()), + | DescriptorType::Tr => (stack, ScriptSigBuf::new()), DescriptorType::ShWsh | DescriptorType::ShWshSortedMulti | DescriptorType::ShWpkh => { (stack, self.descriptor.unsigned_script_sig()) } @@ -316,7 +317,7 @@ impl Plan { #[derive(Default)] struct TrDescriptorData { - tap_script: Option, + tap_script: Option, control_block: Option, spend_type: Option, key_origins: BTreeMap, @@ -337,7 +338,7 @@ impl Plan { match (&data.spend_type, sig_type) { // First encountered schnorr sig, update the `TrDescriptorData` accordingly - (None, SchnorrSigType::KeySpend { .. }) => data.spend_type = Some(SpendType::KeySpend { internal_key: raw_pk }), + (None, SchnorrSigType::KeySpend { .. }) => data.spend_type = Some(SpendType::KeySpend { internal_key: raw_pk.into() }), (None, SchnorrSigType::ScriptSpend { leaf_hash }) => data.spend_type = Some(SpendType::ScriptSpend { leaf_hash: *leaf_hash }), // Inconsistent placeholders (should be unreachable with the @@ -348,7 +349,7 @@ impl Plan { } for path in pk.full_derivation_paths() { - data.key_origins.insert(raw_pk, (pk.master_fingerprint(), path)); + data.key_origins.insert(raw_pk.into(), (pk.master_fingerprint(), path)); } } Placeholder::SchnorrSigPkHash(_, tap_leaf_hash, _) => { @@ -405,8 +406,11 @@ impl Plan { Descriptor::Bare(_) | Descriptor::Pkh(_) | Descriptor::Wpkh(_) => {} Descriptor::Sh(sh) => match sh.as_inner() { descriptor::ShInner::Wsh(wsh) => { - input.witness_script = Some(wsh.inner_script()); - input.redeem_script = Some(wsh.inner_script().to_p2wsh()); + let witness_script = wsh.inner_script(); + input.witness_script = Some(witness_script.clone()); + let wscript_hash = WScriptHash::from_script_unchecked(&witness_script); + let p2wsh_script = ScriptPubKeyBuf::new_p2wsh(wscript_hash); + input.redeem_script = Some(bitcoin::script::RedeemScriptBuf::from_bytes(p2wsh_script.into_bytes())); } descriptor::ShInner::Wpkh(..) => input.redeem_script = Some(sh.inner_script()), descriptor::ShInner::SortedMulti(_) | descriptor::ShInner::Ms(_) => { @@ -1067,7 +1071,7 @@ mod test { "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c", ) .unwrap()]; - let hashes = vec![hash160::Hash::from_slice(&[0; 20]).unwrap()]; + let hashes = vec![hash160::Hash::from_byte_array([0; 20])]; let desc = format!("wsh(and_v(v:pk({}),hash160({})))", keys[0], hashes[0]); let tests = vec![ diff --git a/src/policy/compiler.rs b/src/policy/compiler.rs index 4011bf467..5976798e5 100644 --- a/src/policy/compiler.rs +++ b/src/policy/compiler.rs @@ -1242,7 +1242,6 @@ mod tests { fn pubkeys_and_a_sig(n: usize) -> (Vec, secp256k1::ecdsa::Signature) { let mut ret = Vec::with_capacity(n); - let secp = secp256k1::Secp256k1::new(); let mut sk = [0; 32]; for i in 1..n + 1 { sk[0] = i as u8; @@ -1251,16 +1250,15 @@ mod tests { let pk = bitcoin::PublicKey { inner: secp256k1::PublicKey::from_secret_key( - &secp, - &secp256k1::SecretKey::from_slice(&sk[..]).expect("sk"), + &secp256k1::SecretKey::from_secret_bytes(sk).expect("sk"), ), compressed: true, }; ret.push(pk); } - let sig = secp.sign_ecdsa( - &secp256k1::Message::from_digest(sk), // Not a digest but 32 bytes nonetheless. - &secp256k1::SecretKey::from_slice(&sk[..]).expect("secret key"), + let sig = secp256k1::ecdsa::sign( + secp256k1::Message::from_digest(sk), // Not a digest but 32 bytes nonetheless. + &secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"), ); (ret, sig) } @@ -1345,9 +1343,9 @@ mod tests { let policy: BPolicy = Concrete::Key(keys[0]); let ms: SegwitMiniScript = policy.compile().unwrap(); assert_eq!( - ms.encode(), + ms.encode::(), script::Builder::new() - .push_key(&keys[0]) + .push_key(keys[0]) .push_opcode(opcodes::all::OP_CHECKSIG) .into_script() ); @@ -1362,16 +1360,19 @@ mod tests { let ms: SegwitMiniScript = policy.compile().unwrap(); assert_eq!( ms.encode(), - script::Builder::new() - .push_opcode(opcodes::all::OP_PUSHNUM_2) - .push_key(&keys[5]) - .push_key(&keys[6]) - .push_key(&keys[7]) - .push_opcode(opcodes::all::OP_PUSHNUM_3) - .push_opcode(opcodes::all::OP_CHECKMULTISIGVERIFY) - .push_int(10000) - .push_opcode(opcodes::all::OP_CSV) - .into_script() + { + let builder: script::Builder = script::Builder::new(); + builder + .push_opcode(opcodes::all::OP_PUSHNUM_2) + .push_key(keys[5]) + .push_key(keys[6]) + .push_key(keys[7]) + .push_opcode(opcodes::all::OP_PUSHNUM_3) + .push_opcode(opcodes::all::OP_CHECKMULTISIGVERIFY) + .push_int(10000).unwrap() + .push_opcode(opcodes::all::OP_CSV) + .into_script() + } ); // Liquid policy diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index ac9f815e1..d215f52d4 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -12,13 +12,10 @@ use core::convert::TryFrom; use core::mem; use bitcoin::hashes::hash160; -use bitcoin::key::XOnlyPublicKey; -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 -use bitcoin::secp256k1; -use bitcoin::secp256k1::Secp256k1; use bitcoin::sighash::Prevouts; use bitcoin::taproot::LeafVersion; -use bitcoin::{PublicKey, Script, ScriptBuf, TxOut, Witness}; +use bitcoin::script::{ScriptExt, ScriptPubKey, ScriptPubKeyBuf, ScriptPubKeyExt, ScriptSig, ScriptSigBuf, WitnessScriptExt}; +use bitcoin::{PublicKey, TxOut, Witness}; use super::{sanity_check, Error, InputError, Psbt, PsbtInputSatisfier}; use crate::prelude::*; @@ -33,13 +30,13 @@ use crate::{ // be present. Also, currently the spec does not support hidden branches, so // inferring a descriptor is not possible fn construct_tap_witness( - spk: &Script, + spk: &ScriptPubKey, sat: &PsbtInputSatisfier, allow_mall: bool, ) -> Result>, InputError> { // When miniscript tries to finalize the PSBT, it doesn't have the full descriptor (which contained a pkh() fragment) // and instead resorts to parsing the raw script sig, which is translated into a "expr_raw_pkh" internally. - let mut map: BTreeMap = BTreeMap::new(); + let mut map: BTreeMap = BTreeMap::new(); let psbt_inputs = &sat.psbt.inputs; for psbt_input in psbt_inputs { // We need to satisfy or dissatisfy any given key. `tap_key_origin` is the only field of PSBT Input which consist of @@ -47,16 +44,20 @@ fn construct_tap_witness( let public_keys = psbt_input.tap_key_origins.keys(); for key in public_keys { let bitcoin_key = *key; - let hash = bitcoin_key.to_pubkeyhash(SigType::Schnorr); - map.insert(hash, bitcoin_key); + // Convert XOnly key to full public key to compute hash160 + let full_pk = bitcoin_key.public_key(bitcoin::secp256k1::Parity::Even); + let hash = full_pk.to_pubkeyhash(SigType::Schnorr); + map.insert(hash, *key); } } assert!(spk.is_p2tr()); // try the key spend path firsti if let Some(ref key) = sat.psbt_input().tap_internal_key { + let secp_key = bitcoin::XOnlyPublicKey::from_byte_array(&key.serialize()) + .expect("32-byte array is valid XOnlyPublicKey"); if let Some(sig) = - >::lookup_tap_key_spend_sig(sat, key) + >::lookup_tap_key_spend_sig(sat, &secp_key) { return Ok(vec![sig.to_vec()]); } @@ -64,14 +65,14 @@ fn construct_tap_witness( // Next script spends let (mut min_wit, mut min_wit_len) = (None, None); if let Some(block_map) = - >::lookup_tap_control_block_map(sat) + >::lookup_tap_control_block_map(sat) { for (control_block, (script, ver)) in block_map { if *ver != LeafVersion::TapScript { // We don't know how to satisfy non default version scripts yet continue; } - let ms = match Miniscript::::decode_consensus(script) { + let ms = match Miniscript::::decode_consensus(script) { Ok(ms) => ms.substitute_raw_pkh(&map), Err(..) => continue, // try another script }; @@ -86,7 +87,9 @@ fn construct_tap_witness( Err(..) => continue, } }; - wit.push(ms.encode().into_bytes()); + // Encode tapscript + let encoded: bitcoin::TapScriptBuf = ms.encode(); + wit.push(encoded.as_bytes().to_vec()); wit.push(control_block.serialize()); let wit_len = Some(witness_size(&wit)); if min_wit_len.is_some() && wit_len > min_wit_len { @@ -105,7 +108,7 @@ fn construct_tap_witness( } // Get the scriptpubkey for the psbt input -pub(super) fn get_scriptpubkey(psbt: &Psbt, index: usize) -> Result { +pub(super) fn get_scriptpubkey(psbt: &Psbt, index: usize) -> Result { get_utxo(psbt, index).map(|utxo| utxo.script_pubkey.clone()) } @@ -115,8 +118,8 @@ pub(super) fn get_utxo(psbt: &Psbt, index: usize) -> Result<&bitcoin::TxOut, Inp let utxo = if let Some(ref witness_utxo) = inp.witness_utxo { witness_utxo } else if let Some(ref non_witness_utxo) = inp.non_witness_utxo { - let vout = psbt.unsigned_tx.input[index].previous_output.vout; - &non_witness_utxo.output[vout as usize] + let vout = psbt.unsigned_tx.inputs[index].previous_output.vout; + &non_witness_utxo.outputs[vout as usize] } else { return Err(InputError::MissingUtxo); }; @@ -149,8 +152,9 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In let public_keys = psbt_input.bip32_derivation.keys(); for key in public_keys { let bitcoin_key = bitcoin::PublicKey::new(*key); - let hash = bitcoin_key.pubkey_hash().to_raw_hash(); - map.insert(hash, bitcoin_key); + let hash = bitcoin_key.pubkey_hash().to_byte_array(); + let hash160 = hash160::Hash::from_byte_array(hash); + map.insert(hash160, bitcoin_key); } } @@ -188,7 +192,7 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In Ok(compressed) => { // 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(&compressed, bitcoin::Network::Bitcoin); + let addr = bitcoin::Address::p2wpkh(compressed, bitcoin::Network::Bitcoin); *script_pubkey == addr.script_pubkey() } Err(_) => false, @@ -204,7 +208,11 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In return Err(InputError::NonEmptyRedeemScript); } if let Some(ref witness_script) = inp.witness_script { - if witness_script.to_p2wsh() != *script_pubkey { + let p2wsh = witness_script.to_p2wsh().map_err(|_| InputError::InvalidWitnessScript { + witness_script: witness_script.clone(), + p2wsh_expected: script_pubkey.clone(), + })?; + if p2wsh != *script_pubkey { return Err(InputError::InvalidWitnessScript { witness_script: witness_script.clone(), p2wsh_expected: script_pubkey.clone(), @@ -219,7 +227,11 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In match inp.redeem_script { None => Err(InputError::MissingRedeemScript), Some(ref redeem_script) => { - if redeem_script.to_p2sh() != *script_pubkey { + let p2sh = redeem_script.to_p2sh().map_err(|_| InputError::InvalidRedeemScript { + redeem: redeem_script.clone(), + p2sh_expected: script_pubkey.clone(), + })?; + if p2sh != *script_pubkey { return Err(InputError::InvalidRedeemScript { redeem: redeem_script.clone(), p2sh_expected: script_pubkey.clone(), @@ -228,10 +240,14 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In if redeem_script.is_p2wsh() { // 5. `ShWsh` case if let Some(ref witness_script) = inp.witness_script { - if witness_script.to_p2wsh() != *redeem_script { + let p2wsh = witness_script.to_p2wsh().map_err(|_| InputError::InvalidWitnessScript { + witness_script: witness_script.clone(), + p2wsh_expected: bitcoin::script::ScriptPubKeyBuf::from_bytes(redeem_script.as_bytes().to_vec()), + })?; + if p2wsh.as_bytes() != redeem_script.as_bytes() { return Err(InputError::InvalidWitnessScript { witness_script: witness_script.clone(), - p2wsh_expected: redeem_script.clone(), + p2wsh_expected: bitcoin::script::ScriptPubKeyBuf::from_bytes(redeem_script.as_bytes().to_vec()), }); } let ms = Miniscript::::decode_consensus( @@ -247,10 +263,10 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In match bitcoin::key::CompressedPublicKey::try_from(pk) { Ok(compressed) => { let addr = bitcoin::Address::p2wpkh( - &compressed, + compressed, bitcoin::Network::Bitcoin, ); - *redeem_script == addr.script_pubkey() + redeem_script.as_bytes() == addr.script_pubkey().as_bytes() } Err(_) => false, } @@ -294,14 +310,13 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In /// The psbt must have included final script sig and final witness. /// In other words, this checks whether the finalized psbt interprets /// correctly -pub fn interpreter_check( +pub fn interpreter_check( psbt: &Psbt, - secp: &Secp256k1, ) -> Result<(), Error> { let utxos = prevouts(psbt)?; let utxos = &Prevouts::All(&utxos); for (index, input) in psbt.inputs.iter().enumerate() { - let empty_script_sig = ScriptBuf::new(); + let empty_script_sig = ScriptSigBuf::new(); let empty_witness = Witness::default(); let script_sig = input.final_script_sig.as_ref().unwrap_or(&empty_script_sig); let witness = input @@ -310,19 +325,18 @@ pub fn interpreter_check( .map(|wit_slice| Witness::from_slice(&wit_slice.to_vec())) // TODO: Update rust-bitcoin psbt API to use witness .unwrap_or(empty_witness); - interpreter_inp_check(psbt, secp, index, utxos, &witness, script_sig)?; + interpreter_inp_check(psbt, index, utxos, &witness, script_sig)?; } Ok(()) } // Run the miniscript interpreter on a single psbt input -fn interpreter_inp_check>( +fn interpreter_inp_check>( psbt: &Psbt, - secp: &Secp256k1, index: usize, - utxos: &Prevouts, + _utxos: &Prevouts, witness: &Witness, - script_sig: &Script, + script_sig: &ScriptSig, ) -> Result<(), Error> { let spk = get_scriptpubkey(psbt, index).map_err(|e| Error::InputError(e, index))?; @@ -331,11 +345,11 @@ fn interpreter_inp_check>( // Interpreter check { let cltv = psbt.unsigned_tx.lock_time; - let csv = psbt.unsigned_tx.input[index].sequence; + let csv = psbt.unsigned_tx.inputs[index].sequence; let interpreter = interpreter::Interpreter::from_txdata(&spk, script_sig, witness, csv, cltv) .map_err(|e| Error::InputError(InputError::Interpreter(e), index))?; - let iter = interpreter.iter(secp, &psbt.unsigned_tx, index, utxos); + let iter = interpreter.iter_assume_sigs(); if let Some(error) = iter.filter_map(Result::err).next() { return Err(Error::InputError(InputError::Interpreter(error), index)); }; @@ -355,31 +369,28 @@ fn interpreter_inp_check>( /// The functions fails it is not possible to satisfy any of the inputs non-malleably /// See [finalize_mall] if you want to allow malleable satisfactions #[deprecated(since = "7.0.0", note = "Please use PsbtExt::finalize instead")] -pub fn finalize( +pub fn finalize( psbt: &mut Psbt, - secp: &Secp256k1, ) -> Result<(), super::Error> { - finalize_helper(psbt, secp, false) + finalize_helper(psbt, false) } /// Same as [finalize], but allows for malleable satisfactions -pub fn finalize_mall( +pub fn finalize_mall( psbt: &mut Psbt, - secp: &Secp256k1, ) -> Result<(), super::Error> { - finalize_helper(psbt, secp, true) + finalize_helper(psbt, true) } -pub fn finalize_helper( +pub fn finalize_helper( psbt: &mut Psbt, - secp: &Secp256k1, allow_mall: bool, ) -> Result<(), super::Error> { sanity_check(psbt)?; // Actually construct the witnesses for index in 0..psbt.inputs.len() { - finalize_input(psbt, index, secp, allow_mall)?; + finalize_input(psbt, index, allow_mall)?; } // Interpreter is already run inside finalize_input for each input Ok(()) @@ -387,12 +398,11 @@ pub fn finalize_helper( // Helper function to obtain psbt final_witness/final_script_sig. // Does not add fields to the psbt, only returns the values. -fn finalize_input_helper( +fn finalize_input_helper( psbt: &Psbt, index: usize, - secp: &Secp256k1, allow_mall: bool, -) -> Result<(Witness, ScriptBuf), super::Error> { +) -> Result<(Witness, ScriptSigBuf), super::Error> { let (witness, script_sig) = { let spk = get_scriptpubkey(psbt, index).map_err(|e| Error::InputError(e, index))?; let sat = PsbtInputSatisfier::new(psbt, index); @@ -401,7 +411,7 @@ fn finalize_input_helper( // Deal with tr case separately, unfortunately we cannot infer the full descriptor for Tr let wit = construct_tap_witness(&spk, &sat, allow_mall) .map_err(|e| Error::InputError(e, index))?; - (wit, ScriptBuf::new()) + (wit, ScriptSigBuf::new()) } else { // Get a descriptor for this input. let desc = get_descriptor(psbt, index).map_err(|e| Error::InputError(e, index))?; @@ -420,18 +430,17 @@ fn finalize_input_helper( let witness = bitcoin::Witness::from_slice(&witness); let utxos = prevouts(psbt)?; let utxos = &Prevouts::All(&utxos); - interpreter_inp_check(psbt, secp, index, utxos, &witness, &script_sig)?; + interpreter_inp_check(psbt, index, utxos, &witness, &script_sig)?; Ok((witness, script_sig)) } -pub(super) fn finalize_input( +pub(super) fn finalize_input( psbt: &mut Psbt, index: usize, - secp: &Secp256k1, allow_mall: bool, ) -> Result<(), super::Error> { - let (witness, script_sig) = finalize_input_helper(psbt, index, secp, allow_mall)?; + let (witness, script_sig) = finalize_input_helper(psbt, index, allow_mall)?; // Now mutate the psbt input. Note that we cannot error after this point. // If the input is mutated, it means that the finalization succeeded. @@ -466,8 +475,7 @@ mod tests { fn tests_from_bip174() { let mut psbt = Psbt::deserialize(&hex::decode_to_vec("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f012202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d2010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap(); - let secp = Secp256k1::verification_only(); - psbt.finalize_mut(&secp).unwrap(); + psbt.finalize_mut().unwrap(); let expected = Psbt::deserialize(&hex::decode_to_vec("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap(); assert_eq!(psbt, expected); diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 916f8d3c1..7000bc2f8 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -12,14 +12,15 @@ use core::fmt; #[cfg(feature = "std")] use std::error; -use bitcoin::hashes::{hash160, sha256d, Hash}; +use bitcoin::hashes::{hash160, sha256d}; use bitcoin::psbt::{self, Psbt}; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 use bitcoin::secp256k1; -use bitcoin::secp256k1::{Secp256k1, VerifyOnly}; use bitcoin::sighash::{self, SighashCache}; use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapLeafHash}; -use bitcoin::{absolute, bip32, relative, transaction, Script, ScriptBuf}; +use bitcoin::script::{RedeemScriptBuf, ScriptExt, ScriptPubKey, ScriptPubKeyBuf, ScriptPubKeyExt, TapScriptBuf, WitnessScriptBuf, WitnessScriptExt}; +use bitcoin::transaction::TxInExt; +use bitcoin::{absolute, bip32, relative, transaction}; use crate::miniscript::context::SigType; use crate::prelude::*; @@ -99,16 +100,16 @@ pub enum InputError { /// Redeem script does not match the p2sh hash InvalidRedeemScript { /// Redeem script - redeem: ScriptBuf, + redeem: RedeemScriptBuf, /// Expected p2sh Script - p2sh_expected: ScriptBuf, + p2sh_expected: ScriptPubKeyBuf, }, /// Witness script does not match the p2wsh hash InvalidWitnessScript { /// Witness Script - witness_script: ScriptBuf, + witness_script: WitnessScriptBuf, /// Expected p2wsh script - p2wsh_expected: ScriptBuf, + p2wsh_expected: ScriptPubKeyBuf, }, /// Invalid sig InvalidSignature { @@ -263,7 +264,9 @@ impl<'psbt> PsbtInputSatisfier<'psbt> { impl Satisfier for PsbtInputSatisfier<'_> { fn lookup_tap_key_spend_sig(&self, pk: &Pk) -> Option { if let Some(key) = self.psbt_input().tap_internal_key { - if pk.to_x_only_pubkey() == key { + let secp_pk = pk.to_x_only_pubkey(); + let bitcoin_pk: bitcoin::XOnlyPublicKey = secp_pk.into(); + if bitcoin_pk == key { return self.psbt_input().tap_key_sig; } } @@ -275,9 +278,11 @@ impl Satisfier for PsbtInputSatisfier<'_> { pk: &Pk, lh: &TapLeafHash, ) -> Option { + let secp_pk = pk.to_x_only_pubkey(); + let bitcoin_pk: bitcoin::XOnlyPublicKey = secp_pk.into(); self.psbt_input() .tap_script_sigs - .get(&(pk.to_x_only_pubkey(), *lh)) + .get(&(bitcoin_pk, *lh)) .copied() } @@ -291,21 +296,25 @@ impl Satisfier for PsbtInputSatisfier<'_> { fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { + ) -> Option<&BTreeMap> { Some(&self.psbt_input().tap_scripts) } fn lookup_raw_pkh_tap_leaf_script_sig( &self, pkh: &(hash160::Hash, TapLeafHash), - ) -> Option<(bitcoin::secp256k1::XOnlyPublicKey, bitcoin::taproot::Signature)> { + ) -> Option<(bitcoin::XOnlyPublicKey, bitcoin::taproot::Signature)> { self.psbt_input() .tap_script_sigs .iter() .find(|&((pubkey, lh), _sig)| { - pubkey.to_pubkeyhash(SigType::Schnorr) == pkh.0 && *lh == pkh.1 + // Convert secp256k1::XOnlyPublicKey to bitcoin::key::XOnlyPublicKey + let btc_xonly = bitcoin::key::XOnlyPublicKey::from(*pubkey); + // Convert to full public key to get hash160 + let full_pk = btc_xonly.public_key(bitcoin::secp256k1::Parity::Even); + full_pk.to_pubkeyhash(SigType::Schnorr) == pkh.0 && *lh == pkh.1 }) - .map(|((x_only_pk, _leaf_hash), sig)| (*x_only_pk, *sig)) + .map(|((x_only_pk, _leaf_hash), sig)| (bitcoin::XOnlyPublicKey::from(*x_only_pk), *sig)) } fn lookup_ecdsa_sig(&self, pk: &Pk) -> Option { @@ -327,7 +336,7 @@ impl Satisfier for PsbtInputSatisfier<'_> { } fn check_after(&self, n: absolute::LockTime) -> bool { - if !self.psbt.unsigned_tx.input[self.index].enables_lock_time() { + if !self.psbt.unsigned_tx.inputs[self.index].enables_lock_time() { return false; } @@ -337,7 +346,7 @@ impl Satisfier for PsbtInputSatisfier<'_> { } fn check_older(&self, n: relative::LockTime) -> bool { - let seq = self.psbt.unsigned_tx.input[self.index].sequence; + let seq = self.psbt.unsigned_tx.inputs[self.index].sequence; if self.psbt.unsigned_tx.version < transaction::Version::TWO || !seq.is_relative_lock_time() { @@ -380,9 +389,9 @@ impl Satisfier for PsbtInputSatisfier<'_> { // rust-bitcoin TODO: (Long term) // Brainstorm about how we can enforce these in type system while having a nice API fn sanity_check(psbt: &Psbt) -> Result<(), Error> { - if psbt.unsigned_tx.input.len() != psbt.inputs.len() { + if psbt.unsigned_tx.inputs.len() != psbt.inputs.len() { return Err(Error::WrongInputCount { - in_tx: psbt.unsigned_tx.input.len(), + in_tx: psbt.unsigned_tx.inputs.len(), in_map: psbt.inputs.len(), }); } @@ -443,10 +452,7 @@ pub trait PsbtExt { /// # Errors: /// /// - A vector of errors, one of each of failed finalized input - fn finalize_mut( - &mut self, - secp: &secp256k1::Secp256k1, - ) -> Result<(), Vec>; + fn finalize_mut(&mut self) -> Result<(), Vec>; /// Same as [`PsbtExt::finalize_mut`], but does not mutate the input psbt and /// returns a new psbt @@ -455,22 +461,13 @@ pub trait PsbtExt { /// /// - Returns a mutated psbt with all inputs `finalize_mut` could finalize /// - A vector of input errors, one of each of failed finalized input - fn finalize( - self, - secp: &secp256k1::Secp256k1, - ) -> Result)>; + fn finalize(self) -> Result)>; /// Same as [PsbtExt::finalize_mut], but allows for malleable satisfactions - fn finalize_mall_mut( - &mut self, - secp: &Secp256k1, - ) -> Result<(), Vec>; + fn finalize_mall_mut(&mut self) -> Result<(), Vec>; /// Same as [PsbtExt::finalize], but allows for malleable satisfactions - fn finalize_mall( - self, - secp: &Secp256k1, - ) -> Result)>; + fn finalize_mall(self) -> Result)>; /// Same as [`PsbtExt::finalize_mut`], but only tries to finalize a single input leaving other /// inputs as is. Use this when not all of inputs that you are trying to @@ -479,11 +476,7 @@ pub trait PsbtExt { /// # Errors: /// /// - Input error detailing why the finalization failed. The psbt is not mutated when the finalization fails - fn finalize_inp_mut( - &mut self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result<(), Error>; + fn finalize_inp_mut(&mut self, index: usize) -> Result<(), Error>; /// Same as [`PsbtExt::finalize_inp_mut`], but does not mutate the psbt and returns a new one /// @@ -492,26 +485,14 @@ pub trait PsbtExt { /// - Original psbt /// - Input Error detailing why the input finalization failed #[allow(clippy::result_large_err)] // our "error type" includes the original PSBT - fn finalize_inp( - self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result; + fn finalize_inp(self, index: usize) -> Result; /// Same as [`PsbtExt::finalize_inp_mut`], but allows for malleable satisfactions - fn finalize_inp_mall_mut( - &mut self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result<(), Error>; + fn finalize_inp_mall_mut(&mut self, index: usize) -> Result<(), Error>; /// Same as [`PsbtExt::finalize_inp`], but allows for malleable satisfactions #[allow(clippy::result_large_err)] // our "error type" includes the original PSBT - fn finalize_inp_mall( - self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result; + fn finalize_inp_mall(self, index: usize) -> Result; /// Psbt extractor as defined in BIP174 that takes in a psbt reference /// and outputs a extracted [`bitcoin::Transaction`]. @@ -520,10 +501,7 @@ pub trait PsbtExt { /// /// Will error if the final ScriptSig or final Witness are missing /// or the interpreter check fails. - fn extract( - &self, - secp: &Secp256k1, - ) -> Result; + fn extract(&self) -> Result; /// Update PSBT input with a descriptor and check consistency of `*_utxo` fields. /// @@ -594,14 +572,11 @@ pub trait PsbtExt { } impl PsbtExt for Psbt { - fn finalize_mut( - &mut self, - secp: &secp256k1::Secp256k1, - ) -> Result<(), Vec> { + fn finalize_mut(&mut self) -> Result<(), Vec> { // Actually construct the witnesses let mut errors = vec![]; for index in 0..self.inputs.len() { - match finalizer::finalize_input(self, index, secp, /*allow_mall*/ false) { + match finalizer::finalize_input(self, index, /*allow_mall*/ false) { Ok(..) => {} Err(e) => { errors.push(e); @@ -615,23 +590,17 @@ impl PsbtExt for Psbt { } } - fn finalize( - mut self, - secp: &secp256k1::Secp256k1, - ) -> Result)> { - match self.finalize_mut(secp) { + fn finalize(mut self) -> Result)> { + match self.finalize_mut() { Ok(..) => Ok(self), Err(e) => Err((self, e)), } } - fn finalize_mall_mut( - &mut self, - secp: &secp256k1::Secp256k1, - ) -> Result<(), Vec> { + fn finalize_mall_mut(&mut self) -> Result<(), Vec> { let mut errors = vec![]; for index in 0..self.inputs.len() { - match finalizer::finalize_input(self, index, secp, /*allow_mall*/ true) { + match finalizer::finalize_input(self, index, /*allow_mall*/ true) { Ok(..) => {} Err(e) => { errors.push(e); @@ -645,64 +614,42 @@ impl PsbtExt for Psbt { } } - fn finalize_mall( - mut self, - secp: &Secp256k1, - ) -> Result)> { - match self.finalize_mall_mut(secp) { + fn finalize_mall(mut self) -> Result)> { + match self.finalize_mall_mut() { Ok(..) => Ok(self), Err(e) => Err((self, e)), } } - fn finalize_inp_mut( - &mut self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result<(), Error> { + fn finalize_inp_mut(&mut self, index: usize) -> Result<(), Error> { if index >= self.inputs.len() { return Err(Error::InputIdxOutofBounds { psbt_inp: self.inputs.len(), index }); } - finalizer::finalize_input(self, index, secp, /*allow_mall*/ false) + finalizer::finalize_input(self, index, /*allow_mall*/ false) } - fn finalize_inp( - mut self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result { - match self.finalize_inp_mut(secp, index) { + fn finalize_inp(mut self, index: usize) -> Result { + match self.finalize_inp_mut(index) { Ok(..) => Ok(self), Err(e) => Err((self, e)), } } - fn finalize_inp_mall_mut( - &mut self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result<(), Error> { + fn finalize_inp_mall_mut(&mut self, index: usize) -> Result<(), Error> { if index >= self.inputs.len() { return Err(Error::InputIdxOutofBounds { psbt_inp: self.inputs.len(), index }); } - finalizer::finalize_input(self, index, secp, /*allow_mall*/ false) + finalizer::finalize_input(self, index, /*allow_mall*/ false) } - fn finalize_inp_mall( - mut self, - secp: &secp256k1::Secp256k1, - index: usize, - ) -> Result { - match self.finalize_inp_mall_mut(secp, index) { + fn finalize_inp_mall(mut self, index: usize) -> Result { + match self.finalize_inp_mall_mut(index) { Ok(..) => Ok(self), Err(e) => Err((self, e)), } } - fn extract( - &self, - secp: &Secp256k1, - ) -> Result { + fn extract(&self) -> Result { sanity_check(self)?; let mut ret = self.unsigned_tx.clone(); @@ -712,13 +659,13 @@ impl PsbtExt for Psbt { } if let Some(witness) = input.final_script_witness.as_ref() { - ret.input[n].witness = witness.clone(); + ret.inputs[n].witness = witness.clone(); } if let Some(script_sig) = input.final_script_sig.as_ref() { - ret.input[n].script_sig = script_sig.clone(); + ret.inputs[n].script_sig = script_sig.clone(); } } - interpreter_check(self, secp)?; + interpreter_check(self)?; Ok(ret) } @@ -734,7 +681,7 @@ impl PsbtExt for Psbt { .ok_or(UtxoUpdateError::IndexOutOfBounds(input_index, n_inputs))?; let txin = self .unsigned_tx - .input + .inputs .get(input_index) .ok_or(UtxoUpdateError::MissingInputUtxo)?; @@ -756,7 +703,7 @@ impl PsbtExt for Psbt { } } (None, Some(non_witness_utxo)) => non_witness_utxo - .output + .outputs .get(txin.previous_output.vout as usize) .ok_or(UtxoUpdateError::UtxoCheck)? .script_pubkey @@ -764,7 +711,7 @@ impl PsbtExt for Psbt { (Some(witness_utxo), Some(non_witness_utxo)) => { if witness_utxo != non_witness_utxo - .output + .outputs .get(txin.previous_output.vout as usize) .ok_or(UtxoUpdateError::UtxoCheck)? { @@ -800,7 +747,7 @@ impl PsbtExt for Psbt { .ok_or(OutputUpdateError::IndexOutOfBounds(output_index, n_outputs))?; let txout = self .unsigned_tx - .output + .outputs .get(output_index) .ok_or(OutputUpdateError::MissingTxOut)?; @@ -858,7 +805,7 @@ impl PsbtExt for Psbt { .map_err(|_e| SighashError::InvalidSighashType)?; let amt = finalizer::get_utxo(self, idx) .map_err(|_e| SighashError::MissingInputUtxo)? - .value; + .amount; let is_nested_wpkh = inp_spk.is_p2sh() && inp .redeem_script @@ -890,12 +837,14 @@ impl PsbtExt for Psbt { Ok(PsbtSighashMsg::SegwitV0Sighash(msg)) } else { // legacy sighash case + let redeem_script; let script_code = if inp_spk.is_p2sh() { - inp.redeem_script + redeem_script = inp.redeem_script .as_ref() - .ok_or(SighashError::MissingRedeemScript)? + .ok_or(SighashError::MissingRedeemScript)?; + bitcoin::script::ScriptPubKey::from_bytes(redeem_script.as_bytes()) } else { - &inp_spk + bitcoin::script::ScriptPubKey::from_bytes(inp_spk.as_bytes()) }; let msg = cache.legacy_signature_hash(idx, script_code, hash_ty.to_u32())?; Ok(PsbtSighashMsg::LegacySighash(msg)) @@ -974,17 +923,14 @@ impl PsbtOutputExt for psbt::Output { // Traverse the pkh lookup while maintaining a reverse map for storing the map // hash160 -> (XonlyPublicKey)/PublicKey -struct KeySourceLookUp( - pub BTreeMap, - pub secp256k1::Secp256k1, -); +struct KeySourceLookUp(pub BTreeMap); impl Translator for KeySourceLookUp { type TargetPk = bitcoin::PublicKey; type Error = core::convert::Infallible; fn pk(&mut self, xpk: &DefiniteDescriptorKey) -> Result { - let derived = xpk.derive_public_key(&self.1); + let derived = xpk.derive_public_key(); self.0.insert( derived.to_public_key().inner, ( @@ -1002,13 +948,13 @@ impl Translator for KeySourceLookUp { // Provides generalized access to PSBT fields common to inputs and outputs trait PsbtFields { // Common fields are returned as a mutable ref of the same type - fn redeem_script(&mut self) -> &mut Option; - fn witness_script(&mut self) -> &mut Option; + fn redeem_script(&mut self) -> &mut Option; + fn witness_script(&mut self) -> &mut Option; fn bip32_derivation(&mut self) -> &mut BTreeMap; - fn tap_internal_key(&mut self) -> &mut Option; + fn tap_internal_key(&mut self) -> &mut Option; fn tap_key_origins( &mut self, - ) -> &mut BTreeMap, bip32::KeySource)>; + ) -> &mut BTreeMap, bip32::KeySource)>; #[allow(dead_code)] fn proprietary(&mut self) -> &mut BTreeMap>; #[allow(dead_code)] @@ -1018,24 +964,24 @@ trait PsbtFields { fn tap_tree(&mut self) -> Option<&mut Option> { None } // `tap_scripts` and `tap_merkle_root` only appear in psbt::Input - fn tap_scripts(&mut self) -> Option<&mut BTreeMap> { + fn tap_scripts(&mut self) -> Option<&mut BTreeMap> { None } fn tap_merkle_root(&mut self) -> Option<&mut Option> { None } } impl PsbtFields for psbt::Input { - fn redeem_script(&mut self) -> &mut Option { &mut self.redeem_script } - fn witness_script(&mut self) -> &mut Option { &mut self.witness_script } + fn redeem_script(&mut self) -> &mut Option { &mut self.redeem_script } + fn witness_script(&mut self) -> &mut Option { &mut self.witness_script } fn bip32_derivation(&mut self) -> &mut BTreeMap { &mut self.bip32_derivation } - fn tap_internal_key(&mut self) -> &mut Option { + fn tap_internal_key(&mut self) -> &mut Option { &mut self.tap_internal_key } fn tap_key_origins( &mut self, - ) -> &mut BTreeMap, bip32::KeySource)> { + ) -> &mut BTreeMap, bip32::KeySource)> { &mut self.tap_key_origins } #[allow(dead_code)] @@ -1045,7 +991,7 @@ impl PsbtFields for psbt::Input { #[allow(dead_code)] fn unknown(&mut self) -> &mut BTreeMap> { &mut self.unknown } - fn tap_scripts(&mut self) -> Option<&mut BTreeMap> { + fn tap_scripts(&mut self) -> Option<&mut BTreeMap> { Some(&mut self.tap_scripts) } fn tap_merkle_root(&mut self) -> Option<&mut Option> { @@ -1054,17 +1000,17 @@ impl PsbtFields for psbt::Input { } impl PsbtFields for psbt::Output { - fn redeem_script(&mut self) -> &mut Option { &mut self.redeem_script } - fn witness_script(&mut self) -> &mut Option { &mut self.witness_script } + fn redeem_script(&mut self) -> &mut Option { &mut self.redeem_script } + fn witness_script(&mut self) -> &mut Option { &mut self.witness_script } fn bip32_derivation(&mut self) -> &mut BTreeMap { &mut self.bip32_derivation } - fn tap_internal_key(&mut self) -> &mut Option { + fn tap_internal_key(&mut self) -> &mut Option { &mut self.tap_internal_key } fn tap_key_origins( &mut self, - ) -> &mut BTreeMap, bip32::KeySource)> { + ) -> &mut BTreeMap, bip32::KeySource)> { &mut self.tap_key_origins } #[allow(dead_code)] @@ -1080,18 +1026,16 @@ impl PsbtFields for psbt::Output { fn update_item_with_descriptor_helper( item: &mut F, descriptor: &Descriptor, - check_script: Option<&Script>, + check_script: Option<&ScriptPubKey>, // We return an extra boolean here to indicate an error with `check_script`. We do this // because the error is "morally" a UtxoUpdateError::MismatchedScriptPubkey, but some // callers expect a `descriptor::NonDefiniteKeyError`, which cannot be produced from a // `UtxoUpdateError`, and those callers can't get this error anyway because they pass // `None` for `check_script`. ) -> Result<(Descriptor, bool), descriptor::NonDefiniteKeyError> { - let secp = Secp256k1::verification_only(); - // 1. Derive the descriptor, recording each key derivation in a map from xpubs // the keysource used to derive the key. - let mut bip32_derivation = KeySourceLookUp(BTreeMap::new(), secp); + let mut bip32_derivation = KeySourceLookUp(BTreeMap::new()); let derived = descriptor .translate_pk(&mut bip32_derivation) .map_err(crate::TranslateErr::into_outer_err) @@ -1107,19 +1051,21 @@ fn update_item_with_descriptor_helper( // 3. Update the PSBT fields using the derived key map. if let Descriptor::Tr(ref tr_derived) = &derived { let spend_info = tr_derived.spend_info(); - let KeySourceLookUp(xpub_map, _) = bip32_derivation; + let KeySourceLookUp(xpub_map) = bip32_derivation; *item.tap_internal_key() = Some(spend_info.internal_key()); for (derived_key, key_source) in xpub_map { + let secp_key = derived_key.to_x_only_pubkey(); + let bitcoin_key: bitcoin::XOnlyPublicKey = secp_key.into(); item.tap_key_origins() - .insert(derived_key.to_x_only_pubkey(), (vec![], key_source)); + .insert(bitcoin_key, (vec![], key_source)); } if let Some(merkle_root) = item.tap_merkle_root() { *merkle_root = spend_info.merkle_root(); } for leaf_derived in spend_info.leaves() { - let leaf_script = (ScriptBuf::from(leaf_derived.script()), leaf_derived.leaf_version()); + let leaf_script = (TapScriptBuf::from(leaf_derived.script()), leaf_derived.leaf_version()); let tapleaf_hash = leaf_derived.leaf_hash(); if let Some(tap_scripts) = item.tap_scripts() { let control_block = leaf_derived.control_block().clone(); @@ -1127,9 +1073,11 @@ fn update_item_with_descriptor_helper( } for leaf_pk in leaf_derived.miniscript().iter_pk() { + let secp_key = leaf_pk.to_x_only_pubkey(); + let bitcoin_key: bitcoin::XOnlyPublicKey = secp_key.into(); let tapleaf_hashes = &mut item .tap_key_origins() - .get_mut(&leaf_pk.to_x_only_pubkey()) + .get_mut(&bitcoin_key) .expect("inserted all keys above") .0; if tapleaf_hashes.last() != Some(&tapleaf_hash) { @@ -1159,7 +1107,8 @@ fn update_item_with_descriptor_helper( Descriptor::Sh(sh) => match sh.as_inner() { descriptor::ShInner::Wsh(wsh) => { *item.witness_script() = Some(wsh.inner_script()); - *item.redeem_script() = Some(wsh.inner_script().to_p2wsh()); + let p2wsh_script = wsh.inner_script().to_p2wsh().expect("valid witness script"); + *item.redeem_script() = Some(bitcoin::script::RedeemScriptBuf::from_bytes(p2wsh_script.into_bytes())); } descriptor::ShInner::Wpkh(..) => *item.redeem_script() = Some(sh.inner_script()), descriptor::ShInner::SortedMulti(_) | descriptor::ShInner::Ms(_) => { @@ -1369,9 +1318,9 @@ mod tests { use bitcoin::bip32::{DerivationPath, Xpub}; use bitcoin::consensus::encode::deserialize; - use bitcoin::key::XOnlyPublicKey; + use bitcoin::script::{self, ScriptPubKeyBuf, ScriptBufExt}; use bitcoin::secp256k1::PublicKey; - use bitcoin::{Amount, OutPoint, TxIn, TxOut}; + use bitcoin::{Amount, OutPoint, TxIn, TxOut, XOnlyPublicKey}; use hex; use super::*; @@ -1380,8 +1329,7 @@ mod tests { #[test] fn test_extract_bip174() { let psbt = bitcoin::Psbt::deserialize(&hex::decode_to_vec("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap(); - let secp = Secp256k1::verification_only(); - let tx = psbt.extract(&secp).unwrap(); + let tx = psbt.extract().unwrap(); let expected: bitcoin::Transaction = deserialize(&hex::decode_to_vec("0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000").unwrap()).unwrap(); assert_eq!(tx, expected); } @@ -1527,7 +1475,7 @@ mod tests { psbt_output.update_with_descriptor_unchecked(&desc).unwrap(); assert_eq!(expected_bip32, psbt_input.bip32_derivation); - assert_eq!(psbt_input.witness_script, Some(derived.explicit_script().unwrap())); + assert_eq!(psbt_input.witness_script, Some(script::WitnessScriptBuf::from(derived.explicit_script().unwrap().to_bytes()))); assert_eq!(psbt_output.bip32_derivation, psbt_input.bip32_derivation); assert_eq!(psbt_output.witness_script, psbt_input.witness_script); @@ -1548,7 +1496,7 @@ mod tests { assert_eq!(psbt_input.bip32_derivation, expected_bip32); assert_eq!(psbt_input.witness_script, None); - assert_eq!(psbt_input.redeem_script, Some(derived.explicit_script().unwrap())); + assert_eq!(psbt_input.redeem_script, Some(script::RedeemScriptBuf::from(derived.explicit_script().unwrap().to_bytes()))); assert_eq!(psbt_output.bip32_derivation, psbt_input.bip32_derivation); assert_eq!(psbt_output.witness_script, psbt_input.witness_script); @@ -1564,10 +1512,10 @@ mod tests { let mut non_witness_utxo = bitcoin::Transaction { version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, - input: vec![], - output: vec![TxOut { - value: Amount::from_sat(1_000), - script_pubkey: ScriptBuf::from_hex( + inputs: vec![], + outputs: vec![TxOut { + amount: Amount::from_sat_u32(1_000), + script_pubkey: ScriptPubKeyBuf::from_hex( "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c", ) .unwrap(), @@ -1577,11 +1525,13 @@ mod tests { let tx = bitcoin::Transaction { version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, - input: vec![TxIn { + inputs: vec![TxIn { previous_output: OutPoint { txid: non_witness_utxo.compute_txid(), vout: 0 }, - ..Default::default() + script_sig: bitcoin::ScriptSigBuf::new(), + sequence: bitcoin::Sequence::MAX, + witness: bitcoin::Witness::default(), }], - output: vec![], + outputs: vec![], }; let mut psbt = Psbt::from_unsigned_tx(tx).unwrap(); @@ -1590,7 +1540,7 @@ mod tests { Err(UtxoUpdateError::UtxoCheck), "neither *_utxo are not set" ); - psbt.inputs[0].witness_utxo = Some(non_witness_utxo.output[0].clone()); + psbt.inputs[0].witness_utxo = Some(non_witness_utxo.outputs[0].clone()); assert_eq!( psbt.update_input_with_descriptor(0, &desc), Ok(()), @@ -1602,7 +1552,7 @@ mod tests { Ok(()), "matching non_witness_utxo" ); - non_witness_utxo.version = transaction::Version::non_standard(0); + non_witness_utxo.version = transaction::Version::maybe_non_standard(0); psbt.inputs[0].non_witness_utxo = Some(non_witness_utxo); assert_eq!( psbt.update_input_with_descriptor(0, &desc), @@ -1610,7 +1560,7 @@ mod tests { "non_witness_utxo no longer matches" ); psbt.inputs[0].non_witness_utxo = None; - psbt.inputs[0].witness_utxo.as_mut().unwrap().script_pubkey = ScriptBuf::default(); + psbt.inputs[0].witness_utxo.as_mut().unwrap().script_pubkey = ScriptPubKeyBuf::default(); assert_eq!( psbt.update_input_with_descriptor(0, &desc), Err(UtxoUpdateError::MismatchedScriptPubkey), @@ -1626,10 +1576,10 @@ mod tests { let tx = bitcoin::Transaction { version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, - input: vec![], - output: vec![TxOut { - value: Amount::from_sat(1_000), - script_pubkey: ScriptBuf::from_hex( + inputs: vec![], + outputs: vec![TxOut { + amount: Amount::from_sat_u32(1_000), + script_pubkey: ScriptPubKeyBuf::from_hex( "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c", ) .unwrap(), @@ -1647,7 +1597,7 @@ mod tests { Ok(()), "script_pubkey should match" ); - psbt.unsigned_tx.output[0].script_pubkey = ScriptBuf::default(); + psbt.unsigned_tx.outputs[0].script_pubkey = ScriptPubKeyBuf::new(); assert_eq!( psbt.update_output_with_descriptor(0, &desc), Err(OutputUpdateError::MismatchedScriptPubkey), diff --git a/src/test_utils.rs b/src/test_utils.rs index 9d52b7c25..10ee16441 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -7,7 +7,7 @@ use std::collections::HashMap; use std::str::FromStr; use bitcoin::hashes::{hash160, ripemd160, sha256}; -use bitcoin::key::XOnlyPublicKey; +use bitcoin::XOnlyPublicKey; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 use bitcoin::secp256k1; @@ -129,7 +129,7 @@ fn random_sks(n: usize) -> Vec { sk[2] = (i >> 16) as u8; sk[3] = (i >> 24) as u8; - let sk = secp256k1::SecretKey::from_slice(&sk[..]).expect("secret key"); + let sk = secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"); sks.push(sk) } sks @@ -137,11 +137,10 @@ fn random_sks(n: usize) -> Vec { impl StrKeyTranslator { pub fn new() -> Self { - let secp = secp256k1::Secp256k1::new(); let sks = random_sks(26); let pks: Vec<_> = sks .iter() - .map(|sk| bitcoin::PublicKey::new(secp256k1::PublicKey::from_secret_key(&secp, sk))) + .map(|sk| bitcoin::PublicKey::new(secp256k1::PublicKey::from_secret_key(sk))) .collect(); let mut pk_map = HashMap::new(); let mut pkh_map = HashMap::new(); @@ -164,12 +163,11 @@ impl StrKeyTranslator { impl StrXOnlyKeyTranslator { pub fn new() -> Self { - let secp = secp256k1::Secp256k1::new(); let sks = random_sks(26); let pks: Vec<_> = sks .iter() .map(|sk| { - let keypair = secp256k1::Keypair::from_secret_key(&secp, sk); + let keypair = secp256k1::Keypair::from_secret_key(sk); let (pk, _parity) = XOnlyPublicKey::from_keypair(&keypair); pk }) diff --git a/src/util.rs b/src/util.rs index 5de37b780..743e7c215 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2,16 +2,14 @@ use core::convert::TryFrom; -use bitcoin::constants::MAX_SCRIPT_ELEMENT_SIZE; -use bitcoin::hashes::Hash; -use bitcoin::script::{self, PushBytes, ScriptBuf}; -use bitcoin::PubkeyHash; +use bitcoin::blockdata::constants::MAX_REDEEM_SCRIPT_SIZE; +use bitcoin::script::{self, PushBytes, ScriptSigBuf}; use crate::miniscript::context; use crate::miniscript::satisfy::Placeholder; use crate::prelude::*; use crate::{MiniscriptKey, ScriptContext, ToPublicKey}; -pub(crate) fn varint_len(n: usize) -> usize { bitcoin::VarInt(n as u64).size() } +pub(crate) fn varint_len(n: usize) -> usize { bitcoin::consensus::encode::varint_size(n as u64) } pub(crate) trait ItemSize { fn size(&self) -> usize; @@ -51,19 +49,20 @@ pub(crate) fn witness_size(wit: &[T]) -> usize { wit.iter().map(T::size).sum::() + varint_len(wit.len()) } -pub(crate) fn witness_to_scriptsig(witness: &[Vec]) -> ScriptBuf { +pub(crate) fn witness_to_scriptsig(witness: &[Vec]) -> ScriptSigBuf { let mut b = script::Builder::new(); for (i, wit) in witness.iter().enumerate() { - if let Ok(n) = script::read_scriptint(wit) { - b = b.push_int(n); - } else { - if i != witness.len() - 1 { - assert!(wit.len() < 73, "All pushes in miniscript are < 73 bytes"); + if let Ok(push_bytes) = <&PushBytes>::try_from(wit.as_slice()) { + if let Ok(n) = push_bytes.read_scriptint() { + b = b.push_int(n as i32).expect("valid script int"); } else { - assert!(wit.len() <= MAX_SCRIPT_ELEMENT_SIZE, "P2SH redeem script is <= 520 bytes"); + if i != witness.len() - 1 { + assert!(wit.len() < 73, "All pushes in miniscript are < 73 bytes"); + } else { + assert!(wit.len() <= MAX_REDEEM_SCRIPT_SIZE, "P2SH redeem script is <= 520 bytes"); + } + b = b.push_slice(push_bytes); } - let push = <&PushBytes>::try_from(wit.as_slice()).expect("checked above"); - b = b.push_slice(push) } } b.into_script() @@ -84,14 +83,14 @@ pub(crate) trait MsKeyBuilder { Ctx: ScriptContext; } -impl MsKeyBuilder for script::Builder { +impl MsKeyBuilder for script::Builder { fn push_ms_key(self, key: &Pk) -> Self where Pk: ToPublicKey, Ctx: ScriptContext, { match Ctx::sig_type() { - context::SigType::Ecdsa => self.push_key(&key.to_public_key()), + context::SigType::Ecdsa => self.push_key(key.to_public_key()), context::SigType::Schnorr => self.push_slice(key.to_x_only_pubkey().serialize()), } } @@ -104,7 +103,10 @@ impl MsKeyBuilder for script::Builder { match Ctx::sig_type() { context::SigType::Ecdsa => self.push_slice(key.to_public_key().pubkey_hash()), context::SigType::Schnorr => { - self.push_slice(PubkeyHash::hash(&key.to_x_only_pubkey().serialize())) + // Convert XOnly key to full public key (assuming even parity) to get hash + let xonly = key.to_x_only_pubkey(); + let full_pk = xonly.public_key(bitcoin::secp256k1::Parity::Even); + self.push_slice(full_pk.pubkey_hash()) } } } diff --git a/tests/bip-174.rs b/tests/bip-174.rs index 25f8e2d2b..dc955c15a 100644 --- a/tests/bip-174.rs +++ b/tests/bip-174.rs @@ -12,17 +12,15 @@ fn main() { let expected_finalized_psbt = Psbt::deserialize(&hex::decode_to_vec("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap(); - // Construct a secp context for transaction signature verification - let secp = bitcoin::secp256k1::Secp256k1::verification_only(); // Assuming all partial sigs are filled in. // Construct a generic finalizer - psbt.finalize_mut(&secp).unwrap(); + psbt.finalize_mut().unwrap(); // println!("{:?}", psbt); assert_eq!(psbt, expected_finalized_psbt); // Extract the transaction from the psbt - let tx = psbt.extract(&secp).unwrap(); + let tx = psbt.extract().unwrap(); let expected: bitcoin::Transaction = deserialize(&hex::decode_to_vec("0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000").unwrap()).unwrap(); // println!("{:?}", tx);