diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 91a74f3b2..5f0741905 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "base58ck" @@ -23,124 +23,257 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" dependencies = [ - "bitcoin-internals", - "bitcoin_hashes", + "bitcoin-internals 0.3.0", + "bitcoin_hashes 0.14.1", +] + +[[package]] +name = "base58ck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6a87a8367e7a4248c8dfd783c37ef492bca1307cd4b21b4cfad9cfd15bf060" +dependencies = [ + "bitcoin-internals 0.5.0", + "bitcoin_hashes 0.20.0", ] [[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" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" +checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f" [[package]] name = "bitcoin" -version = "0.32.6" +version = "0.32.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8929a18b8e33ea6b3c09297b687baaa71fb1b97353243a3f1029fad5c59c5b" +checksum = "1e499f9fc0407f50fe98af744ab44fa67d409f76b6772e1689ec8485eb0c0f66" dependencies = [ - "base58ck", - "base64", + "base58ck 0.1.0", "bech32", - "bitcoin-internals", - "bitcoin-io", - "bitcoin-units", - "bitcoin_hashes", - "hex-conservative 0.2.1", + "bitcoin-internals 0.3.0", + "bitcoin-io 0.1.4", + "bitcoin-units 0.1.2", + "bitcoin_hashes 0.14.1", + "hex-conservative 0.2.2", "hex_lit", - "secp256k1", + "secp256k1 0.29.1", +] + +[[package]] +name = "bitcoin" +version = "0.33.0-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "517161def4ca8527bfc4ba36efe5b40923024f73308a1f9c0fc5cca1bee2f536" +dependencies = [ + "base58ck 0.4.0", + "base64", + "bech32", + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "bitcoin-io 0.5.0", + "bitcoin-network-kind", + "bitcoin-primitives", + "bitcoin-units 0.3.0", + "bitcoin_hashes 0.20.0", + "bitcoinconsensus", + "hex-conservative 0.3.2", + "hex-conservative 1.0.1", + "secp256k1 0.32.0-beta.2", "serde", ] +[[package]] +name = "bitcoin-consensus-encoding" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d7ca3dc8ff835693ad73bf1596240c06f974a31eeb3f611aaedf855f1f2725" +dependencies = [ + "bitcoin-internals 0.5.0", +] + [[package]] name = "bitcoin-internals" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" + +[[package]] +name = "bitcoin-internals" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a30a22d1f112dde8e16be7b45c63645dc165cef254f835b3e1e9553e485cfa64" dependencies = [ + "hex-conservative 0.3.2", "serde", ] [[package]] name = "bitcoin-io" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e5b76b88667412087beea1882980ad843b660490bbf6cce0a6cfc999c5b989" +checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" [[package]] -name = "bitcoin-units" +name = "bitcoin-io" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6fb823712b12e5cfccdb9a2b6a62de2dc42ddb5ec489511025eebeba1c21829" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "bitcoin_hashes 0.20.0", +] + +[[package]] +name = "bitcoin-network-kind" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d437fd727271c866d6fd5e71eb2c886437d4c97f80d89246be3189b1da4e58b" +checksum = "f85911fdff634a2e65f8175a54e609172a718d385ab4da87937f166d37eef4a3" dependencies = [ - "bitcoin-internals", + "bitcoin-internals 0.5.0", + "serde", +] + +[[package]] +name = "bitcoin-primitives" +version = "0.102.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48379e4d9a4456c038d78551ccbb8a3d7f9514c799f51ae815a6e947d64c9efe" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "bitcoin-units 0.3.0", + "bitcoin_hashes 0.20.0", + "hex-conservative 0.3.2", + "hex-conservative 1.0.1", + "serde", +] + +[[package]] +name = "bitcoin-units" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +dependencies = [ + "bitcoin-internals 0.3.0", +] + +[[package]] +name = "bitcoin-units" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fe8fafd73be14659c450deb64f90d2fd5a354fce366a01223a8319cf4d98b40" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", "serde", ] [[package]] name = "bitcoin_hashes" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" dependencies = [ - "bitcoin-io", - "hex-conservative 0.2.1", + "bitcoin-io 0.1.4", + "hex-conservative 0.2.2", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8a45c2b41c457a9a9e4670422fcbdf109afb3b22bc920b4045e8bdfd788a3d" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "hex-conservative 0.3.2", "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" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" +dependencies = [ + "find-msvc-tools", + "shlex", +] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "descriptor-fuzz" version = "0.0.1" dependencies = [ "honggfuzz", - "miniscript 12.3.0", + "miniscript 12.3.5", "miniscript 13.0.0", "regex", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" +dependencies = [ + "arrayvec", ] [[package]] name = "hex-conservative" -version = "0.2.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +checksum = "830e599c2904b08f0834ee6337d8fe8f0ed4a63b5d9e7a7f49c0ffa06d08d360" dependencies = [ "arrayvec", ] [[package]] name = "hex-conservative" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee770c000993d17c185713463d5ebfbd1af9afae4c17cc295640104383bfbf0" +checksum = "366fa3443ac84474447710ec17bb00b05dfbd096137817981e86f992f21a2793" [[package]] name = "hex_lit" @@ -150,50 +283,51 @@ checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" [[package]] name = "honggfuzz" -version = "0.5.56" +version = "0.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c76b6234c13c9ea73946d1379d33186151148e0da231506b964b44f3d023505" +checksum = "4d6510a410acedd7a7683b3a45dafdc5ccf3c72d6addaa373497005964fc4e23" dependencies = [ "lazy_static", "memmap2", "rustc_version", + "semver", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" dependencies = [ "libc", ] [[package]] name = "miniscript" -version = "12.3.0" +version = "12.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd3c9608217b0d6fa9c9c8ddd875b85ab72bd4311cfc8db35e1b5a08fc11f4d" +checksum = "487906208f38448e186e3deb02f2b8ef046a9078b0de00bdb28bf4fb9b76951c" dependencies = [ "bech32", - "bitcoin", + "bitcoin 0.32.8", ] [[package]] @@ -201,53 +335,61 @@ name = "miniscript" version = "13.0.0" dependencies = [ "bech32", - "bitcoin", - "hex-conservative 1.0.0", - "secp256k1", + "bitcoin 0.33.0-beta", + "hex-conservative 1.0.1", + "secp256k1 0.32.0-beta.2", "serde", "serde_test", ] [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" 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.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" 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,18 +397,30 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom", ] [[package]] name = "regex" -version = "1.7.3" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -275,60 +429,88 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "secp256k1" -version = "0.29.0" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +dependencies = [ + "bitcoin_hashes 0.14.1", + "secp256k1-sys 0.10.1", +] + +[[package]] +name = "secp256k1" +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", + "secp256k1-sys 0.12.0", "serde", ] [[package]] name = "secp256k1-sys" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + +[[package]] +name = "secp256k1-sys" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d3be00697c88c00fe102af8dc316038cc2062eab8da646e7463f4c0e70ca9fd" dependencies = [ "cc", ] [[package]] name = "semver" -version = "1.0.22" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" -version = "1.0.199" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.199" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -337,18 +519,24 @@ dependencies = [ [[package]] name = "serde_test" -version = "1.0.176" +version = "1.0.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab" +checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "syn" -version = "2.0.56" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2415488199887523e74fd9a5f7be804dfd42d868ae0eca382e3917094d210e" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -357,12 +545,41 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen", +] [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wit-bindgen" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo-recent.lock b/Cargo-recent.lock index 91a74f3b2..5f0741905 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "base58ck" @@ -23,124 +23,257 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" dependencies = [ - "bitcoin-internals", - "bitcoin_hashes", + "bitcoin-internals 0.3.0", + "bitcoin_hashes 0.14.1", +] + +[[package]] +name = "base58ck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6a87a8367e7a4248c8dfd783c37ef492bca1307cd4b21b4cfad9cfd15bf060" +dependencies = [ + "bitcoin-internals 0.5.0", + "bitcoin_hashes 0.20.0", ] [[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" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" +checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f" [[package]] name = "bitcoin" -version = "0.32.6" +version = "0.32.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8929a18b8e33ea6b3c09297b687baaa71fb1b97353243a3f1029fad5c59c5b" +checksum = "1e499f9fc0407f50fe98af744ab44fa67d409f76b6772e1689ec8485eb0c0f66" dependencies = [ - "base58ck", - "base64", + "base58ck 0.1.0", "bech32", - "bitcoin-internals", - "bitcoin-io", - "bitcoin-units", - "bitcoin_hashes", - "hex-conservative 0.2.1", + "bitcoin-internals 0.3.0", + "bitcoin-io 0.1.4", + "bitcoin-units 0.1.2", + "bitcoin_hashes 0.14.1", + "hex-conservative 0.2.2", "hex_lit", - "secp256k1", + "secp256k1 0.29.1", +] + +[[package]] +name = "bitcoin" +version = "0.33.0-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "517161def4ca8527bfc4ba36efe5b40923024f73308a1f9c0fc5cca1bee2f536" +dependencies = [ + "base58ck 0.4.0", + "base64", + "bech32", + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "bitcoin-io 0.5.0", + "bitcoin-network-kind", + "bitcoin-primitives", + "bitcoin-units 0.3.0", + "bitcoin_hashes 0.20.0", + "bitcoinconsensus", + "hex-conservative 0.3.2", + "hex-conservative 1.0.1", + "secp256k1 0.32.0-beta.2", "serde", ] +[[package]] +name = "bitcoin-consensus-encoding" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d7ca3dc8ff835693ad73bf1596240c06f974a31eeb3f611aaedf855f1f2725" +dependencies = [ + "bitcoin-internals 0.5.0", +] + [[package]] name = "bitcoin-internals" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" + +[[package]] +name = "bitcoin-internals" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a30a22d1f112dde8e16be7b45c63645dc165cef254f835b3e1e9553e485cfa64" dependencies = [ + "hex-conservative 0.3.2", "serde", ] [[package]] name = "bitcoin-io" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e5b76b88667412087beea1882980ad843b660490bbf6cce0a6cfc999c5b989" +checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" [[package]] -name = "bitcoin-units" +name = "bitcoin-io" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6fb823712b12e5cfccdb9a2b6a62de2dc42ddb5ec489511025eebeba1c21829" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "bitcoin_hashes 0.20.0", +] + +[[package]] +name = "bitcoin-network-kind" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d437fd727271c866d6fd5e71eb2c886437d4c97f80d89246be3189b1da4e58b" +checksum = "f85911fdff634a2e65f8175a54e609172a718d385ab4da87937f166d37eef4a3" dependencies = [ - "bitcoin-internals", + "bitcoin-internals 0.5.0", + "serde", +] + +[[package]] +name = "bitcoin-primitives" +version = "0.102.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48379e4d9a4456c038d78551ccbb8a3d7f9514c799f51ae815a6e947d64c9efe" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "bitcoin-units 0.3.0", + "bitcoin_hashes 0.20.0", + "hex-conservative 0.3.2", + "hex-conservative 1.0.1", + "serde", +] + +[[package]] +name = "bitcoin-units" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +dependencies = [ + "bitcoin-internals 0.3.0", +] + +[[package]] +name = "bitcoin-units" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fe8fafd73be14659c450deb64f90d2fd5a354fce366a01223a8319cf4d98b40" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", "serde", ] [[package]] name = "bitcoin_hashes" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" dependencies = [ - "bitcoin-io", - "hex-conservative 0.2.1", + "bitcoin-io 0.1.4", + "hex-conservative 0.2.2", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8a45c2b41c457a9a9e4670422fcbdf109afb3b22bc920b4045e8bdfd788a3d" +dependencies = [ + "bitcoin-consensus-encoding", + "bitcoin-internals 0.5.0", + "hex-conservative 0.3.2", "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" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" +dependencies = [ + "find-msvc-tools", + "shlex", +] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "descriptor-fuzz" version = "0.0.1" dependencies = [ "honggfuzz", - "miniscript 12.3.0", + "miniscript 12.3.5", "miniscript 13.0.0", "regex", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" +dependencies = [ + "arrayvec", ] [[package]] name = "hex-conservative" -version = "0.2.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +checksum = "830e599c2904b08f0834ee6337d8fe8f0ed4a63b5d9e7a7f49c0ffa06d08d360" dependencies = [ "arrayvec", ] [[package]] name = "hex-conservative" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee770c000993d17c185713463d5ebfbd1af9afae4c17cc295640104383bfbf0" +checksum = "366fa3443ac84474447710ec17bb00b05dfbd096137817981e86f992f21a2793" [[package]] name = "hex_lit" @@ -150,50 +283,51 @@ checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" [[package]] name = "honggfuzz" -version = "0.5.56" +version = "0.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c76b6234c13c9ea73946d1379d33186151148e0da231506b964b44f3d023505" +checksum = "4d6510a410acedd7a7683b3a45dafdc5ccf3c72d6addaa373497005964fc4e23" dependencies = [ "lazy_static", "memmap2", "rustc_version", + "semver", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" dependencies = [ "libc", ] [[package]] name = "miniscript" -version = "12.3.0" +version = "12.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd3c9608217b0d6fa9c9c8ddd875b85ab72bd4311cfc8db35e1b5a08fc11f4d" +checksum = "487906208f38448e186e3deb02f2b8ef046a9078b0de00bdb28bf4fb9b76951c" dependencies = [ "bech32", - "bitcoin", + "bitcoin 0.32.8", ] [[package]] @@ -201,53 +335,61 @@ name = "miniscript" version = "13.0.0" dependencies = [ "bech32", - "bitcoin", - "hex-conservative 1.0.0", - "secp256k1", + "bitcoin 0.33.0-beta", + "hex-conservative 1.0.1", + "secp256k1 0.32.0-beta.2", "serde", "serde_test", ] [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" 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.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" 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,18 +397,30 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom", ] [[package]] name = "regex" -version = "1.7.3" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -275,60 +429,88 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "secp256k1" -version = "0.29.0" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +dependencies = [ + "bitcoin_hashes 0.14.1", + "secp256k1-sys 0.10.1", +] + +[[package]] +name = "secp256k1" +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", + "secp256k1-sys 0.12.0", "serde", ] [[package]] name = "secp256k1-sys" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + +[[package]] +name = "secp256k1-sys" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d3be00697c88c00fe102af8dc316038cc2062eab8da646e7463f4c0e70ca9fd" dependencies = [ "cc", ] [[package]] name = "semver" -version = "1.0.22" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" -version = "1.0.199" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.199" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -337,18 +519,24 @@ dependencies = [ [[package]] name = "serde_test" -version = "1.0.176" +version = "1.0.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab" +checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "syn" -version = "2.0.56" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2415488199887523e74fd9a5f7be804dfd42d868ae0eca382e3917094d210e" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -357,12 +545,41 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen", +] [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wit-bindgen" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 1a5f8d039..80cde86fb 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 = { version = "0.33.0-beta", 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 = { version = "0.33.0-beta", features = ["base64"] } +secp256k1 = { version = "0.32.0-beta.2", features = ["rand", "global-context"] } [[example]] name = "htlc" diff --git a/examples/big.rs b/examples/big.rs index a5057937b..9e5224fa3 100644 --- a/examples/big.rs +++ b/examples/big.rs @@ -20,7 +20,6 @@ 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 +38,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 +50,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..b49664b2a 100644 --- a/examples/psbt_sign_finalize.rs +++ b/examples/psbt_sign_finalize.rs @@ -3,20 +3,19 @@ use std::collections::BTreeMap; use std::str::FromStr; +use miniscript::bitcoin::blockdata::witness::Witness; use miniscript::bitcoin::consensus::encode::deserialize_hex; use miniscript::bitcoin::psbt::{self, Psbt}; use miniscript::bitcoin::sighash::SighashCache; +use miniscript::bitcoin::ScriptPubKey; //use miniscript::bitcoin::secp256k1; // https://github.com/rust-lang/rust/issues/121684 use miniscript::bitcoin::{ - transaction, Address, Amount, Network, OutPoint, PrivateKey, Script, Sequence, Transaction, - TxIn, TxOut, + 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 +30,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 +81,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(amount / 5 - 500).expect("in range"), }); - 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(amount * 4 / 5).expect("in range"), }); // Generating signatures & witness data @@ -118,18 +118,18 @@ fn main() { // Fixme: Take a parameter let hash_ty = bitcoin::sighash::EcdsaSighashType::All; - let sk1 = backup1_private.inner; - let sk2 = backup2_private.inner; + let sk1 = *backup1_private.as_inner(); + let sk2 = *backup2_private.as_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.to_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.to_inner()).is_ok()); psbt.inputs[0] .partial_sigs @@ -138,7 +138,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 +146,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() { - if spk == &txout.script_pubkey { - return (OutPoint::new(tx.compute_txid(), i as u32), txout); +fn get_vout(tx: &Transaction, spk: &ScriptPubKey) -> (OutPoint, TxOut) { + for (i, txout) in tx.clone().outputs.into_iter().enumerate() { + if spk == AsRef::::as_ref(&txout.script_pubkey) { + return (OutPoint { txid: tx.compute_txid(), vout: i as u32 }, 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..86ec9f9dd 100644 --- a/examples/sign_multisig.rs +++ b/examples/sign_multisig.rs @@ -6,7 +6,8 @@ use std::collections::HashMap; use std::str::FromStr; use bitcoin::blockdata::witness::Witness; -use bitcoin::{absolute, ecdsa, transaction, Amount, Sequence}; +use bitcoin::{absolute, ecdsa, transaction, Amount, OutPoint, Sequence}; +use miniscript::bitcoin::script::ScriptPubKeyBuf as ScriptBuf; fn main() { let mut tx = spending_transaction(); @@ -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: OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::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: ScriptBuf::new(), + amount: Amount::from_sat(100_000_000).expect("in range"), }], } } diff --git a/examples/taproot.rs b/examples/taproot.rs index aea13f6ce..08cd78930 100644 --- a/examples/taproot.rs +++ b/examples/taproot.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use std::str::FromStr; use miniscript::bitcoin::key::{Keypair, XOnlyPublicKey}; -use miniscript::bitcoin::secp256k1::rand; +use miniscript::bitcoin::secp256k1::{self, rand}; use miniscript::bitcoin::{Network, WitnessVersion}; use miniscript::descriptor::DescriptorType; use miniscript::policy::Concrete; @@ -86,10 +86,10 @@ 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 _secp = secp256k1::Secp256k1::new(); + let key_pair = Keypair::from_secp(secp256k1::Keypair::new(&mut rand::rng())); // Random unspendable XOnlyPublicKey provided for compilation to Taproot Descriptor - let (unspendable_pubkey, _parity) = XOnlyPublicKey::from_keypair(&key_pair); + let unspendable_pubkey = XOnlyPublicKey::from_keypair(&key_pair); pk_map.insert("UNSPENDABLE_KEY".to_string(), unspendable_pubkey); let pubkeys = hardcoded_xonlypubkeys(); @@ -142,7 +142,11 @@ fn hardcoded_xonlypubkeys() -> Vec { ]; let mut keys: Vec = vec![]; for key in serialized_keys { - keys.push(XOnlyPublicKey::from_slice(&key).unwrap()); + keys.push( + secp256k1::XOnlyPublicKey::from_byte_array(key) + .unwrap() + .into(), + ); } 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 5248bb689..edc096a95 100644 --- a/examples/taptree_of_horror/taptree_of_horror.rs +++ b/examples/taptree_of_horror/taptree_of_horror.rs @@ -1,9 +1,9 @@ use std::str::FromStr; use bitcoin::absolute::LockTime; +use bitcoin::blockdata::witness::Witness; use bitcoin::consensus::encode::serialize; -use bitcoin::hashes::Hash; -use bitcoin::hex::{Case, DisplayHex}; +use bitcoin::hashes::hex::prelude::DisplayHex; use bitcoin::transaction::Version; use bitcoin::{Address, Amount, Network, Psbt, PublicKey, Sequence, TxIn, TxOut}; use helper_fns::{produce_grim_hash, produce_kelly_hash, produce_key_pairs}; @@ -16,8 +16,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 @@ -59,8 +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(); + let internal_xpub: miniscript::DescriptorPublicKey = 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,18 @@ 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 (s_pks, _s_prvs) = - produce_key_pairs(s_descriptor_desc_secret, secp, normal_path, "s_backup1"); - let (x_pks, _x_prvs) = - produce_key_pairs(x_descriptor_desc_secret, secp, normal_path, "x_backup2"); + 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, normal_path, "s_backup1"); + let (x_pks, _x_prvs) = 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 +197,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 +204,20 @@ 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(100_000_000).expect("in range"); 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(99_999_000).expect("in range"), script_pubkey: destination_address.assume_checked().script_pubkey(), }; @@ -232,12 +225,12 @@ 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], + lock_time: LockTime::from_mtp(time).unwrap(), + inputs: vec![tx_in], + outputs: vec![destination_output], }; - let unsigned_tx_test_string = serialize(&unsigned_tx).to_hex_string(Case::Lower); + let unsigned_tx_test_string = serialize(&unsigned_tx).to_lower_hex_string(); assert!(unsigned_tx_test_string == "0200000001ffffffffeeeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa99999999888888880000000000000000000118ddf5050000000022512052fe7176190833196b7eb9aab6ec029b5ad1d1dd2f108f85a246672732aa1d9d60011967"); let mut psbt = Psbt::from_unsigned_tx(unsigned_tx).unwrap(); @@ -253,16 +246,16 @@ fn main() { //let _res = psbt.sign(&intneral_xpriv.xkey, secp).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,11 +266,11 @@ 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(); - let raw_tx = bitcoin::consensus::encode::serialize(&signed_tx).to_hex_string(Case::Lower); + let raw_tx = bitcoin::consensus::encode::serialize(&signed_tx).to_lower_hex_string(); assert!(raw_tx == "02000000000101ffffffffeeeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa99999999888888880000000000000000000118ddf5050000000022512052fe7176190833196b7eb9aab6ec029b5ad1d1dd2f108f85a246672732aa1d9d0e209250ecce1169d94cf17baaecddcef779ff1b0d07d347d24afcd5b2231f95a500209562ef4e826d891eaa72f2cee753b80a3f7f6b5aed07b850227e83546fa6185740a5da084901627205e860d6530ff5ff580fc3841b779ad8535ffd7b466664aa0280c218aa05a1054c73b1f717b6c5badf70e71e5091b4b34e25ec3584243fd0604032a0bad48af9b3263d331ba2c789a931af81755c67dfefab28f8e40658545e6659eeb93d2c501ac79914ca82f4dbdcd669d34c7de73b4c243400926cffeb42b640015f5b58eb820676382521bb38b9d0c16d40c6a1b710242232d3d8276145aee859667d3caf9b72acecbfa3be33ce7afb9bda70b19451c58550bb1076125463c240ba0ba063d92ef71a35a1bdbd41b165d71825d6b5d9555781a3a6c35aba5864c82c4e53a7656458dc8bd586a6de749b6ab59cbb5ec4e2264a185ef7b79db3ea9c408176c65f6486f5c9a7d466fe86dfed7d55f8fc480b5843414696842f1efc689e74fce36a0b318535ef86864d8f83ac4bb60085c2b45c0547b9657def51b52b8e40b5f95b03c77b685314848a292d05bf350cdad506bcb2601b634779e956235aef3bade98a812f046d47060fbf9965ac0ef016e6ef09540c1c7d5b2fe447192cbd405ea9e1a58685ef958db8aa529d3fbfcc1182e252a35715bf9b2c35a30c73e718a65e8a8c0141eaac72af71a1dd7f19c53aaead75ae5b963a4eee5d1228c389844094a38c8574e6089c33d2c37d6f889adb671ef09a188e91cf032e97a3e25e9636901096e1cc92d17fbf4c581e5a1915de53f807f3198f4a2b829fc3a4479f6bb54017e68b70fd9e5c94c6f99abf284f5da42365a2e5fd4f0971bf5cb68aea3408c0d05ace043c15e70958c73f7455db3a22e3e5fb0240749a9dc52aa66a554fb06b40c478230871c12b60bc7cae151e411aa779780a8e6a7afd57aa763185809259fc7853f65e712d1ef178d4750f66e1b6db3cae7efcec5308b815b39fe8498f404afd9c0120fe88003d0bcb15d1628edff84046255758baf205d42ce460b6fb4595b983f2ecad20eecd6dba68fd0ec5d4baa0052db8084cb15a55503b78cfee5ef31c35cd98d846ad20529c1e24d86bf35b35133a81bf1e8c21759f3a83cfb38f18eae1d5b8292ff4bead2083835dbe036944f18783e0a525babe23965a2b4fdeca2d2d84997fc6ff0fb06aad204aeb360d05ad743b838ad27c56b78f08668aeba77f2f1fc439ac80f970e57328ad2062c4d094ce7a28414102bacccb06947053e07e4da53ad96e5724565f09436dfcad20f6e5c74176d69d44a97220a694237d8e719fae4a029942aadb28a9b491b40e31ad20dc7ea580c6887971614260d91069c4d398cc80ecc6cbb4ab59099e110ad3bb8bad2059fa3dfd7286d59f9b3853fb0cdd13c4760508f672435be40057b9e02eb937bdad20aa90f13a1c98abc5620d3f379d20b8c28ddf8f46772a0d0af6b7deb7bf3a1ee1ad82012088a8202db9cdb5e102541f19b455fa798e0cb009f5faa6358b9d3507858caf797bca418882012088a6148d60757ec290d055be92da400cff617b0423cb14880460011967b141c1259b7a61aa66c551a6cd35ccc35e9e011ecbbddbbb673acba71e2e4cc11e8883326f8afc8b0ef3f1cc0428893a40e48b9419807a4fd8f8673b62840ef216d5f660011967"); } diff --git a/examples/verify_tx.rs b/examples/verify_tx.rs index f2a63f447..7d3807f9d 100644 --- a/examples/verify_tx.rs +++ b/examples/verify_tx.rs @@ -5,6 +5,7 @@ use std::str::FromStr; use miniscript::bitcoin::consensus::Decodable; +use miniscript::bitcoin::script::ScriptPubKeyBuf as ScriptBuf; use miniscript::bitcoin::secp256k1::Secp256k1; use miniscript::bitcoin::{absolute, sighash, Sequence}; use miniscript::interpreter::KeySigPair; @@ -17,10 +18,12 @@ fn main() { let tx = hard_coded_transaction(); let spk_input_1 = hard_coded_script_pubkey(); + let script_sig_as_spk = + bitcoin::script::ScriptPubKey::from_bytes(tx.inputs[0].script_sig.as_bytes()); let interpreter = miniscript::Interpreter::from_txdata( &spk_input_1, - &tx.input[0].script_sig, - &tx.input[0].witness, + script_sig_as_spk, + &tx.inputs[0].witness, Sequence::ZERO, absolute::LockTime::ZERO, ) @@ -63,13 +66,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,15 +84,13 @@ fn main() { // // Same, but with the wrong signature hash, to demonstrate what happens // given an apparently invalid script. - let secp = Secp256k1::new(); + 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) - .is_ok() + && ecdsa_sig.signature.verify(message, &pk.to_inner()).is_ok() })); println!("\n\nExample three:\n"); @@ -161,8 +161,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() -> ScriptBuf { + ScriptBuf::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 d7be9cc4f..d0b7d8109 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,28 +11,25 @@ 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(); // P2TR with xpubs in sortedmulti_a - let _ = p2tr_sortedmulti_a(&secp); + let _ = p2tr_sortedmulti_a(); } /// 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(); @@ -48,14 +44,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(); @@ -69,7 +65,7 @@ fn p2sh_p2wsh(secp: &Secp256k1) -> Address { } /// Parses a P2TR sortedmulti_a descriptor, returns the associated address. -fn p2tr_sortedmulti_a(secp: &Secp256k1) -> Address { +fn p2tr_sortedmulti_a() -> Address { let internal = "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"; // It does not matter what order the two xpubs go in, the same address will be generated. let s1 = format!("tr({},sortedmulti_a(2,{}/1/0/*,{}/0/0/*))", internal, XPUB_1, XPUB_2); @@ -80,7 +76,7 @@ fn p2tr_sortedmulti_a(secp: &Secp256k1) -> Address { .map(|s| { Descriptor::::from_str(&s) .unwrap() - .derived_descriptor(secp, 5) + .derived_descriptor(5) .unwrap() .address(Network::Bitcoin) .unwrap() diff --git a/fuzz/fuzz_targets/miniscript_satisfy.rs b/fuzz/fuzz_targets/miniscript_satisfy.rs index d22bde00c..157f213c8 100644 --- a/fuzz/fuzz_targets/miniscript_satisfy.rs +++ b/fuzz/fuzz_targets/miniscript_satisfy.rs @@ -26,8 +26,7 @@ impl Satisfier for FuzzSatisfier<'_> { fn lookup_tap_key_spend_sig(&self, _: &FuzzPk) -> Option { let b = self.read_byte()?; if b & 1 == 1 { - // FIXME in later version of rust-secp we can use from_byte_array - let secp_sig = secp256k1::schnorr::Signature::from_slice(&[0xab; 64]).unwrap(); + let secp_sig = secp256k1::schnorr::Signature::from_byte_array([0xab; 64]); Some(Signature { signature: secp_sig, sighash_type: TapSighashType::Default }) } else { None @@ -74,7 +73,7 @@ impl Satisfier for FuzzSatisfier<'_> { fn lookup_raw_pkh_x_only_pk(&self, h: &hash160::Hash) -> Option { self.lookup_raw_pkh_pk(h) - .map(|pk| pk.inner.x_only_public_key().0) + .map(|pk| XOnlyPublicKey::from(pk.to_inner().x_only_public_key().0)) } // todo diff --git a/fuzz/fuzz_targets/parse_descriptor_priv.rs b/fuzz/fuzz_targets/parse_descriptor_priv.rs index 98bfb992c..41c22720d 100644 --- a/fuzz/fuzz_targets/parse_descriptor_priv.rs +++ b/fuzz/fuzz_targets/parse_descriptor_priv.rs @@ -1,14 +1,12 @@ #![allow(unexpected_cfgs)] use honggfuzz::fuzz; -use miniscript::bitcoin::secp256k1; 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/fuzz/fuzz_targets/regression_taptree.rs b/fuzz/fuzz_targets/regression_taptree.rs index ab50d06bd..8afe74eea 100644 --- a/fuzz/fuzz_targets/regression_taptree.rs +++ b/fuzz/fuzz_targets/regression_taptree.rs @@ -14,36 +14,58 @@ fn do_test(data: &[u8]) { (Ok(new), Ok(old)) => { let new_si = new.spend_info(); let old_si = old.spend_info(); + // The old and new crates each carry their own copy of `bitcoin` types, so we can't + // compare the typed values directly. Compare their serialized byte representations + // instead. + // `internal_key()` yields an `UntweakedPublicKey` in both crates, but since new + // bitcoin's `XOnlyPublicKey::serialize()` returns `([u8; 32], Parity)` while the old + // one returns `[u8; 32]`, discard the parity on the new side to compare x-coords. assert_eq!( - old_si.internal_key(), - new_si.internal_key(), - "merkle root mismatch (left is old, new is right)", + old_si.internal_key().serialize(), + new_si.internal_key().serialize().0, + "internal key mismatch (left is old, new is right)", ); assert_eq!( - old_si.merkle_root(), - new_si.merkle_root(), + old_si.merkle_root().as_ref().map(|h| { + use old_miniscript::bitcoin::hashes::Hash as _; + h.to_byte_array() + }), + new_si.merkle_root().as_ref().map(|h| h.to_byte_array()), "merkle root mismatch (left is old, new is right)", ); assert_eq!( - old_si.output_key(), - new_si.output_key(), - "merkle root mismatch (left is old, new is right)", + old_si.output_key().serialize(), + new_si.output_key().serialize(), + "output key mismatch (left is old, new is right)", ); - // Map every leaf script to a set of all the control blocks - let mut new_cbs = HashMap::new(); + // Map every leaf script to a set of all the control blocks (keyed by script bytes). + let mut new_cbs: HashMap, HashSet>> = HashMap::new(); for leaf in new_si.leaves() { new_cbs - .entry(leaf.script()) - .or_insert(HashSet::new()) - .insert(leaf.control_block().clone()); + .entry(leaf.script().to_vec()) + .or_default() + .insert(leaf.control_block().serialize()); } // ...the old code will only ever yield one of them and it's not easy to predict which one for leaf in new_si.leaves() { - let old_cb = old_si - .control_block(&(leaf.script().into(), leaf.leaf_version())) - .unwrap(); - assert!(new_cbs[leaf.script()].contains(&old_cb)); + let old_cb_bytes = { + use old_miniscript::bitcoin::taproot::LeafVersion; + let leaf_bytes: Vec = leaf.script().to_vec(); + let script_buf = + old_miniscript::bitcoin::ScriptBuf::from_bytes(leaf_bytes.clone()); + let leaf_ver = LeafVersion::from_consensus( + miniscript::bitcoin::taproot::LeafVersion::to_consensus( + leaf.leaf_version(), + ), + ) + .expect("valid leaf version"); + old_si + .control_block(&(script_buf, leaf_ver)) + .unwrap() + .serialize() + }; + assert!(new_cbs[&leaf.script().to_vec()].contains(&old_cb_bytes)); } } } diff --git a/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs b/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs index 7dd16fc9c..8e010051e 100644 --- a/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs +++ b/fuzz/fuzz_targets/roundtrip_miniscript_script_tap.rs @@ -1,17 +1,16 @@ #![allow(unexpected_cfgs)] use honggfuzz::fuzz; -use miniscript::bitcoin::blockdata::script; use miniscript::{Miniscript, Tap}; fn do_test(data: &[u8]) { // Try round-tripping as a script - let script = script::Script::from_bytes(data); + let script = miniscript::bitcoin::script::ScriptPubKey::from_bytes(data); - if let Ok(pt) = Miniscript::::decode(script) { - let output = pt.encode(); + if let Ok(pt) = Miniscript::::decode(script) { + let output: miniscript::bitcoin::script::ScriptPubKeyBuf = pt.encode(); assert_eq!(pt.script_size(), output.len()); - assert_eq!(&output, script); + assert_eq!(output.as_bytes(), script.as_bytes()); } } diff --git a/fuzz/src/lib.rs b/fuzz/src/lib.rs index 616dc2254..8951aa291 100644 --- a/fuzz/src/lib.rs +++ b/fuzz/src/lib.rs @@ -7,8 +7,7 @@ use core::{fmt, str}; -use miniscript::bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; -use miniscript::bitcoin::{secp256k1, PublicKey}; +use miniscript::bitcoin::hashes::{hash160, ripemd160, sha256}; use miniscript::{hash256, MiniscriptKey, ToPublicKey}; /// A public key which is encoded as a single hex byte (two hex characters). @@ -46,7 +45,8 @@ impl MiniscriptKey for FuzzPk { } impl ToPublicKey for FuzzPk { - fn to_public_key(&self) -> PublicKey { + fn to_public_key(&self) -> miniscript::bitcoin::PublicKey { + use miniscript::bitcoin::secp256k1; let secp_pk = secp256k1::PublicKey::from_slice(&[ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce, 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, @@ -55,14 +55,16 @@ impl ToPublicKey for FuzzPk { 0xfc, 0x07, 0x00, 0xca, 0x10, 0x0e, 0x59, 0xdd, 0xf3, ]) .unwrap(); - PublicKey { inner: secp_pk, compressed: self.compressed } + if self.compressed { + miniscript::bitcoin::PublicKey::from_secp(secp_pk) + } else { + miniscript::bitcoin::PublicKey::from_secp_uncompressed(secp_pk) + } } fn to_sha256(hash: &Self::Sha256) -> sha256::Hash { sha256::Hash::from_byte_array([*hash; 32]) } - fn to_hash256(hash: &Self::Hash256) -> hash256::Hash { - hash256::Hash::from_byte_array([*hash; 32]) - } + fn to_hash256(hash: &Self::Hash256) -> hash256::Hash { hash256::Hash::hash(&[*hash; 32]) } fn to_ripemd160(hash: &Self::Ripemd160) -> ripemd160::Hash { ripemd160::Hash::from_byte_array([*hash; 20]) @@ -81,7 +83,8 @@ impl old_miniscript::MiniscriptKey for FuzzPk { } impl old_miniscript::ToPublicKey for FuzzPk { - fn to_public_key(&self) -> PublicKey { + fn to_public_key(&self) -> old_miniscript::bitcoin::PublicKey { + use old_miniscript::bitcoin::secp256k1; let secp_pk = secp256k1::PublicKey::from_slice(&[ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x78, 0xce, 0x56, 0x3f, 0x89, 0xa0, 0xed, 0x94, 0x14, 0xf5, 0xaa, 0x28, 0xad, 0x0d, 0x96, @@ -90,20 +93,26 @@ impl old_miniscript::ToPublicKey for FuzzPk { 0xfc, 0x07, 0x00, 0xca, 0x10, 0x0e, 0x59, 0xdd, 0xf3, ]) .unwrap(); - PublicKey { inner: secp_pk, compressed: self.compressed } + old_miniscript::bitcoin::PublicKey { inner: secp_pk, compressed: self.compressed } } - fn to_sha256(hash: &Self::Sha256) -> sha256::Hash { sha256::Hash::from_byte_array([*hash; 32]) } + fn to_sha256(hash: &Self::Sha256) -> old_miniscript::bitcoin::hashes::sha256::Hash { + use old_miniscript::bitcoin::hashes::Hash as _; + old_miniscript::bitcoin::hashes::sha256::Hash::from_byte_array([*hash; 32]) + } fn to_hash256(hash: &Self::Hash256) -> old_miniscript::hash256::Hash { + use old_miniscript::bitcoin::hashes::Hash as _; old_miniscript::hash256::Hash::from_byte_array([*hash; 32]) } - fn to_ripemd160(hash: &Self::Ripemd160) -> ripemd160::Hash { - ripemd160::Hash::from_byte_array([*hash; 20]) + fn to_ripemd160(hash: &Self::Ripemd160) -> old_miniscript::bitcoin::hashes::ripemd160::Hash { + use old_miniscript::bitcoin::hashes::Hash as _; + old_miniscript::bitcoin::hashes::ripemd160::Hash::from_byte_array([*hash; 20]) } - fn to_hash160(hash: &Self::Ripemd160) -> hash160::Hash { - hash160::Hash::from_byte_array([*hash; 20]) + fn to_hash160(hash: &Self::Ripemd160) -> old_miniscript::bitcoin::hashes::hash160::Hash { + use old_miniscript::bitcoin::hashes::Hash as _; + old_miniscript::bitcoin::hashes::hash160::Hash::from_byte_array([*hash; 20]) } } diff --git a/src/benchmarks.rs b/src/benchmarks.rs index 52823186c..6079c637f 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::new(sk.public_key()); DescriptorPublicKey::Single(SinglePub { origin: None, key: SinglePubKey::FullKey(pk) }) } diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index b41ee2850..8dacd8896 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::{PushBytes, ScriptPubKeyBuf}; +use bitcoin::{Address, Network, Weight}; use crate::descriptor::{write_descriptor, DefiniteDescriptorKey}; use crate::expression::{self, FromTree}; @@ -103,18 +103,21 @@ 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>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -127,7 +130,10 @@ 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>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -267,7 +273,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,25 +286,28 @@ 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>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { if let Some(sig) = satisfier.lookup_ecdsa_sig(&self.pk) { - let script_sig = script::Builder::new() + let script_sig = bitcoin::script::Builder::::new() .push_slice::<&PushBytes>( // 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 +319,10 @@ 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>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index ff856f89d..7170a8327 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -6,11 +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::hashes::{hash160, ripemd160, sha256, HashEngine}; use bitcoin::key::{PublicKey, XOnlyPublicKey}; -use bitcoin::secp256k1::{Secp256k1, Signing, Verification}; -use bitcoin::NetworkKind; +use bitcoin::{bip32, NetworkKind}; use super::WalletPolicyError; use crate::prelude::*; @@ -167,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 /// @@ -176,17 +174,13 @@ pub trait InnerXKey: fmt::Display + FromStr { } impl InnerXKey for bip32::Xpub { - fn xkey_fingerprint(&self, _secp: &Secp256k1) -> bip32::Fingerprint { - self.fingerprint() - } + fn xkey_fingerprint(&self) -> bip32::Fingerprint { self.fingerprint() } fn can_derive_hardened() -> bool { false } } 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 } } @@ -214,8 +208,8 @@ impl fmt::Display for 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) } } @@ -228,10 +222,7 @@ 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( - &self, - secp: &Secp256k1, - ) -> Result, DescriptorKeyParseError> { + fn to_public(&self) -> Result, DescriptorKeyParseError> { let unhardened = self .derivation_path .into_iter() @@ -245,17 +236,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, }; @@ -274,10 +265,7 @@ 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( - &self, - secp: &Secp256k1, - ) -> Result, DescriptorKeyParseError> { + fn to_public(&self) -> Result, DescriptorKeyParseError> { let deriv_paths = self.derivation_paths.paths(); let shared_prefix: Vec<_> = deriv_paths[0] @@ -320,16 +308,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, }; @@ -379,6 +367,26 @@ impl fmt::Display for NonDefiniteKeyError { #[cfg(feature = "std")] impl error::Error for NonDefiniteKeyError {} +/// Error parsing the hex string of a master key fingerprint. +/// +/// The underlying `Fingerprint::from_hex` surfaces its error from an unstable +/// `hex-conservative` version that is not re-exported from `bitcoin`, so we +/// capture its textual representation and expose it as a proper [`error::Error`]. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct MasterFingerprintHexError(String); + +impl MasterFingerprintHexError { + /// Construct from any displayable source error. + pub fn from_display(err: E) -> Self { Self(err.to_string()) } +} + +impl fmt::Display for MasterFingerprintHexError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.0) } +} + +#[cfg(feature = "std")] +impl error::Error for MasterFingerprintHexError {} + /// Kinds of malformed key data #[derive(Debug, PartialEq, Eq, Clone)] #[non_exhaustive] @@ -432,20 +440,20 @@ pub enum DescriptorKeyParseError { /// The invalid index index: String, /// The underlying parse error - err: bip32::Error, + err: bip32::ParseChildNumberError, }, /// 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::ParseChildNumberError), /// Error indicating a malformed master fingerprint (invalid hex). MasterFingerprint { /// The invalid fingerprint fingerprint: String, - /// The underlying parse error - err: bitcoin::hex::HexToArrayError, + /// The underlying hex parse error. + err: MasterFingerprintHexError, }, /// Attempt to construct a [`DefiniteDescriptorKey`] from an ambiguous key. NonDefiniteKey(NonDefiniteKeyError), @@ -453,8 +461,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), /// XKey parsing error XKeyParseError(XKeyParseError), } @@ -484,9 +492,9 @@ impl fmt::Display for DescriptorKeyParseError { impl error::Error for DescriptorKeyParseError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match self { - Self::DerivationIndexError { err, .. } - | Self::DeriveHardenedKey(err) - | Self::MasterDerivationPath(err) => Some(err), + Self::DerivationIndexError { err, .. } => Some(err), + Self::DeriveHardenedKey(err) => Some(err), + Self::MasterDerivationPath(err) => Some(err), Self::MasterFingerprint { err, .. } => Some(err), Self::NonDefiniteKey(err) => Some(err), Self::FullPublicKey(err) => Some(err), @@ -501,7 +509,7 @@ impl error::Error for DescriptorKeyParseError { /// An error when parsing an extended key. #[derive(Debug, PartialEq, Eq, Clone)] pub enum XKeyParseError { - Bip32(bip32::Error), + Bip32(bip32::ParseError), Bip388(WalletPolicyError), } @@ -524,8 +532,8 @@ impl fmt::Display for XKeyParseError { } } -impl From for XKeyParseError { - fn from(err: bip32::Error) -> Self { Self::Bip32(err) } +impl From for XKeyParseError { + fn from(err: bip32::ParseError) -> Self { Self::Bip32(err) } } impl fmt::Display for DescriptorPublicKey { @@ -565,15 +573,12 @@ 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( - &self, - secp: &Secp256k1, - ) -> Result { + pub fn to_public(&self) -> 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()?) } }; @@ -759,17 +764,16 @@ impl DescriptorPublicKey { if let Some((fingerprint, _)) = single.origin { fingerprint } else { - let mut engine = XKeyIdentifier::engine(); + 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()), + SinglePubKey::XOnly(x_only_pk) => engine.input(&x_only_pk.serialize().0), }; + let hash = hash160::Hash::from_engine(engine); bip32::Fingerprint::from( - &XKeyIdentifier::from_engine(engine)[..4] - .try_into() - .expect("4 byte slice"), + &hash.as_byte_array()[..4].try_into().expect("4 byte slice"), ) } } @@ -1059,12 +1063,12 @@ fn parse_key_origin(s: &str) -> Result<(&str, Option), Descrip let parent_fingerprint = bip32::Fingerprint::from_hex(origin_id_hex).map_err(|err| { DescriptorKeyParseError::MasterFingerprint { fingerprint: origin_id_hex.to_owned(), - err, + err: MasterFingerprintHexError::from_display(err), } })?; let origin_path = raw_origin .map(bip32::ChildNumber::from_str) - .collect::>() + .collect::>() .map_err(DescriptorKeyParseError::MasterDerivationPath)?; let key = parts @@ -1215,8 +1219,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, @@ -1227,32 +1229,28 @@ 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( - &self, - keysource: &bip32::KeySource, - secp: &Secp256k1, - ) -> Option { + pub fn matches(&self, keysource: &bip32::KeySource) -> Option { let (fingerprint, path) = keysource; let (compare_fingerprint, compare_path) = match self.origin { @@ -1260,7 +1258,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::>(), ), }; @@ -1323,7 +1321,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, @@ -1333,9 +1331,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()) { - Ok(xpub) => bitcoin::PublicKey::new(xpub.public_key), - Err(bip32::Error::CannotDeriveFromHardenedKey) => { + Wildcard::None => match xpk.xkey.derive_pub(xpk.derivation_path.as_ref()) { + Ok(xpub) => bitcoin::PublicKey::from_secp(xpub.public_key), + Err(bip32::DerivationError::CannotDeriveHardenedChild) => { unreachable!("impossible by construction of DefiniteDescriptorKey") } Err(e) => unreachable!("cryptographically unreachable: {}", e), @@ -1410,10 +1408,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) - } + fn to_public_key(&self) -> bitcoin::PublicKey { self.derive_public_key() } fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash } @@ -1563,35 +1558,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"); @@ -1629,8 +1622,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); assert_eq!( @@ -1787,7 +1778,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()]); @@ -1806,16 +1797,14 @@ 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] @@ -1825,7 +1814,7 @@ mod test { .unwrap(); if let DescriptorSecretKey::Single(single) = secret_key { assert_eq!( - single.key.inner, + *single.key.as_inner(), "0C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D" .parse() .unwrap() diff --git a/src/descriptor/key_map.rs b/src/descriptor/key_map.rs index 3e193ec87..6f5bfbf3e 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,40 +100,33 @@ impl GetKey for KeyMap { impl GetKey for DescriptorSecretKey { type Error = GetKeyError; - fn get_key( - &self, - key_request: KeyRequest, - secp: &Secp256k1, - ) -> Result, Self::Error> { + fn get_key(&self, 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 = bitcoin::secp256k1::PublicKey::from_secret_key(&xpriv.private_key); - if public_key.inner.eq(&pk) { + if public_key.to_inner().eq(&pk) { Ok(Some(xpriv.to_priv())) } else { Ok(None) } } - ( - 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)? { + (DescriptorSecretKey::XPrv(descriptor_xkey), KeyRequest::Bip32(key_source)) => { + 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 +134,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 +151,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 +173,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 +183,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 +196,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 +214,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 +227,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 +247,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 +260,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 +283,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 +297,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 +309,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 +318,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 +327,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().to_inner().x_only_public_key().0; + let request = KeyRequest::XOnlyPubkey(bitcoin::XOnlyPublicKey::from(xonly_pk)); - 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 +374,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().to_inner().x_only_public_key().0; + let request_x = KeyRequest::XOnlyPubkey(bitcoin::XOnlyPublicKey::from(xonly_pk)); - 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 2ad51c838..2b61e9841 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -16,9 +16,8 @@ use core::ops::Range; use core::str::{self, FromStr}; use bitcoin::hashes::{hash160, ripemd160, sha256}; -use bitcoin::{ - secp256k1, Address, Network, Script, ScriptBuf, TxIn, Weight, Witness, WitnessVersion, -}; +use bitcoin::script::{ScriptPubKey, ScriptPubKeyBuf}; +use bitcoin::{Address, Network, TxIn, Weight, Witness, WitnessVersion}; use sync::Arc; use crate::expression::FromTree as _; @@ -440,7 +439,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(), @@ -458,14 +457,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) -> bitcoin::script::ScriptSigBuf { match *self { - Descriptor::Bare(_) => ScriptBuf::new(), - Descriptor::Pkh(_) => ScriptBuf::new(), - Descriptor::Wpkh(_) => ScriptBuf::new(), - Descriptor::Wsh(_) => ScriptBuf::new(), + Descriptor::Bare(_) => bitcoin::script::ScriptSigBuf::new(), + Descriptor::Pkh(_) => bitcoin::script::ScriptSigBuf::new(), + Descriptor::Wpkh(_) => bitcoin::script::ScriptSigBuf::new(), + Descriptor::Wsh(_) => bitcoin::script::ScriptSigBuf::new(), Descriptor::Sh(ref sh) => sh.unsigned_script_sig(), - Descriptor::Tr(_) => ScriptBuf::new(), + Descriptor::Tr(_) => bitcoin::script::ScriptSigBuf::new(), } } @@ -475,13 +474,17 @@ 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), } } @@ -493,13 +496,17 @@ impl Descriptor { /// /// # Errors /// If the descriptor is a taproot descriptor. - pub fn script_code(&self) -> Result { + 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), } } @@ -507,7 +514,10 @@ 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>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -524,7 +534,10 @@ 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>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -730,14 +743,13 @@ impl Descriptor { /// 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.derive_at_index(index).unwrap().derived_descriptor(&secp); - /// # assert_eq!(descriptor.derived_descriptor(&secp, index).unwrap(), derived_descriptor); + /// let derived_descriptor = descriptor.derive_at_index(index).unwrap().derived_descriptor(); + /// # assert_eq!(descriptor.derived_descriptor(index).unwrap(), derived_descriptor); /// ``` /// /// and is only here really here for backwards compatibility. @@ -751,31 +763,23 @@ impl Descriptor { /// This function will return an error for multi-path descriptors /// or if hardened derivation is attempted, #[allow(deprecated)] - 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, - s: &str, - ) -> Result<(Descriptor, KeyMap), Error> { - fn parse_key( - s: &str, - key_map: &mut KeyMap, - secp: &secp256k1::Secp256k1, - ) -> Result { + pub fn parse_descriptor(s: &str) -> Result<(Descriptor, KeyMap), Error> { + fn parse_key(s: &str, key_map: &mut KeyMap) -> 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) } @@ -789,16 +793,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 { @@ -887,14 +891,13 @@ 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> { if !self.has_wildcard() { - let concrete = self.into_definite()?.derived_descriptor(secp); + let concrete = self.into_definite()?.derived_descriptor(); if &concrete.script_pubkey() == script_pubkey { return Ok(Some((0, concrete))); } @@ -902,7 +905,7 @@ impl Descriptor { } for i in range { - let concrete = self.derive_at_index(i)?.derived_descriptor(secp); + let concrete = self.derive_at_index(i)?.derived_descriptor(); if &concrete.script_pubkey() == script_pubkey { return Ok(Some((i, concrete))); } @@ -1031,34 +1034,30 @@ impl Descriptor { /// 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.derive_at_index(0).unwrap().derived_descriptor(&secp); + /// let result = descriptor.derive_at_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( - &self, - secp: &secp256k1::Secp256k1, - ) -> Descriptor { - struct Derivator<'a, C: secp256k1::Verification>(&'a secp256k1::Secp256k1); + pub fn derived_descriptor(&self) -> Descriptor { + 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 @@ -1174,11 +1173,10 @@ pub(crate) use write_descriptor; mod tests { use core::convert::TryFrom; + use bitcoin::blockdata::opcodes; 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, ScriptExt as _, WitnessScriptExt as _}; use bitcoin::sighash::EcdsaSighashType; use bitcoin::{bip32, PublicKey, Sequence, XOnlyPublicKey}; @@ -1280,7 +1278,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, @@ -1295,7 +1293,7 @@ mod tests { .unwrap(); assert_eq!( pkh.script_pubkey(), - script::Builder::new() + bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_DUP) .push_opcode(opcodes::all::OP_HASH160) .push_slice( @@ -1320,7 +1318,7 @@ mod tests { .unwrap(); assert_eq!( wpkh.script_pubkey(), - script::Builder::new() + bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_PUSHBYTES_0) .push_slice( hash160::Hash::from_str("84e9ed95a38613f0527ff685a9928abe2d4754d4",) @@ -1342,7 +1340,7 @@ mod tests { .unwrap(); assert_eq!( shwpkh.script_pubkey(), - script::Builder::new() + bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_HASH160) .push_slice( hash160::Hash::from_str("f1c3b9a431134cb90a500ec06e0067cfa9b8bba7",) @@ -1365,7 +1363,7 @@ mod tests { .unwrap(); assert_eq!( sh.script_pubkey(), - script::Builder::new() + bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_HASH160) .push_slice( hash160::Hash::from_str("aa5282151694d3f2f32ace7d00ad38f927a33ac8",) @@ -1388,7 +1386,7 @@ mod tests { .unwrap(); assert_eq!( wsh.script_pubkey(), - script::Builder::new() + bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_PUSHBYTES_0) .push_slice( sha256::Hash::from_str( @@ -1415,7 +1413,7 @@ mod tests { .unwrap(); assert_eq!( shwsh.script_pubkey(), - script::Builder::new() + bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_HASH160) .push_slice( hash160::Hash::from_str("4bec5d7feeed99e1d0a23fe32a4afe126a7ff07e",) @@ -1434,12 +1432,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 mut sk_bytes = [0u8; 32]; + sk_bytes.copy_from_slice(&b"sally was a secret key, she said"[..]); + let sk = secp256k1::SecretKey::from_secret_bytes(sk_bytes).unwrap(); + let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key(&sk)); + let mut msg_bytes = [0u8; 32]; + msg_bytes.copy_from_slice(&b"michael was a message, amusingly"[..]); + let msg = secp256k1::Message::from_digest(msg_bytes); + let _ = &secp; + let sig = secp256k1::ecdsa::sign(msg, &sk); let mut sigser = sig.serialize_der().to_vec(); sigser.push(0x01); // sighash_all @@ -1468,8 +1469,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: bitcoin::ScriptSigBuf::new(), sequence: Sequence::from_height(100), witness: Witness::default(), }; @@ -1479,48 +1480,48 @@ mod tests { assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: script::Builder::new() + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::script::Builder::::new() .push_slice(<&PushBytes>::try_from(sigser.as_slice()).unwrap()) .into_script(), sequence: Sequence::from_height(100), witness: Witness::default(), } ); - assert_eq!(bare.unsigned_script_sig(), bitcoin::ScriptBuf::new()); + assert_eq!(bare.unsigned_script_sig(), bitcoin::script::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(), - script_sig: script::Builder::new() + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::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(), bitcoin::script::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: bitcoin::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(), bitcoin::script::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 = bitcoin::script::Builder::::new() .push_opcode(opcodes::all::OP_PUSHBYTES_0) .push_slice( hash160::Hash::from_str("d1b2a1faf62e73460af885c687dee3b7189cd8ab") @@ -1531,8 +1532,8 @@ mod tests { assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: script::Builder::new() + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::script::Builder::::new() .push_slice(<&PushBytes>::try_from(redeem_script.as_bytes()).unwrap()) .into_script(), sequence: Sequence::from_height(100), @@ -1541,7 +1542,7 @@ mod tests { ); assert_eq!( shwpkh.unsigned_script_sig(), - script::Builder::new() + bitcoin::script::Builder::::new() .push_slice(<&PushBytes>::try_from(redeem_script.as_bytes()).unwrap()) .into_script() ); @@ -1549,52 +1550,60 @@ mod tests { let ms = ms_str!("c:pk_k({})", pk); let sh = Descriptor::new_sh(ms.clone()).unwrap(); sh.satisfy(&mut txin, &satisfier).expect("satisfaction"); + let ms_redeem: bitcoin::script::RedeemScriptBuf = ms.encode(); assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: script::Builder::new() + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::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_redeem.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(), bitcoin::script::ScriptSigBuf::new()); let ms = ms_str!("c:pk_k({})", pk); let wsh = Descriptor::new_wsh(ms.clone()).unwrap(); wsh.satisfy(&mut txin, &satisfier).expect("satisfaction"); + let ms_wit: bitcoin::WitnessScriptBuf = ms.encode(); assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: bitcoin::ScriptBuf::new(), + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::ScriptSigBuf::new(), sequence: Sequence::from_height(100), - witness: Witness::from_slice(&[sigser.clone(), ms.encode().into_bytes()]), + witness: Witness::from_slice(&[sigser.clone(), ms_wit.into_bytes()]), } ); - assert_eq!(wsh.unsigned_script_sig(), bitcoin::ScriptBuf::new()); + assert_eq!(wsh.unsigned_script_sig(), bitcoin::script::ScriptSigBuf::new()); let shwsh = Descriptor::new_sh_wsh(ms.clone()).unwrap(); shwsh.satisfy(&mut txin, &satisfier).expect("satisfaction"); + let ms_wit2: bitcoin::WitnessScriptBuf = ms.encode(); assert_eq!( txin, bitcoin::TxIn { - previous_output: bitcoin::OutPoint::default(), - script_sig: script::Builder::new() - .push_slice(<&PushBytes>::try_from(ms.encode().to_p2wsh().as_bytes()).unwrap()) + previous_output: bitcoin::OutPoint::COINBASE_PREVOUT, + script_sig: bitcoin::script::Builder::::new() + .push_slice( + <&PushBytes>::try_from(ms_wit2.to_p2wsh().unwrap().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_wit2.clone().into_bytes()]), } ); + let ms_encoded: bitcoin::WitnessScriptBuf = ms.encode(); assert_eq!( shwsh.unsigned_script_sig(), - script::Builder::new() - .push_slice(<&PushBytes>::try_from(ms.encode().to_p2wsh().as_bytes()).unwrap()) + bitcoin::script::Builder::::new() + .push_slice( + <&PushBytes>::try_from(ms_encoded.to_p2wsh().unwrap().as_bytes()).unwrap() + ) .into_script() ); } @@ -1730,8 +1739,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: bitcoin::ScriptSigBuf::new(), sequence: Sequence::ZERO, witness: Witness::default(), }; @@ -1921,7 +1930,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 @@ -1938,13 +1946,13 @@ mod tests { let addr_one = desc_one .derive_at_index(index) .unwrap() - .derived_descriptor(&secp_ctx) + .derived_descriptor() .address(bitcoin::Network::Bitcoin) .unwrap(); let addr_two = desc_two .derive_at_index(index) .unwrap() - .derived_descriptor(&secp_ctx) + .derived_descriptor() .address(bitcoin::Network::Bitcoin) .unwrap(); let addr_expected = bitcoin::Address::from_str(raw_addr_expected) @@ -1954,8 +1962,6 @@ mod tests { assert_eq!(addr_two, addr_expected); } - let secp_ctx = secp256k1::Secp256k1::verification_only(); - // P2SH and pubkeys (no wildcard — descriptors are fully defined) { let desc_strs = [ @@ -1969,7 +1975,7 @@ mod tests { let desc = Descriptor::::from_str(desc_str).unwrap(); assert_eq!(desc.to_string(), desc_str); let addr = desc - .derived_descriptor(&secp_ctx) + .derived_descriptor() .address(bitcoin::Network::Bitcoin) .unwrap(); assert_eq!(addr, addr_expected); @@ -1991,7 +1997,7 @@ mod tests { let desc = Descriptor::::from_str(desc_str).unwrap(); assert_eq!(desc.to_string(), desc_str); let addr = desc - .derived_descriptor(&secp_ctx) + .derived_descriptor() .address(bitcoin::Network::Bitcoin) .unwrap(); assert_eq!(addr, addr_expected); @@ -2008,17 +2014,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), @@ -2026,7 +2031,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", @@ -2040,8 +2045,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] @@ -2068,10 +2073,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()); @@ -2109,24 +2113,25 @@ 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( - "5120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb", - ) - .unwrap(); + let script_at_0_1 = ScriptPubKeyBuf::from_bytes( + hex::decode_to_vec( + "5120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb", + ) + .unwrap(), + ); let expected_concrete = Descriptor::from_str( "tr(0283dfe85a3151d2517290da461fe2815591ef69f2b18a2ce63f01697a8b313145)", ) .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))) ); } @@ -2334,14 +2339,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 b1398ba68..7873d93c3 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, WitnessScriptBuf, WitnessScriptExt as _}; +use bitcoin::{Address, Network, Weight}; use crate::descriptor::{write_descriptor, DefiniteDescriptorKey}; use crate::expression::{self, FromTree}; @@ -120,43 +121,55 @@ 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("witness script size within bounds") + } /// Obtains the corresponding script pubkey for this descriptor. pub fn address(&self, network: Network) -> Address { - Address::p2wsh(&self.ms.encode(), network) + let witness_script = self.inner_script(); + Address::p2wsh(&witness_script, network).expect("witness script size within bounds") } - /// Obtains the underlying miniscript for this descriptor. - pub fn inner_script(&self) -> ScriptBuf { self.ms.encode() } + /// Obtains the underlying miniscript for this descriptor, tagged as a + /// witness script. + pub fn inner_script(&self) -> WitnessScriptBuf { self.ms.encode() } /// 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>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { let mut witness = self.ms.satisfy(satisfier)?; let witness_script = self.inner_script(); witness.push(witness_script.into_bytes()); - let script_sig = ScriptBuf::new(); + let script_sig = bitcoin::script::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>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { let mut witness = self.ms.satisfy_malleable(satisfier)?; witness.push(self.inner_script().into_bytes()); - let script_sig = ScriptBuf::new(); + let script_sig = bitcoin::script::ScriptSigBuf::new(); Ok((witness, script_sig)) } } @@ -306,12 +319,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() } @@ -321,14 +334,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: @@ -340,13 +353,16 @@ 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>, bitcoin::script::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 = bitcoin::script::ScriptSigBuf::new(); let witness = vec![sig_vec, self.pk.to_public_key().to_bytes()]; Ok((witness, script_sig)) } else { @@ -357,7 +373,10 @@ 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>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index 3c235b777..74ff24c22 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::{PushBytes, ScriptExt as _, WitnessScriptBuf, WitnessScriptExt as _}; +use bitcoin::{Address, Network, Weight}; use super::{Wpkh, Wsh}; use crate::descriptor::{write_descriptor, DefiniteDescriptorKey}; @@ -252,50 +252,68 @@ impl Sh { impl Sh { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { + pub fn script_pubkey(&self) -> bitcoin::script::ScriptPubKeyBuf { match self.inner { - ShInner::Wsh(ref wsh) => wsh.script_pubkey().to_p2sh(), - ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey().to_p2sh(), - ShInner::Ms(ref ms) => ms.encode().to_p2sh(), + ShInner::Wsh(ref wsh) => wsh + .script_pubkey() + .to_p2sh() + .expect("redeem script within size bounds"), + ShInner::Wpkh(ref wpkh) => wpkh + .script_pubkey() + .to_p2sh() + .expect("redeem script within size bounds"), + ShInner::Ms(ref ms) => { + let redeem: bitcoin::script::RedeemScriptBuf = ms.encode(); + redeem.to_p2sh().expect("redeem script within size bounds") + } } } /// Obtains the corresponding address for this descriptor. pub fn address(&self, network: Network) -> Address { - let addr = self.address_fallible(network); - + // The redeem script for a P2SH-wrapped segwit descriptor is the wrapped + // segwit output's scriptPubKey, not the inner witness/redeem script. // Size is checked in `check_global_consensus_validity`. - assert!(addr.is_ok()); - addr.expect("only fails if size > MAX_SCRIPT_ELEMENT_SIZE") - } - - 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::Ms(ref ms) => ms.encode(), - }; - let address = Address::p2sh(&script, network)?; - - Ok(address) + match self.inner { + ShInner::Wsh(ref wsh) => Address::p2sh(&wsh.script_pubkey(), network) + .expect("redeem script within size bounds"), + ShInner::Wpkh(ref wpkh) => Address::p2sh(&wpkh.script_pubkey(), network) + .expect("redeem script within size bounds"), + ShInner::Ms(ref ms) => { + let redeem: bitcoin::script::RedeemScriptBuf = ms.encode(); + Address::p2sh(&redeem, network).expect("redeem script within size bounds") + } + } } - /// Obtain the underlying miniscript for this descriptor - pub fn inner_script(&self) -> ScriptBuf { + /// Obtain the underlying miniscript for this descriptor, tagged as a + /// redeem script. + /// + /// For `Sh(Wsh)` this returns the inner witness script; for `Sh(Wpkh)` + /// and `Sh(Ms)` it returns the redeem script itself. + pub fn inner_script(&self) -> bitcoin::script::RedeemScriptBuf { match self.inner { - ShInner::Wsh(ref wsh) => wsh.inner_script(), - ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey(), + ShInner::Wsh(ref wsh) => { + bitcoin::script::RedeemScriptBuf::from_bytes(wsh.inner_script().into_bytes()) + } + ShInner::Wpkh(ref wpkh) => { + bitcoin::script::RedeemScriptBuf::from_bytes(wpkh.script_pubkey().into_bytes()) + } 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) -> bitcoin::script::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::Wpkh(ref wpkh) => wpkh.ecdsa_sighash_script_code(), + ShInner::Wsh(ref wsh) => bitcoin::script::RedeemScriptBuf::from_bytes( + wsh.ecdsa_sighash_script_code().into_bytes(), + ), + ShInner::Wpkh(ref wpkh) => bitcoin::script::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(), } @@ -308,29 +326,38 @@ 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) -> bitcoin::script::ScriptSigBuf { match self.inner { ShInner::Wsh(ref wsh) => { // wsh explicit must contain exactly 1 element - let witness_script = wsh.inner_script().to_p2wsh(); + let witness_script = WitnessScriptBuf::from(wsh.inner_script().into_bytes()) + .to_p2wsh() + .expect("Witness script is not too large"); 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() + bitcoin::script::Builder::::new() + .push_slice(push_bytes) + .into_script() } ShInner::Wpkh(ref wpkh) => { let redeem_script = wpkh.script_pubkey(); let push_bytes: &PushBytes = <&PushBytes>::try_from(redeem_script.as_bytes()).expect("Script not too large"); - script::Builder::new().push_slice(push_bytes).into_script() + bitcoin::script::Builder::::new() + .push_slice(push_bytes) + .into_script() } - ShInner::Ms(..) => ScriptBuf::new(), + ShInner::Ms(..) => bitcoin::script::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>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -346,7 +373,8 @@ impl Sh { } ShInner::Ms(ref ms) => { let mut script_witness = ms.satisfy(satisfier)?; - script_witness.push(ms.encode().into_bytes()); + let encoded: bitcoin::script::RedeemScriptBuf = ms.encode(); + script_witness.push(encoded.into_bytes()); let script_sig = witness_to_scriptsig(&script_witness); let witness = vec![]; Ok((witness, script_sig)) @@ -357,7 +385,10 @@ 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>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -369,7 +400,8 @@ impl Sh { } ShInner::Ms(ref ms) => { let mut script_witness = ms.satisfy_malleable(satisfier)?; - script_witness.push(ms.encode().into_bytes()); + let encoded: bitcoin::script::RedeemScriptBuf = ms.encode(); + script_witness.push(encoded.into_bytes()); let script_sig = witness_to_scriptsig(&script_witness); let witness = vec![]; Ok((witness, script_sig)) diff --git a/src/descriptor/tr/mod.rs b/src/descriptor/tr/mod.rs index 203e3cee2..6e83a39c1 100644 --- a/src/descriptor/tr/mod.rs +++ b/src/descriptor/tr/mod.rs @@ -3,7 +3,7 @@ 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::{opcodes, Address, Network, Weight}; use sync::Arc; use super::checksum; @@ -267,9 +267,9 @@ impl Tr { impl Tr { /// Obtains the corresponding script pubkey for this descriptor. - pub fn script_pubkey(&self) -> ScriptBuf { + pub fn script_pubkey(&self) -> bitcoin::script::ScriptPubKeyBuf { let output_key = self.spend_info().output_key(); - let builder = bitcoin::blockdata::script::Builder::new(); + let builder = bitcoin::script::Builder::::new(); builder .push_opcode(opcodes::all::OP_PUSHNUM_1) .push_slice(output_key.serialize()) @@ -285,7 +285,10 @@ 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>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -293,7 +296,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, bitcoin::script::ScriptSigBuf::new())) } else { Err(Error::CouldNotSatisfy) } @@ -305,7 +308,7 @@ impl Tr { pub fn get_satisfaction_mall( &self, satisfier: &S, - ) -> Result<(Vec>, ScriptBuf), Error> + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> where S: Satisfier, { @@ -313,7 +316,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, bitcoin::script::ScriptSigBuf::new())) } else { Err(Error::CouldNotSatisfy) } @@ -503,7 +506,7 @@ where _ => unreachable!(), }; - let script = ScriptBuf::from(leaf.script()); + let script = bitcoin::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..d77d19133 100644 --- a/src/descriptor/tr/spend_info.rs +++ b/src/descriptor/tr/spend_info.rs @@ -7,9 +7,10 @@ //! 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::script::{TapScript, TapScriptBuf}; +use bitcoin::taproot::{ + ControlBlock, LeafVersion, TapLeafHash, TapNodeHash, TaprootMerkleBranchBuf, +}; use crate::miniscript::context::Tap; use crate::prelude::Vec; @@ -68,7 +69,10 @@ impl TrSpendInfo { let depth = usize::from(leaf.depth()); let script = leaf.miniscript().encode(); - let leaf_hash = TapLeafHash::from_script(&script, leaf.leaf_version()); + let leaf_hash = TapLeafHash::from_script( + TapScript::from_bytes(script.as_bytes()), + leaf.leaf_version(), + ); let mut current_hash = TapNodeHash::from(leaf_hash); // 1. If this node increases our depth, add parents. @@ -138,16 +142,15 @@ 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(); + let internal_key: UntweakedPublicKey = tr.internal_key().to_x_only_pubkey(); 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)); + let output_key = internal_key.tap_tweak(nodes.first().map(|node| node.sibling_hash)); + let output_key_parity = output_key.as_x_only_public_key().parity(); TrSpendInfo { internal_key, output_key, output_key_parity, nodes } } @@ -204,7 +207,7 @@ impl TrSpendInfo { builder = builder .add_leaf_with_ver( leaf.depth(), - ScriptBuf::from(leaf.script()), + TapScriptBuf::from(leaf.script().to_vec()), leaf.leaf_version(), ) .expect("iterating through tree in correct DFS order") @@ -222,7 +225,7 @@ struct TrSpendInfoNode { #[derive(Debug)] struct LeafData { - script: ScriptBuf, + script: TapScriptBuf, miniscript: Arc>, leaf_hash: TapLeafHash, } @@ -280,7 +283,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 +299,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 +308,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 +372,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 +393,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); + let internal_key = UntweakedPublicKey::from(pk.to_x_only_pubkey()); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( format!("tr({pk})"), ExpectedTree { internal_key, output_key, output_key_parity, merkle_root }, @@ -401,14 +404,15 @@ 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::from(pk.to_x_only_pubkey()); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); 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 +422,21 @@ 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::from(pk.to_x_only_pubkey()); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); 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 +448,21 @@ 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::from(pk.to_x_only_pubkey()); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); 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 +474,9 @@ 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::from(pk.to_x_only_pubkey()); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( format!("tr({pk},{{0,{{0,tv:0}}}})"), @@ -477,7 +484,7 @@ mod tests { vec![ ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "573d619569d58a36b52187e56f168650ac17f66a9a3afaf054900a04001019b3" .parse::() .unwrap(), @@ -486,7 +493,7 @@ mod tests { }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "64ac241466a5e7032586718ff7465716f77a88d89946ce472daa4c3d0b81148f" .parse::() .unwrap(), @@ -498,7 +505,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 +520,9 @@ 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::from(pk.to_x_only_pubkey()); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( format!("tr({pk},{{uuu:0,{{0,uu:0}}}})"), @@ -524,7 +532,7 @@ mod tests { leaf_hash: "6498e1d56640a272493d1d87549f3347dc448ca674556a2110cdfe100e3c238b" .parse() .unwrap(), - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "7e3e98bab404812c8eebd21c5d825527676b8e9f261f7ad479f3a08a83a43fb4" .parse::() .unwrap(), @@ -533,7 +541,7 @@ mod tests { }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "19417c32bc6ca7e0f6e65b006ac305107c6add73c8bef31181037e6faaa55e7f" .parse::() .unwrap(), @@ -547,7 +555,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 +572,9 @@ 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::from(pk.to_x_only_pubkey()); + let output_key = internal_key.tap_tweak(merkle_root); + let output_key_parity = output_key.as_x_only_public_key().parity(); ret.push(( format!("tr({pk},{{{{0,{{uuu:0,0}}}},{{0,uu:0}}}})"), @@ -573,7 +582,7 @@ mod tests { vec![ ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "57e3b7d414075ff4864deec9efa99db4462c038706306e02c58e02e957c8a51e" .parse::() .unwrap(), @@ -587,7 +596,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 +607,7 @@ mod tests { }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "6498e1d56640a272493d1d87549f3347dc448ca674556a2110cdfe100e3c238b" .parse::() .unwrap(), @@ -611,7 +620,7 @@ mod tests { }, ExpectedLeaf { leaf_hash: zero_hash, - branch: TaprootMerkleBranch::try_from(vec![ + branch: TaprootMerkleBranchBuf::try_from(vec![ "19417c32bc6ca7e0f6e65b006ac305107c6add73c8bef31181037e6faaa55e7f" .parse::() .unwrap(), @@ -625,7 +634,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..16d526b01 100644 --- a/src/descriptor/tr/taptree.rs +++ b/src/descriptor/tr/taptree.rs @@ -188,8 +188,8 @@ 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`] - /// on the returned value. + /// To obtain a [`bitcoin::script::TapScriptBuf`] 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. /// @@ -226,7 +226,11 @@ impl TapTreeIterItem<'_, Pk> { /// [`super::Tr::spend_info`] and use the [`super::TrSpendInfo::leaves`] iterator instead. #[inline] pub fn compute_tap_leaf_hash(&self) -> TapLeafHash { - TapLeafHash::from_script(&self.compute_script(), self.leaf_version()) + let script = self.compute_script(); + TapLeafHash::from_script( + bitcoin::script::TapScript::from_bytes(script.as_bytes()), + self.leaf_version(), + ) } } diff --git a/src/interpreter/error.rs b/src/interpreter/error.rs index 4e47932a6..e47059f11 100644 --- a/src/interpreter/error.rs +++ b/src/interpreter/error.rs @@ -6,7 +6,6 @@ use core::fmt; use std::error; use bitcoin::hashes::hash160; -use bitcoin::hex::DisplayHex; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 use bitcoin::secp256k1; use bitcoin::{absolute, relative, taproot}; @@ -33,7 +32,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. @@ -143,12 +142,20 @@ impl fmt::Display for Error { Error::IncorrectWScriptHash => f.write_str("witness script did not match scriptpubkey"), Error::InsufficientSignaturesMultiSig => f.write_str("Insufficient signatures for CMS"), Error::InvalidSchnorrSighashType(ref sig) => { - write!(f, "Invalid sighash type for schnorr signature '{:x}'", sig.as_hex()) + write!(f, "Invalid sighash type for schnorr signature '")?; + for b in sig { + write!(f, "{:02x}", b)?; + } + write!(f, "'") } Error::InvalidEcdsaSignature(pk) => write!(f, "bad ecdsa signature with pk {}", pk), Error::InvalidSchnorrSignature(pk) => write!(f, "bad schnorr signature with pk {}", pk), Error::NonStandardSighash(ref sig) => { - write!(f, "Non standard sighash type for signature '{:x}'", sig.as_hex()) + write!(f, "Non standard sighash type for signature '")?; + for b in sig { + write!(f, "{:02x}", b)?; + } + write!(f, "'") } Error::NonEmptyWitness => f.write_str("legacy spend had nonempty witness"), Error::NonEmptyScriptSig => f.write_str("segwit spend had nonempty scriptsig"), @@ -247,8 +254,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)] diff --git a/src/interpreter/inner.rs b/src/interpreter/inner.rs index b65e26a7f..0fe6f9074 100644 --- a/src/interpreter/inner.rs +++ b/src/interpreter/inner.rs @@ -1,7 +1,12 @@ // Written in 2019 by Sanket Kanjular and Andrew Poelstra // SPDX-License-Identifier: CC0-1.0 -use bitcoin::hashes::{hash160, sha256, Hash}; +use bitcoin::hashes::{hash160, sha256}; +use bitcoin::key::{PubkeyHash, WPubkeyHash}; +use bitcoin::script::{ + ScriptBufExt as _, ScriptExt as _, ScriptHash, ScriptPubKeyBufExt as _, ScriptPubKeyExt as _, + WScriptHash, +}; use bitcoin::taproot::{ControlBlock, TAPROOT_ANNEX_PREFIX}; use bitcoin::Witness; @@ -14,7 +19,7 @@ use crate::{BareCtx, Legacy, Miniscript, Segwitv0, Tap, ToPublicKey, Translator} /// if asked to, but otherwise dropping it fn pk_from_slice(slice: &[u8], require_compressed: bool) -> Result { if let Ok(pk) = bitcoin::PublicKey::from_slice(slice) { - if require_compressed && !pk.compressed { + if require_compressed && !pk.compressed() { Err(Error::UncompressedPubkey) } else { Ok(pk) @@ -43,7 +48,8 @@ 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(bitcoin::script::ScriptPubKey::from_bytes(sl)) + .map_err(Error::from) } stack::Element::Satisfied => Ok(Miniscript::TRUE), stack::Element::Dissatisfied => Ok(Miniscript::FALSE), @@ -91,10 +97,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: &bitcoin::script::ScriptPubKey, + script_sig: &'txin bitcoin::script::ScriptPubKey, 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) @@ -129,7 +135,9 @@ pub(super) fn from_txdata<'txin>( Some(elem) => { let pk = pk_from_stack_elem(&elem, false)?; if *spk - == bitcoin::ScriptBuf::new_p2pkh(&pk.to_pubkeyhash(SigType::Ecdsa).into()) + == bitcoin::script::ScriptPubKeyBuf::new_p2pkh(PubkeyHash::from_byte_array( + pk.to_pubkeyhash(SigType::Ecdsa).to_byte_array(), + )) { Ok(( Inner::PublicKey(pk.into(), PubkeyType::Pkh), @@ -152,11 +160,17 @@ 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()) { + if *spk + == bitcoin::script::ScriptPubKeyBuf::new_p2wpkh( + WPubkeyHash::from_byte_array(hash160.to_byte_array()), + ) + { Ok(( Inner::PublicKey(pk.into(), PubkeyType::Wpkh), wit_stack, - Some(bitcoin::ScriptBuf::new_p2pkh(&hash160.into())), // bip143, why.. + Some(bitcoin::script::ScriptPubKeyBuf::new_p2pkh( + PubkeyHash::from_byte_array(hash160.to_byte_array()), + )), // bip143, why.. )) } else { Err(Error::IncorrectWPubkeyHash) @@ -176,7 +190,11 @@ 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()) { + if *spk + == bitcoin::script::ScriptPubKeyBuf::new_p2wsh( + WScriptHash::from_byte_array(scripthash.to_byte_array()), + ) + { Ok((Inner::Script(miniscript, ScriptType::Wsh), wit_stack, Some(script))) } else { Err(Error::IncorrectWScriptHash) @@ -190,8 +208,12 @@ 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()) - .map_err(|_| Error::XOnlyPublicKeyParseError)?; + let output_key = { + let arr = <[u8; 32]>::try_from(spk[2..].as_bytes()) + .map_err(|_| Error::XOnlyPublicKeyParseError)?; + bitcoin::key::XOnlyPublicKey::from_byte_array(&arr) + .map_err(|_| Error::XOnlyPublicKeyParseError)? + }; let has_annex = wit_stack .last() .and_then(|x| x.as_push().ok()) @@ -220,10 +242,10 @@ 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) { + let tap_script_tagged = + bitcoin::script::TapScript::from_bytes(tap_script.as_bytes()); + if ctrl_blk.verify_taproot_commitment(output_key, tap_script_tagged) { Ok(( Inner::Script(ms, ScriptType::Tr), wit_stack, @@ -247,7 +269,11 @@ pub(super) fn from_txdata<'txin>( Some(elem) => { if let stack::Element::Push(slice) = elem { let scripthash = hash160::Hash::hash(slice); - if *spk != bitcoin::ScriptBuf::new_p2sh(&scripthash.into()) { + if *spk + != bitcoin::script::ScriptPubKeyBuf::new_p2sh(ScriptHash::from_byte_array( + scripthash.to_byte_array(), + )) + { return Err(Error::IncorrectScriptHash); } // ** p2sh-wrapped wpkh ** @@ -260,13 +286,19 @@ pub(super) fn from_txdata<'txin>( let pk = pk_from_stack_elem(&elem, true)?; let hash160 = pk.to_pubkeyhash(SigType::Ecdsa); if slice - == bitcoin::ScriptBuf::new_p2wpkh(&hash160.into()) - .as_bytes() + == bitcoin::script::ScriptPubKeyBuf::new_p2wpkh( + WPubkeyHash::from_byte_array(hash160.to_byte_array()), + ) + .as_bytes() { Ok(( Inner::PublicKey(pk.into(), PubkeyType::ShWpkh), wit_stack, - Some(bitcoin::ScriptBuf::new_p2pkh(&hash160.into())), // bip143, why.. + Some(bitcoin::script::ScriptPubKeyBuf::new_p2pkh( + PubkeyHash::from_byte_array( + hash160.to_byte_array(), + ), + )), // bip143, why.. )) } else { Err(Error::IncorrectWScriptHash) @@ -288,8 +320,12 @@ pub(super) fn from_txdata<'txin>( let miniscript = miniscript.to_no_checks_ms(); let scripthash = sha256::Hash::hash(script.as_bytes()); if slice - == bitcoin::ScriptBuf::new_p2wsh(&scripthash.into()) - .as_bytes() + == bitcoin::script::ScriptPubKeyBuf::new_p2wsh( + WScriptHash::from_byte_array( + scripthash.to_byte_array(), + ), + ) + .as_bytes() { Ok(( Inner::Script(miniscript, ScriptType::ShWsh), @@ -311,7 +347,11 @@ pub(super) fn from_txdata<'txin>( 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()) { + if *spk + == bitcoin::script::ScriptPubKeyBuf::new_p2sh(ScriptHash::from_byte_array( + scripthash.to_byte_array(), + )) + { Ok((Inner::Script(miniscript, ScriptType::Sh), ssig_stack, Some(script))) } else { Err(Error::IncorrectScriptHash) @@ -393,24 +433,22 @@ mod tests { use core::convert::TryFrom; use core::str::FromStr; - use bitcoin::blockdata::script; - use bitcoin::script::PushBytes; - use bitcoin::ScriptBuf; + use bitcoin::script::{Builder as ScriptBuilderLocal, PushBytes, ScriptPubKeyBuf as ScriptBuf}; 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: ScriptBuf, + pk_sig: ScriptBuf, + pkh_spk: ScriptBuf, + pkh_sig: ScriptBuf, + pkh_sig_justkey: ScriptBuf, + wpkh_spk: ScriptBuf, wpkh_stack: Witness, wpkh_stack_justkey: Witness, - sh_wpkh_spk: bitcoin::ScriptBuf, - sh_wpkh_sig: bitcoin::ScriptBuf, + sh_wpkh_spk: ScriptBuf, + sh_wpkh_sig: ScriptBuf, sh_wpkh_stack: Witness, sh_wpkh_stack_justkey: Witness, } @@ -427,29 +465,37 @@ 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_byte_array( + key.to_pubkeyhash(SigType::Ecdsa).to_byte_array(), + ); + let wpkhash = bitcoin::key::WPubkeyHash::from_byte_array( + key.to_pubkeyhash(SigType::Ecdsa).to_byte_array(), + ); + let wpkh_spk = ScriptBuf::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_sig: script::Builder::new().push_slice(dummy_sig).into_script(), - pkh_sig: script::Builder::new() + pk_spk: ScriptBuf::new_p2pk(key), + pkh_spk: ScriptBuf::new_p2pkh(pkhash), + pk_sig: ScriptBuilderLocal::new() + .push_slice(dummy_sig) + .into_script(), + pkh_sig: ScriptBuilderLocal::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: ScriptBuilderLocal::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_sig: script::Builder::new() + wpkh_stack: Witness::from_slice(&[dummy_sig_vec.clone(), key.to_vec()]), + wpkh_stack_justkey: Witness::from_slice(&[key.to_vec()]), + sh_wpkh_spk: ScriptBuf::new_p2sh(wpkh_scripthash), + sh_wpkh_sig: ScriptBuilderLocal::new() .push_slice(<&PushBytes>::try_from(wpkh_spk[..].as_bytes()).unwrap()) .into_script(), - sh_wpkh_stack: Witness::from_slice(&[dummy_sig_vec, key.to_bytes()]), - sh_wpkh_stack_justkey: Witness::from_slice(&[key.to_bytes()]), + sh_wpkh_stack: Witness::from_slice(&[dummy_sig_vec, key.to_vec()]), + sh_wpkh_stack_justkey: Witness::from_slice(&[key.to_vec()]), } } } @@ -482,7 +528,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 = ScriptBuf::new(); let empty_wit = Witness::default(); // Compressed pk, empty scriptsig @@ -514,17 +560,17 @@ mod tests { assert_eq!(script_code, Some(uncomp.pk_spk)); // Scriptpubkey has invalid key - let mut spk = comp.pk_spk.to_bytes(); + let mut spk = comp.pk_spk.to_vec(); spk[1] = 5; - let spk = bitcoin::ScriptBuf::from(spk); - let err = from_txdata(&spk, &bitcoin::ScriptBuf::new(), &empty_wit).unwrap_err(); + let spk = ScriptBuf::from(spk); + let err = from_txdata(&spk, &ScriptBuf::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(); + let mut spk = comp.pk_spk.to_vec(); spk[0] = 100; - let spk = bitcoin::ScriptBuf::from(spk); - let err = from_txdata(&spk, &bitcoin::ScriptBuf::new(), &empty_wit).unwrap_err(); + let spk = ScriptBuf::from(spk); + let err = from_txdata(&spk, &ScriptBuf::new(), &empty_wit).unwrap_err(); assert_eq!(&err.to_string()[0..12], "parse error:"); // Witness is nonempty @@ -541,7 +587,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, &ScriptBuf::new(), &empty_wit).unwrap_err(); assert_eq!(err.to_string(), "unexpected end of stack"); // pkh, wrong pubkey @@ -587,7 +633,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 = ScriptBuf::new(); // wpkh, empty witness; this time it errors out let err = from_txdata(&comp.wpkh_spk, &blank_script, &Witness::default()).unwrap_err(); @@ -615,7 +661,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.get_back(1).unwrap().into()])); assert_eq!(script_code, Some(comp.pkh_spk)); // Scriptsig is nonempty @@ -628,7 +674,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 = ScriptBuf::new(); // sh_wpkh, missing witness or scriptsig let err = from_txdata(&comp.sh_wpkh_spk, &blank_script, &Witness::default()).unwrap_err(); @@ -669,11 +715,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.get_back(1).unwrap().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, ScriptBuf) { let ms = Miniscript::::from_str_insane(ms).unwrap(); let spk = ms.encode(); let miniscript = ms.to_no_checks_ms(); @@ -684,7 +730,7 @@ 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 = ScriptBuf::new(); let empty_wit = Witness::default(); let (miniscript, spk) = ms_inner_script(&format!("hash160({})", hash)); @@ -710,13 +756,15 @@ 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 script_sig = script::Builder::new() + let spk = ScriptBuf::new_p2sh(rs_hash); + let script_sig = ScriptBuilderLocal::new() .push_slice(<&PushBytes>::try_from(redeem_script.as_bytes()).unwrap()) .into_script(); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptBuf::new(); let empty_wit = Witness::default(); // sh without scriptsig @@ -745,18 +793,20 @@ 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_stack = Witness::from_slice(&[witness_script.to_bytes()]); + 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_vec()]); - let spk = ScriptBuf::new_p2wsh(&wit_hash); - let blank_script = bitcoin::ScriptBuf::new(); + let spk = ScriptBuf::new_p2wsh(wit_hash); + let blank_script = ScriptBuf::new(); // wsh without witness let err = from_txdata(&spk, &blank_script, &Witness::default()).unwrap_err(); assert_eq!(&err.to_string(), "unexpected end of stack"); // with incorrect witness - let wit = Witness::from_slice(&[spk.to_bytes()]); + let wit = Witness::from_slice(&[spk.to_vec()]); let err = from_txdata(&spk, &blank_script, &wit).unwrap_err(); assert_eq!(&err.to_string()[0..12], "parse error:"); @@ -768,7 +818,7 @@ mod tests { assert_eq!(script_code, Some(witness_script.clone())); // nonempty script_sig - let script_sig = script::Builder::new() + let script_sig = ScriptBuilderLocal::new() .push_slice(<&PushBytes>::try_from(witness_script.as_bytes()).unwrap()) .into_script(); let err = from_txdata(&spk, &script_sig, &wit_stack).unwrap_err(); @@ -780,17 +830,21 @@ 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_stack = Witness::from_slice(&[witness_script.to_bytes()]); + 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_vec()]); - let redeem_script = ScriptBuf::new_p2wsh(&wit_hash); - let script_sig = script::Builder::new() + let redeem_script = ScriptBuf::new_p2wsh(wit_hash); + let script_sig = ScriptBuilderLocal::new() .push_slice(<&PushBytes>::try_from(redeem_script.as_bytes()).unwrap()) .into_script(); - let blank_script = bitcoin::ScriptBuf::new(); + let blank_script = ScriptBuf::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 = ScriptBuf::new_p2sh(rs_hash); // shwsh without witness or scriptsig let err = from_txdata(&spk, &blank_script, &Witness::default()).unwrap_err(); @@ -801,7 +855,7 @@ mod tests { assert_eq!(&err.to_string(), "unexpected end of stack"); // with incorrect witness - let wit = Witness::from_slice(&[spk.to_bytes()]); + let wit = Witness::from_slice(&[spk.to_vec()]); let err = from_txdata(&spk, &script_sig, &wit).unwrap_err(); assert_eq!(&err.to_string()[0..12], "parse error:"); diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 5aed49fb0..6700ccf38 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -11,7 +11,7 @@ use core::fmt; use core::str::FromStr; -use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256}; use bitcoin::{absolute, relative, secp256k1, sighash, taproot, Sequence, TxOut, Witness}; use crate::miniscript::context::{NoChecks, SigType}; @@ -34,7 +34,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, } @@ -126,7 +126,7 @@ impl MiniscriptKey for BitcoinKey { fn is_uncompressed(&self) -> bool { match *self { - BitcoinKey::Fullkey(pk) => !pk.compressed, + BitcoinKey::Fullkey(pk) => !pk.compressed(), BitcoinKey::XOnlyPublicKey(_) => false, } } @@ -142,8 +142,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: &bitcoin::script::ScriptPubKeyBuf, + script_sig: &'txin bitcoin::script::ScriptPubKey, witness: &'txin Witness, sequence: Sequence, // CSV, relative lock time. lock_time: absolute::LockTime, // CLTV, absolute lock time. @@ -192,9 +192,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, @@ -226,13 +225,15 @@ 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, ); @@ -243,8 +244,7 @@ impl<'txin> Interpreter<'txin> { }; let success = msg.map(|msg| { - secp.verify_ecdsa(&msg, &ecdsa_sig.signature, &key.inner) - .is_ok() + secp256k1::ecdsa::verify(&ecdsa_sig.signature, msg, &key.to_inner()).is_ok() }); success.unwrap_or(false) // unwrap_or checks for errors, while success would have checksig results } @@ -260,6 +260,7 @@ impl<'txin> Interpreter<'txin> { "Internal Hack: Saving leaf script instead\ of script code for script spend", ); + let tap_script = bitcoin::script::TapScript::from_bytes(tap_script.as_bytes()); let leaf_hash = taproot::TapLeafHash::from_script( tap_script, taproot::LeafVersion::TapScript, @@ -274,11 +275,9 @@ impl<'txin> Interpreter<'txin> { // schnorr sigs in ecdsa descriptors return false; }; - let msg = - sighash_msg.map(|hash| secp256k1::Message::from_digest(hash.to_byte_array())); + let msg = sighash_msg.map(|hash| hash.to_byte_array()); let success = msg.map(|msg| { - secp.verify_schnorr(&schnorr_sig.signature, &msg, xpk) - .is_ok() + secp256k1::schnorr::verify(&schnorr_sig.signature, &msg, xpk.as_inner()).is_ok() }); success.unwrap_or(false) // unwrap_or_default checks for errors, while success would have checksig results } @@ -302,14 +301,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 @@ -1089,12 +1087,9 @@ 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 pk = bitcoin::PublicKey { - inner: secp256k1::PublicKey::from_secret_key(&secp, &sk), - compressed: true, - }; - let signature = secp.sign_ecdsa(&msg, &sk); + let sk = secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"); + let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key(&sk)); + let signature = secp256k1::ecdsa::sign(msg, &sk); ecdsa_sigs.push(bitcoin::ecdsa::Signature { signature, sighash_type: bitcoin::sighash::EcdsaSighashType::All, @@ -1104,10 +1099,15 @@ 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 secp_keypair = secp256k1::Keypair::from_secret_key(&sk); + let keypair = bitcoin::key::Keypair::from_secp(secp_keypair); + // The interpreter reconstructs XOnlyPublicKey from a 32-byte push with default (Even) + // parity; normalise the test's expected keys the same way so assertions line up. + let x_only_pk = bitcoin::key::XOnlyPublicKey::from_keypair(&keypair) + .with_parity(bitcoin::secp256k1::Parity::Even); 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(msg.as_ref(), &secp_keypair, &[0u8; 32]); let schnorr_sig = bitcoin::taproot::Signature { signature: schnorr_sig, sighash_type: bitcoin::sighash::TapSighashType::Default, @@ -1123,13 +1123,15 @@ mod tests { let (pks, der_sigs, ecdsa_sigs, sighash, secp, xpks, schnorr_sigs, ser_schnorr_sigs) = setup_keys_sigs(10); let secp_ref = &secp; + let _ = secp_ref; let vfyfn = |pksig: &KeySigPair| match pksig { - KeySigPair::Ecdsa(pk, ecdsa_sig) => secp_ref - .verify_ecdsa(&sighash, &ecdsa_sig.signature, &pk.inner) - .is_ok(), - KeySigPair::Schnorr(xpk, schnorr_sig) => secp_ref - .verify_schnorr(&schnorr_sig.signature, &sighash, xpk) - .is_ok(), + KeySigPair::Ecdsa(pk, ecdsa_sig) => { + ecdsa_sig.signature.verify(sighash, &pk.to_inner()).is_ok() + } + KeySigPair::Schnorr(xpk, schnorr_sig) => { + secp256k1::schnorr::verify(&schnorr_sig.signature, sighash.as_ref(), xpk.as_inner()) + .is_ok() + } }; fn from_stack<'txin, 'elem>( diff --git a/src/interpreter/stack.rs b/src/interpreter/stack.rs index 647a84713..c5213f166 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,12 @@ 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 arr = <[u8; 32]>::try_from(sl).ok()?; + bitcoin::key::XOnlyPublicKey::from_byte_array(&arr) + .ok()? + .into() + } SigType::Ecdsa => bitcoin::PublicKey::from_slice(sl).ok()?.into(), }; Some(key) diff --git a/src/lib.rs b/src/lib.rs index 87714e103..0cdda1904 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}; @@ -189,7 +189,7 @@ impl MiniscriptKey for bitcoin::PublicKey { type Ripemd160 = ripemd160::Hash; type Hash160 = hash160::Hash; - fn is_uncompressed(&self) -> bool { !self.compressed } + fn is_uncompressed(&self) -> bool { !self.compressed() } fn is_x_only_key(&self) -> bool { false } fn num_der_paths(&self) -> usize { 0 } } @@ -204,6 +204,16 @@ impl MiniscriptKey for bitcoin::secp256k1::XOnlyPublicKey { fn num_der_paths(&self) -> usize { 0 } } +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 } + fn num_der_paths(&self) -> usize { 0 } +} + impl MiniscriptKey for String { type Sha256 = String; type Hash256 = String; @@ -220,9 +230,9 @@ pub trait ToPublicKey: MiniscriptKey { fn to_public_key(&self) -> bitcoin::PublicKey; /// Converts key to an x-only public key. - 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.to_inner()) } /// Obtains the pubkey hash for this key (as a `MiniscriptKey`). @@ -232,7 +242,7 @@ pub trait ToPublicKey: MiniscriptKey { fn to_pubkeyhash(&self, sig_type: SigType) -> hash160::Hash { match sig_type { SigType::Ecdsa => hash160::Hash::hash(&self.to_public_key().to_bytes()), - SigType::Schnorr => hash160::Hash::hash(&self.to_x_only_pubkey().serialize()), + SigType::Schnorr => hash160::Hash::hash(&self.to_x_only_pubkey().serialize().0), } } @@ -277,7 +287,20 @@ 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::from_secp(*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 { bitcoin::XOnlyPublicKey::to_public_key(self) } + + fn to_x_only_pubkey(&self) -> bitcoin::XOnlyPublicKey { *self } fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash } fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { *hash } @@ -432,8 +455,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 @@ -506,7 +527,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), @@ -572,7 +592,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), @@ -631,11 +650,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 { @@ -673,7 +687,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::script::ScriptBufExt as _; + bitcoin::script::ScriptPubKeyBuf::from_hex(s).unwrap() +} #[cfg(test)] mod tests { diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index 078cfac58..f2b9f93d3 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -7,22 +7,23 @@ //! 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 bitcoin::{absolute, opcodes}; use crate::miniscript::context::SigType; use crate::miniscript::ScriptContext; use crate::util::MsKeyBuilder; use crate::{Miniscript, MiniscriptKey, Terminal, ToPublicKey}; -/// Helper trait to add a `push_astelem` method to `script::Builder` +/// Helper trait to add a `push_astelem` method to `bitcoin::script::Builder`. trait PushAstElem { fn push_astelem(self, ast: &Miniscript) -> Self where Pk: ToPublicKey; } -impl PushAstElem for script::Builder { +impl PushAstElem + for bitcoin::script::Builder +{ fn push_astelem(self, ast: &Miniscript) -> Self where Pk: ToPublicKey, @@ -35,7 +36,7 @@ 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: bitcoin::script::Builder) -> bitcoin::script::Builder where Pk: ToPublicKey, { @@ -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() as i64) .push_opcode(opcodes::all::OP_CSV), Terminal::Sha256(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) - .push_int(32) + .push_int_unchecked(32) .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_unchecked(32) .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_unchecked(32) .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_unchecked(32) .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_PUSHNUM_1), + Terminal::False => builder.push_opcode(opcodes::all::OP_0), Terminal::Alt(ref sub) => builder .push_opcode(opcodes::all::OP_TOALTSTACK) .push_astelem(sub) @@ -149,7 +150,7 @@ 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) | Terminal::SortedMulti(ref thresh) => { @@ -161,12 +162,12 @@ impl Terminal { } else { thresh.iter() }; - builder = builder.push_int(thresh.k() as i64); + builder = builder.push_int_unchecked(thresh.k() as i64); for pk in iter { - 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) | Terminal::SortedMultiA(ref thresh) => { @@ -188,7 +189,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 bd3f0a929..a7fd7f471 100644 --- a/src/miniscript/context.rs +++ b/src/miniscript/context.rs @@ -579,7 +579,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 a8c0b8491..9b6170443 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; @@ -38,7 +38,18 @@ impl ParseableKey for bitcoin::PublicKey { impl ParseableKey for bitcoin::secp256k1::XOnlyPublicKey { fn from_slice(sl: &[u8]) -> Result { - bitcoin::secp256k1::XOnlyPublicKey::from_slice(sl).map_err(KeyError::XOnly) + let arr: [u8; 32] = sl + .try_into() + .map_err(|_| KeyError::XOnly(bitcoin::secp256k1::Error::InvalidPublicKey))?; + bitcoin::secp256k1::XOnlyPublicKey::from_byte_array(arr).map_err(KeyError::XOnly) + } +} + +impl ParseableKey for bitcoin::XOnlyPublicKey { + fn from_slice(sl: &[u8]) -> Result { + let secp: bitcoin::secp256k1::XOnlyPublicKey = + ::from_slice(sl)?; + Ok(bitcoin::XOnlyPublicKey::from_secp(secp)) } } @@ -50,6 +61,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)] diff --git a/src/miniscript/iter.rs b/src/miniscript/iter.rs index 0ef2272af..f108466f7 100644 --- a/src/miniscript/iter.rs +++ b/src/miniscript/iter.rs @@ -211,7 +211,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; @@ -227,7 +227,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 { @@ -236,8 +235,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 @@ -247,7 +245,13 @@ pub mod test { pub fn gen_bitcoin_pubkeys(n: usize, compressed: bool) -> Vec { gen_secp_pubkeys(n) .into_iter() - .map(|inner| bitcoin::PublicKey { inner, compressed }) + .map(|inner| { + if compressed { + bitcoin::PublicKey::from_secp(inner) + } else { + bitcoin::PublicKey::from_secp_uncompressed(inner) + } + }) .collect() } diff --git a/src/miniscript/lex.rs b/src/miniscript/lex.rs index 1df1f2dd4..aad38a795 100644 --- a/src/miniscript/lex.rs +++ b/src/miniscript/lex.rs @@ -8,7 +8,7 @@ use core::fmt; use bitcoin::blockdata::{opcodes, script}; -use bitcoin::hex::DisplayHex as _; +use bitcoin::script::{ScriptExt as _, ScriptPubKey as Script}; use crate::prelude::*; @@ -50,15 +50,22 @@ pub enum Token { Bytes65([u8; 65]), } +fn fmt_bytes_hex(f: &mut fmt::Formatter<'_>, bytes: &[u8]) -> fmt::Result { + for byte in bytes { + write!(f, "{:02x}", byte)?; + } + Ok(()) +} + impl fmt::Display for Token { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Token::Num(n) => write!(f, "#{}", n), - Token::Hash20(b) => write!(f, "{}", b.as_hex()), - Token::Bytes32(b) => write!(f, "{}", b.as_hex()), - Token::Bytes33(b) => write!(f, "{}", b.as_hex()), - Token::Bytes65(b) => write!(f, "{}", b.as_hex()), - x => write!(f, "{:?}", x), + Token::Hash20(ref b) => fmt_bytes_hex(f, b), + Token::Bytes32(ref b) => fmt_bytes_hex(f, b), + Token::Bytes33(ref b) => fmt_bytes_hex(f, b), + Token::Bytes65(ref b) => fmt_bytes_hex(f, b), + ref x => write!(f, "{:?}", x), } } } @@ -93,7 +100,7 @@ impl Iterator for TokenIter { } /// Tokenize a script -pub fn lex(script: &'_ script::Script) -> Result, Error> { +pub fn lex(script: &'_ Script) -> Result, Error> { let mut ret = Vec::with_capacity(script.len()); for ins in script.instructions_minimal() { @@ -215,11 +222,13 @@ 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)); } - Ok(n) => return Err(Error::NegativeInt { bytes: bytes.to_owned(), n }), + Ok(n) => { + return Err(Error::NegativeInt { bytes: bytes.to_owned(), n: n as i64 }) + } Err(err) => return Err(Error::InvalidInt { bytes: bytes.to_owned(), err }), } } @@ -289,7 +298,7 @@ pub enum Error { /// The bytes of the push that were attempted to be parsed. bytes: bitcoin::script::PushBytesBuf, /// The error that occurred. - err: bitcoin::script::Error, + err: bitcoin::script::ScriptIntError, }, /// Parsed an opcode outside of the Miniscript language. InvalidOpcode(bitcoin::Opcode), @@ -310,10 +319,27 @@ impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Self::Script(ref e) => e.fmt(f), - Self::InvalidInt { ref bytes, ref err } => write!(f, "push {} of length {} is not a key, hash or minimal integer: {}", bytes.as_bytes().as_hex(), bytes.len(), err), - Self::InvalidOpcode(ref op) => write!(f, "found opcode {} which does not occur in Miniscript", op), - Self::NegativeInt { ref bytes, n } => write!(f, "push {} of length {} parses as a negative number {} which does not occur in Miniscript", bytes.as_bytes().as_hex(), bytes.len(), n), - Self::NonMinimalVerify(ref op) => write!(f, "found {} VERIFY (should be one opcode, {}VERIFY)", op, op), + Self::InvalidInt { ref bytes, ref err } => { + write!(f, "push ")?; + fmt_bytes_hex(f, bytes.as_bytes())?; + write!( + f, + " of length {} is not a key, hash or minimal integer: {}", + bytes.len(), + err + ) + } + Self::InvalidOpcode(ref op) => { + write!(f, "found opcode {} which does not occur in Miniscript", op) + } + Self::NegativeInt { ref bytes, n } => { + write!(f, "push ")?; + fmt_bytes_hex(f, bytes.as_bytes())?; + write!(f, " of length {} parses as a negative number {} which does not occur in Miniscript", bytes.len(), n) + } + Self::NonMinimalVerify(ref op) => { + write!(f, "found {} VERIFY (should be one opcode, {}VERIFY)", op, op) + } } } } diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 4aff8784f..f77583b3a 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -15,7 +15,7 @@ use core::{hash, str}; use bitcoin::hashes::hash160; -use bitcoin::script; +use bitcoin::script::ScriptPubKey as Script; use bitcoin::taproot::{LeafVersion, TapLeafHash}; use self::analyzable::ExtParams; @@ -361,12 +361,18 @@ impl Miniscript { /// Get a reference to the inner `AstElem` representing the root of miniscript pub fn as_inner(&self) -> &Terminal { &self.node } - /// Encode as a Bitcoin script - pub fn encode(&self) -> script::ScriptBuf + /// Encode as a Bitcoin script, tagged at the call site. + /// + /// The caller chooses the script tag `T`, so this works for + /// `ScriptPubKeyBuf`, `RedeemScriptBuf`, `WitnessScriptBuf`, + /// `TapScriptBuf`, etc. without any byte-level conversion. + pub fn encode(&self) -> bitcoin::script::ScriptBuf where Pk: ToPublicKey, { - self.node.encode(script::Builder::new()).into_script() + self.node + .encode(bitcoin::script::Builder::::new()) + .into_script() } /// Size, in bytes of the script-pubkey. If this Miniscript is used outside @@ -453,7 +459,8 @@ impl Miniscript { where Pk: ToPublicKey, { - TapLeafHash::from_script(&self.encode(), LeafVersion::TapScript) + let encoded: bitcoin::script::TapScriptBuf = self.encode(); + TapLeafHash::from_script(&encoded, LeafVersion::TapScript) } /// Attempt to produce non-malleable satisfying witness for the @@ -549,13 +556,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) -> 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, + script: &Script, ext: &ExtParams, ) -> Result, Error> { let tokens = lex(script)?; @@ -585,29 +592,30 @@ impl Miniscript { /// /// ```rust /// use miniscript::{Miniscript, Segwitv0, Tap}; - /// use miniscript::bitcoin::secp256k1::XOnlyPublicKey; + /// use miniscript::bitcoin::script::{ScriptBufExt as _, ScriptPubKeyBuf}; + /// use miniscript::bitcoin::XOnlyPublicKey; /// /// type Segwitv0Script = Miniscript; /// type TapScript = Miniscript; /// /// // parse x-only miniscript in Taproot context - /// let tapscript_ms = TapScript::decode(&bitcoin::ScriptBuf::from_hex( + /// let tapscript_ms = TapScript::decode(&ScriptPubKeyBuf::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( + /// let err = TapScript::decode(&ScriptPubKeyBuf::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( + /// Segwitv0Script::decode(&ScriptPubKeyBuf::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) -> Result, Error> { let ms = Self::decode_with_ext(script, &ExtParams::sane())?; Ok(ms) } @@ -1076,13 +1084,24 @@ serde_string_impl_pk!(Miniscript, "a miniscript", Ctx; ScriptContext); /// Provides a Double SHA256 `Hash` type that displays forwards. pub mod hash256 { - use bitcoin::hashes::{hash_newtype, sha256d}; + use bitcoin::hashes::{hash_newtype, impl_hex_for_newtype, sha256d}; hash_newtype! { /// A hash256 of preimage. #[hash_newtype(forward)] pub struct Hash(sha256d::Hash); } + + impl_hex_for_newtype!(Hash); + + #[allow(clippy::self_named_constructors)] + impl Hash { + /// Hashes some bytes. + pub fn hash(data: &[u8]) -> Self { Self(sha256d::Hash::hash(data)) } + + /// Construct a zero-filled hash. + pub fn all_zeros() -> Self { Self(sha256d::Hash::from_byte_array([0; 32])) } + } } #[cfg(test)] @@ -1091,9 +1110,9 @@ 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::taproot::TapLeafHash; + use bitcoin::XOnlyPublicKey; use sync::Arc; use super::{Miniscript, ScriptContext, Segwitv0, Tap}; @@ -1106,24 +1125,19 @@ 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; sk[1] = (i >> 8) as u8; sk[2] = (i >> 16) as u8; - let pk = bitcoin::PublicKey { - inner: secp256k1::PublicKey::from_secret_key( - &secp, - &secp256k1::SecretKey::from_slice(&sk[..]).expect("secret key"), - ), - compressed: true, - }; + let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key( + &secp256k1::SecretKey::from_secret_bytes(sk).expect("secret key"), + )); ret.push(pk); } ret @@ -1197,7 +1211,7 @@ mod tests { fn roundtrip(tree: &Segwitv0Script, s: &str) { assert_eq!(tree.ty.corr.base, types::Base::B); - let ser = tree.encode(); + let ser: bitcoin::script::ScriptPubKeyBuf = tree.encode(); assert_eq!(ser.len(), tree.script_size()); assert_eq!(ser.to_string(), s); let deser = @@ -1217,7 +1231,8 @@ mod tests { let ms: Result = Miniscript::from_str_insane(ms); match (ms, valid) { (Ok(ms), true) => { - assert_eq!(format!("{:x}", ms.encode()), expected_hex); + let encoded: bitcoin::script::ScriptPubKeyBuf = ms.encode(); + assert_eq!(format!("{:x}", encoded), 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); @@ -1329,10 +1344,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()); @@ -1365,7 +1380,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)" ); @@ -1373,7 +1388,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)" ); @@ -1381,7 +1396,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)" ); @@ -1389,7 +1404,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)", ); @@ -1397,7 +1412,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)", ); @@ -1405,7 +1420,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)", ); } @@ -1416,7 +1431,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: bitcoin::script::ScriptPubKeyBuf = tree.encode(); let s = "\ OP_DUP OP_HASH160 OP_PUSHBYTES_20 \ 7e5a2a6a7610ca4ea78bd65a087bd75b1870e319 \ @@ -1431,7 +1446,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 @@ -1441,13 +1456,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" ); @@ -1483,13 +1498,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( @@ -1498,11 +1513,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 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_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!( @@ -1515,12 +1530,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!( @@ -1531,14 +1546,14 @@ mod tests { "\ 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_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", ); } @@ -1671,8 +1686,11 @@ mod tests { // ); assert_eq!(tap_ms.script_size(), 104); assert_eq!(tap_ms_sorted.script_size(), 104); - assert_eq!(tap_ms.encode().len(), tap_ms.script_size()); - assert_eq!(tap_ms_sorted.encode().len(), tap_ms_sorted.script_size()); + assert_eq!(tap_ms.encode::().len(), tap_ms.script_size()); + assert_eq!( + tap_ms_sorted.encode::().len(), + tap_ms_sorted.script_size() + ); // Test satisfaction code struct SimpleSatisfier(secp256k1::schnorr::Signature); @@ -1713,9 +1731,11 @@ mod tests { ) .unwrap(); let ms_trans = ms.translate_pk(&mut StrKeyTranslator::new()).unwrap(); - let enc = ms_trans.encode(); + let enc: bitcoin::script::ScriptPubKeyBuf = ms_trans.encode(); let ms = Miniscript::::decode_consensus(&enc).unwrap(); - assert_eq!(ms_trans.encode(), ms.encode()); + let trans_enc: bitcoin::script::ScriptPubKeyBuf = ms_trans.encode(); + let re_enc: bitcoin::script::ScriptPubKeyBuf = ms.encode(); + assert_eq!(trans_enc, re_enc); } #[test] @@ -1725,7 +1745,8 @@ mod tests { "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c", ) .unwrap(); - let hash160 = pk.pubkey_hash().to_raw_hash(); + let hash160 = + bitcoin::hashes::hash160::Hash::from_byte_array(pk.pubkey_hash().to_byte_array()); let ms_str = &format!("c:expr_raw_pkh({})", hash160); type SegwitMs = Miniscript; @@ -1926,7 +1947,8 @@ 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::::new() + .push_opcode(bitcoin::opcodes::all::OP_PUSHNUM_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 5a88e4ad3..de8ffacd3 100644 --- a/src/miniscript/satisfy.rs +++ b/src/miniscript/satisfy.rs @@ -10,8 +10,9 @@ use core::{cmp, fmt, mem}; use bitcoin::hashes::hash160; use bitcoin::key::XOnlyPublicKey; +use bitcoin::script::TapScriptBuf; use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash}; -use bitcoin::{absolute, relative, ScriptBuf, Sequence}; +use bitcoin::{absolute, relative, Sequence}; use sync::Arc; use super::context::SigType; @@ -49,7 +50,7 @@ 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 } @@ -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), } @@ -648,7 +649,7 @@ impl Placeholder { match self { Placeholder::Pubkey(pk, size) => { if *size == 33 { - Some(pk.to_x_only_pubkey().serialize().to_vec()) + Some(pk.to_x_only_pubkey().serialize().0.to_vec()) } else { Some(pk.to_public_key().to_bytes()) } @@ -695,7 +696,7 @@ impl Placeholder { Placeholder::HashDissatisfaction => Some(vec![0; 32]), Placeholder::PushZero => Some(vec![]), Placeholder::PushOne => Some(vec![1]), - Placeholder::TapScript(s) => Some(s.to_bytes()), + Placeholder::TapScript(s) => Some(s.to_vec()), Placeholder::TapControlBlock(cb) => Some(cb.serialize()), } } diff --git a/src/plan.rs b/src/plan.rs index 6f56895a4..89f95986a 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -20,9 +20,11 @@ use core::iter::FromIterator; use bitcoin::hashes::{hash160, ripemd160, sha256}; use bitcoin::key::XOnlyPublicKey; -use bitcoin::script::PushBytesBuf; +use bitcoin::script::{ + PushBytesBuf, RedeemScriptBuf, TapScriptBuf, WitnessScriptBuf, WitnessScriptExt as _, +}; use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash}; -use bitcoin::{absolute, bip32, psbt, relative, ScriptBuf, WitnessVersion}; +use bitcoin::{absolute, bip32, psbt, relative, WitnessVersion}; use crate::descriptor::{self, Descriptor, DescriptorType, KeyMap}; use crate::miniscript::hash256; @@ -267,9 +269,7 @@ impl Plan { pub fn satisfy>( &self, stfr: &Sat, - ) -> Result<(Vec>, ScriptBuf), Error> { - use bitcoin::blockdata::script::Builder; - + ) -> Result<(Vec>, bitcoin::script::ScriptSigBuf), Error> { let stack = self .template .iter() @@ -282,14 +282,20 @@ impl Plan { vec![], stack .into_iter() - .fold(Builder::new(), |builder, item| { - let bytes = PushBytesBuf::try_from(item) - .expect("All the possible placeholders can be made into PushBytesBuf"); - builder.push_slice(bytes) - }) + .fold( + bitcoin::script::Builder::::new(), + |builder, item| { + let bytes = PushBytesBuf::try_from(item).expect( + "All the possible placeholders can be made into PushBytesBuf", + ); + builder.push_slice(bytes) + }, + ) .into_script(), ), - DescriptorType::Wpkh | DescriptorType::Tr => (stack, ScriptBuf::new()), + DescriptorType::Wpkh | DescriptorType::Tr => { + (stack, bitcoin::script::ScriptSigBuf::new()) + } DescriptorType::ShWpkh => (stack, self.descriptor.unsigned_script_sig()), DescriptorType::Wsh | DescriptorType::ShWsh => { let mut stack = stack; @@ -317,7 +323,7 @@ impl Plan { #[derive(Default)] struct TrDescriptorData { - tap_script: Option, + tap_script: Option, control_block: Option, spend_type: Option, key_origins: BTreeMap, @@ -334,7 +340,7 @@ impl Plan { Placeholder::TapScript(script) => data.tap_script = Some(script.clone()), Placeholder::TapControlBlock(cb) => data.control_block = Some(cb.clone()), Placeholder::SchnorrSigPk(pk, sig_type, _) => { - let raw_pk = pk.to_x_only_pubkey(); + let raw_pk: XOnlyPublicKey = pk.to_x_only_pubkey(); match (&data.spend_type, sig_type) { // First encountered schnorr sig, update the `TrDescriptorData` accordingly @@ -385,14 +391,15 @@ impl Plan { .or_insert_with(|| (vec![], key_source)); } if let (Some(tap_script), Some(control_block)) = (data.tap_script, data.control_block) { - input - .tap_scripts - .insert(control_block, (tap_script, LeafVersion::TapScript)); + input.tap_scripts.insert( + control_block, + (TapScriptBuf::from_bytes(tap_script.into_bytes()), LeafVersion::TapScript), + ); } } else { for item in &self.template { if let Placeholder::EcdsaSigPk(pk) = item { - let public_key = pk.to_public_key().inner; + let public_key = pk.to_public_key().to_inner(); let master_fingerprint = pk.master_fingerprint(); for derivation_path in pk.full_derivation_paths() { input @@ -406,13 +413,28 @@ 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 inner = wsh.inner_script(); + let witness_script = WitnessScriptBuf::from_bytes(inner.to_vec()); + let p2wsh_spk = witness_script + .to_p2wsh() + .expect("witness script size within bounds"); + input.redeem_script = + Some(RedeemScriptBuf::from_bytes(p2wsh_spk.into_bytes())); + input.witness_script = Some(witness_script); + } + descriptor::ShInner::Wpkh(..) => { + input.redeem_script = + Some(RedeemScriptBuf::from_bytes(sh.inner_script().into_bytes())) + } + descriptor::ShInner::Ms(_) => { + input.redeem_script = + Some(RedeemScriptBuf::from_bytes(sh.inner_script().into_bytes())) } - descriptor::ShInner::Wpkh(..) => input.redeem_script = Some(sh.inner_script()), - descriptor::ShInner::Ms(_) => input.redeem_script = Some(sh.inner_script()), }, - Descriptor::Wsh(wsh) => input.witness_script = Some(wsh.inner_script()), + Descriptor::Wsh(wsh) => { + input.witness_script = + Some(WitnessScriptBuf::from_bytes(wsh.inner_script().into_bytes())) + } Descriptor::Tr(_) => unreachable!("Tr is dealt with separately"), } } @@ -728,7 +750,6 @@ mod test { use std::str::FromStr; use bitcoin::bip32::Xpub; - use secp256k1::Secp256k1; use super::*; use crate::*; @@ -934,7 +955,7 @@ mod test { vec![0, 1], vec![], None, - Some(absolute::LockTime::from_time(500_001_000).unwrap()), + Some(absolute::LockTime::from_mtp(500_001_000).unwrap()), Some(153), ), // incompatible timelock ]; @@ -1036,7 +1057,7 @@ mod test { vec![4], vec![], None, - Some(absolute::LockTime::from_time(1296000000).unwrap()), + Some(absolute::LockTime::from_mtp(1296000000).unwrap()), None, ), // Spend with third leaf (key + timelock), @@ -1067,7 +1088,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![ @@ -1159,17 +1180,15 @@ mod test { desc_str_fn: fn(&[bitcoin::PublicKey]) -> String, exp_witness_len: usize, ) -> Vec> { - let secp = Secp256k1::new(); - let (sks, pks): (Vec<_>, Vec<_>) = [ - &b"sally was a secret key, she said"[..], - &b"polly was a secret key, she said"[..], - &b"bonny was a secret key, she said"[..], + b"sally was a secret key, she said", + b"polly was a secret key, she said", + b"bonny was a secret key, she said", ] .iter() - .map(|d| { - let sk = secp256k1::SecretKey::from_slice(d).unwrap(); - let pk = bitcoin::PublicKey::new(secp256k1::PublicKey::from_secret_key(&secp, &sk)); + .map(|d: &&[u8; 32]| { + let sk = secp256k1::SecretKey::from_secret_bytes(**d).unwrap(); + let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key(&sk)); (sk, pk) }) .unzip(); @@ -1179,11 +1198,11 @@ mod test { let sigs = sks .iter() .map(|sk| { - let sighash = - secp256k1::Message::from_digest_slice(&b"michael was a message, amusingly"[..]) - .expect("32 bytes"); + let mut msg_bytes = [0u8; 32]; + msg_bytes.copy_from_slice(&b"michael was a message, amusingly"[..]); + let sighash = secp256k1::Message::from_digest(msg_bytes); bitcoin::ecdsa::Signature { - signature: secp.sign_ecdsa(&sighash, sk), + signature: secp256k1::ecdsa::sign(sighash, sk), sighash_type: bitcoin::sighash::EcdsaSighashType::All, } }) diff --git a/src/policy/compiler.rs b/src/policy/compiler.rs index 24b0f0ae1..c0ea6a6ed 100644 --- a/src/policy/compiler.rs +++ b/src/policy/compiler.rs @@ -1275,18 +1275,15 @@ mod tests { sk[1] = (i >> 8) as u8; sk[2] = (i >> 16) as u8; - let pk = bitcoin::PublicKey { - inner: secp256k1::PublicKey::from_secret_key( - &secp, - &secp256k1::SecretKey::from_slice(&sk[..]).expect("sk"), - ), - compressed: true, - }; + let pk = bitcoin::PublicKey::from_secp(secp256k1::PublicKey::from_secret_key( + &secp256k1::SecretKey::from_secret_bytes(sk).expect("sk"), + )); 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 _ = &secp; + 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) } @@ -1370,13 +1367,11 @@ mod tests { let policy: BPolicy = Concrete::Key(keys[0]); let ms: SegwitMiniScript = policy.compile().unwrap(); - assert_eq!( - ms.encode(), - script::Builder::new() - .push_key(&keys[0]) - .push_opcode(opcodes::all::OP_CHECKSIG) - .into_script() - ); + let expected: script::WitnessScriptBuf = script::Builder::new() + .push_key(keys[0]) + .push_opcode(opcodes::all::OP_CHECKSIG) + .into_script(); + assert_eq!(ms.encode(), expected); // CSV reordering trick let policy: BPolicy = policy_str!( @@ -1386,19 +1381,17 @@ mod tests { keys[7] ); 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 expected: script::WitnessScriptBuf = 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_unchecked(10000) + .push_opcode(opcodes::all::OP_CSV) + .into_script(); + assert_eq!(ms.encode(), expected); // Liquid policy let policy: BPolicy = Concrete::Or(vec![ diff --git a/src/policy/mod.rs b/src/policy/mod.rs index 073c3aa40..e993e56d2 100644 --- a/src/policy/mod.rs +++ b/src/policy/mod.rs @@ -354,7 +354,7 @@ mod tests { .unwrap(); let ms_str: Miniscript = - format!("andor(multi(1,{}),older(42),c:pk_k({}))", key_a.inner, key_b.inner) + format!("andor(multi(1,{}),older(42),c:pk_k({}))", key_a.to_inner(), key_b.to_inner()) .parse() .unwrap(); assert_eq!( diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index 15ba83618..0c944d441 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -896,7 +896,7 @@ mod tests { assert_eq!( policy .clone() - .at_lock_time(absolute::LockTime::from_time(500_000_001).expect("valid timestamp")), + .at_lock_time(absolute::LockTime::from_mtp(500_000_001).expect("valid timestamp")), Policy::Unsatisfiable ); assert_eq!(policy.n_keys(), 0); @@ -931,25 +931,25 @@ mod tests { assert_eq!( policy .clone() - .at_lock_time(absolute::LockTime::from_time(500_000_000).expect("valid timestamp")), + .at_lock_time(absolute::LockTime::from_mtp(500_000_000).expect("valid timestamp")), Policy::Unsatisfiable ); assert_eq!( policy .clone() - .at_lock_time(absolute::LockTime::from_time(500_000_001).expect("valid timestamp")), + .at_lock_time(absolute::LockTime::from_mtp(500_000_001).expect("valid timestamp")), Policy::Unsatisfiable ); assert_eq!( policy .clone() - .at_lock_time(absolute::LockTime::from_time(500_000_010).expect("valid timestamp")), + .at_lock_time(absolute::LockTime::from_mtp(500_000_010).expect("valid timestamp")), policy ); assert_eq!( policy .clone() - .at_lock_time(absolute::LockTime::from_time(500_000_012).expect("valid timestamp")), + .at_lock_time(absolute::LockTime::from_mtp(500_000_012).expect("valid timestamp")), policy ); assert_eq!(policy.n_keys(), 0); diff --git a/src/primitives/threshold.rs b/src/primitives/threshold.rs index 1ec8c30dd..37271102c 100644 --- a/src/primitives/threshold.rs +++ b/src/primitives/threshold.rs @@ -247,7 +247,7 @@ impl Threshold { /// Lexicographically sorts underlying `Vec` of pubkeys as /// defined by BIP-67 and returns a new `Threshold`. pub fn into_sorted_bip67(self) -> Self { - Self::into_sorted(self, |pk| pk.to_public_key().inner.serialize()) + Self::into_sorted(self, |pk| pk.to_public_key().to_inner().serialize()) } /// Lexicographically sorts underlying `Vec` of x-only pubkeys as @@ -259,7 +259,7 @@ impl Threshold { /// Checks if underlying `Vec` of pubkeys is sorted lexicographically from /// smallest to largest as defined by BIP-67 pub fn is_sorted_bip67(&self) -> bool { - Self::is_sorted(self, |pk| pk.to_public_key().inner.serialize()) + Self::is_sorted(self, |pk| pk.to_public_key().to_inner().serialize()) } /// Checks if underlying `Vec` of x-only pubkeys is sorted lexicographically diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index ac9f815e1..a4822226e 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -13,12 +13,13 @@ 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::script::{ + ScriptExt as _, ScriptPubKey as Script, ScriptPubKeyBuf as ScriptBuf, ScriptPubKeyExt as _, + WitnessScriptExt as _, +}; use bitcoin::sighash::Prevouts; use bitcoin::taproot::LeafVersion; -use bitcoin::{PublicKey, Script, ScriptBuf, TxOut, Witness}; +use bitcoin::{PublicKey, TxOut, Witness}; use super::{sanity_check, Error, InputError, Psbt, PsbtInputSatisfier}; use crate::prelude::*; @@ -39,14 +40,14 @@ fn construct_tap_witness( ) -> 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 // all the keys added on a descriptor and thus we get keys from it. let public_keys = psbt_input.tap_key_origins.keys(); for key in public_keys { - let bitcoin_key = *key; + let bitcoin_key: bitcoin::XOnlyPublicKey = *key; let hash = bitcoin_key.to_pubkeyhash(SigType::Schnorr); map.insert(hash, bitcoin_key); } @@ -63,15 +64,16 @@ 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) - { + let block_map = &sat.psbt_input().tap_scripts; + if !block_map.is_empty() { 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 script_spk = Script::from_bytes(script.as_bytes()); + let ms = match Miniscript::::decode_consensus(script_spk) + { Ok(ms) => ms.substitute_raw_pkh(&map), Err(..) => continue, // try another script }; @@ -86,7 +88,8 @@ fn construct_tap_witness( Err(..) => continue, } }; - wit.push(ms.encode().into_bytes()); + let encoded: bitcoin::TapScriptBuf = ms.encode(); + wit.push(encoded.into_bytes()); wit.push(control_block.serialize()); let wit_len = Some(witness_size(&wit)); if min_wit_len.is_some() && wit_len > min_wit_len { @@ -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,7 +152,7 @@ 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(); + let hash = hash160::Hash::from_byte_array(bitcoin_key.pubkey_hash().to_byte_array()); map.insert(hash, bitcoin_key); } } @@ -160,7 +163,7 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In // 1. `PK`: creates a `Pk` descriptor(does not check if partial sig is given) if script_pubkey.is_p2pk() { let script_pubkey_len = script_pubkey.len(); - let pk_bytes = &script_pubkey.to_bytes(); + let pk_bytes = &script_pubkey.to_vec(); match bitcoin::PublicKey::from_slice(&pk_bytes[1..script_pubkey_len - 1]) { Ok(pk) => Ok(Descriptor::new_pk(pk)), Err(e) => Err(InputError::from(e)), @@ -188,7 +191,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,13 +207,22 @@ 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 derived = + witness_script + .to_p2wsh() + .map_err(|_| InputError::InvalidWitnessScript { + witness_script: witness_script.clone(), + p2wsh_expected: script_pubkey.clone(), + })?; + if derived != *script_pubkey { return Err(InputError::InvalidWitnessScript { witness_script: witness_script.clone(), p2wsh_expected: script_pubkey.clone(), }); } - let ms = Miniscript::::decode_consensus(witness_script)?; + let witness_script_spk = Script::from_bytes(witness_script.as_bytes()); + let ms = + Miniscript::::decode_consensus(witness_script_spk)?; Ok(Descriptor::new_wsh(ms.substitute_raw_pkh(&map))?) } else { Err(InputError::MissingWitnessScript) @@ -219,7 +231,14 @@ 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 derived_p2sh = + redeem_script + .to_p2sh() + .map_err(|_| InputError::InvalidRedeemScript { + redeem: redeem_script.clone(), + p2sh_expected: script_pubkey.clone(), + })?; + if derived_p2sh != *script_pubkey { return Err(InputError::InvalidRedeemScript { redeem: redeem_script.clone(), p2sh_expected: script_pubkey.clone(), @@ -228,14 +247,21 @@ 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 derived_p2wsh = witness_script.to_p2wsh().map_err(|_| { + InputError::InvalidWitnessScript { + witness_script: witness_script.clone(), + p2wsh_expected: ScriptBuf::from_bytes(redeem_script.to_vec()), + } + })?; + if derived_p2wsh.as_bytes() != redeem_script.as_bytes() { return Err(InputError::InvalidWitnessScript { witness_script: witness_script.clone(), - p2wsh_expected: redeem_script.clone(), + p2wsh_expected: ScriptBuf::from_bytes(redeem_script.to_vec()), }); } + let witness_script_spk = Script::from_bytes(witness_script.as_bytes()); let ms = Miniscript::::decode_consensus( - witness_script, + witness_script_spk, )?; Ok(Descriptor::new_sh_wsh(ms.substitute_raw_pkh(&map))?) } else { @@ -246,11 +272,9 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In let partial_sig_contains_pk = inp.partial_sigs.iter().find(|&(&pk, _sig)| { match bitcoin::key::CompressedPublicKey::try_from(pk) { Ok(compressed) => { - let addr = bitcoin::Address::p2wpkh( - &compressed, - bitcoin::Network::Bitcoin, - ); - *redeem_script == addr.script_pubkey() + let addr = + bitcoin::Address::p2wpkh(compressed, bitcoin::Network::Bitcoin); + redeem_script.as_bytes() == addr.script_pubkey().as_bytes() } Err(_) => false, } @@ -265,8 +289,9 @@ fn get_descriptor(psbt: &Psbt, index: usize) -> Result, In return Err(InputError::NonEmptyWitnessScript); } if let Some(ref redeem_script) = inp.redeem_script { + let redeem_script_spk = Script::from_bytes(redeem_script.as_bytes()); let ms = Miniscript::::decode_consensus( - redeem_script, + redeem_script_spk, )?; Ok(Descriptor::new_sh(ms)?) } else { @@ -294,35 +319,34 @@ 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( - psbt: &Psbt, - secp: &Secp256k1, -) -> Result<(), Error> { +pub fn interpreter_check(psbt: &Psbt) -> 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 = bitcoin::script::ScriptSigBuf::new(); + let script_sig = match input.final_script_sig.as_ref() { + Some(sig) => sig.clone(), + None => empty_script_sig, + }; let empty_witness = Witness::default(); - let script_sig = input.final_script_sig.as_ref().unwrap_or(&empty_script_sig); let witness = input .final_script_witness .as_ref() .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, witness: &Witness, - script_sig: &Script, + script_sig: &bitcoin::script::ScriptSig, ) -> Result<(), Error> { let spk = get_scriptpubkey(psbt, index).map_err(|e| Error::InputError(e, index))?; @@ -331,11 +355,14 @@ 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; + // The miniscript interpreter takes an untagged ScriptPubKey for both spk and sig; + // cast the tagged scriptSig bytes accordingly. + let script_sig_spk = Script::from_bytes(script_sig.as_bytes()); let interpreter = - interpreter::Interpreter::from_txdata(&spk, script_sig, witness, csv, cltv) + interpreter::Interpreter::from_txdata(&spk, script_sig_spk, 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(&psbt.unsigned_tx, index, utxos); if let Some(error) = iter.filter_map(Result::err).next() { return Err(Error::InputError(InputError::Interpreter(error), index)); }; @@ -355,31 +382,17 @@ 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( - psbt: &mut Psbt, - secp: &Secp256k1, -) -> Result<(), super::Error> { - finalize_helper(psbt, secp, false) -} +pub fn finalize(psbt: &mut Psbt) -> Result<(), super::Error> { finalize_helper(psbt, false) } /// Same as [finalize], but allows for malleable satisfactions -pub fn finalize_mall( - psbt: &mut Psbt, - secp: &Secp256k1, -) -> Result<(), super::Error> { - finalize_helper(psbt, secp, true) -} +pub fn finalize_mall(psbt: &mut Psbt) -> Result<(), super::Error> { finalize_helper(psbt, true) } -pub fn finalize_helper( - psbt: &mut Psbt, - secp: &Secp256k1, - allow_mall: bool, -) -> Result<(), super::Error> { +pub fn finalize_helper(psbt: &mut Psbt, 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 +400,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, bitcoin::script::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 +413,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, bitcoin::script::ScriptSigBuf::new()) } else { // Get a descriptor for this input. let desc = get_descriptor(psbt, index).map_err(|e| Error::InputError(e, index))?; @@ -420,18 +432,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. @@ -443,7 +454,7 @@ pub(super) fn finalize_input( input.final_script_sig = if script_sig.is_empty() { None } else { - Some(script_sig) + Some(bitcoin::script::ScriptSigBuf::from_bytes(script_sig.into_bytes())) }; input.final_script_witness = if witness.is_empty() { None @@ -466,8 +477,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 554ca9b36..e29f32d94 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -12,14 +12,18 @@ 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}; +use bitcoin::script::{ + RedeemScriptBuf, ScriptExt as _, ScriptPubKeyExt as _, TapScriptBuf, WitnessScriptBuf, + WitnessScriptExt as _, +}; #[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::transaction::TxInExt as _; +use bitcoin::{absolute, bip32, relative, transaction}; use crate::miniscript::context::SigType; use crate::prelude::*; @@ -99,16 +103,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: bitcoin::script::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: bitcoin::script::ScriptPubKeyBuf, }, /// Invalid sig InvalidSignature { @@ -263,7 +267,8 @@ 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 pk_xonly: bitcoin::key::XOnlyPublicKey = pk.to_x_only_pubkey(); + if pk_xonly == key { return self.psbt_input().tap_key_sig; } } @@ -275,9 +280,10 @@ impl Satisfier for PsbtInputSatisfier<'_> { pk: &Pk, lh: &TapLeafHash, ) -> Option { + let pk_xonly: bitcoin::key::XOnlyPublicKey = pk.to_x_only_pubkey(); self.psbt_input() .tap_script_sigs - .get(&(pk.to_x_only_pubkey(), *lh)) + .get(&(pk_xonly, *lh)) .copied() } @@ -291,14 +297,18 @@ impl Satisfier for PsbtInputSatisfier<'_> { fn lookup_tap_control_block_map( &self, - ) -> Option<&BTreeMap> { - Some(&self.psbt_input().tap_scripts) + ) -> Option<&BTreeMap> { + // The PSBT's `tap_scripts` field uses `TapScriptBuf`, which differs in type + // from the `ScriptBuf` (= `ScriptPubKeyBuf`) required by this trait. We do + // not attempt the conversion here; callers that need access to PSBT tap + // scripts should read `psbt_input().tap_scripts` directly. + None } fn lookup_raw_pkh_tap_leaf_script_sig( &self, pkh: &(hash160::Hash, TapLeafHash), - ) -> Option<(bitcoin::secp256k1::XOnlyPublicKey, bitcoin::taproot::Signature)> { + ) -> Option<(bitcoin::key::XOnlyPublicKey, bitcoin::taproot::Signature)> { self.psbt_input() .tap_script_sigs .iter() @@ -327,7 +337,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 +347,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 +390,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 +453,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 @@ -456,23 +463,14 @@ 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 #[allow(clippy::result_large_err)] - 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 #[allow(clippy::result_large_err)] - 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 @@ -481,11 +479,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 /// @@ -494,26 +488,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`]. @@ -522,10 +504,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. /// @@ -596,14 +575,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); @@ -617,23 +593,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); @@ -647,64 +617,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(); @@ -714,13 +662,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) } @@ -736,7 +684,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)?; @@ -758,7 +706,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 @@ -766,7 +714,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)? { @@ -802,7 +750,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)?; @@ -860,7 +808,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 @@ -892,12 +840,14 @@ impl PsbtExt for Psbt { Ok(PsbtSighashMsg::SegwitV0Sighash(msg)) } else { // legacy sighash case + let inp_spk_as_redeem; let script_code = if inp_spk.is_p2sh() { inp.redeem_script .as_ref() .ok_or(SighashError::MissingRedeemScript)? } else { - &inp_spk + inp_spk_as_redeem = RedeemScriptBuf::from_bytes(inp_spk.to_vec()); + &inp_spk_as_redeem }; let msg = cache.legacy_signature_hash(idx, script_code, hash_ty.to_u32())?; Ok(PsbtSighashMsg::LegacySighash(msg)) @@ -976,19 +926,16 @@ 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, + derived.to_public_key().to_inner(), ( xpk.master_fingerprint(), xpk.full_derivation_path() @@ -1004,8 +951,8 @@ 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_key_origins( @@ -1020,15 +967,15 @@ 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 } @@ -1047,7 +994,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> { @@ -1056,8 +1003,8 @@ 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 } @@ -1082,18 +1029,16 @@ impl PsbtFields for psbt::Output { fn update_item_with_descriptor_helper( item: &mut F, descriptor: &Descriptor, - check_script: Option<&Script>, + check_script: Option<&bitcoin::script::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) @@ -1109,19 +1054,22 @@ 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 { - item.tap_key_origins() - .insert(derived_key.to_x_only_pubkey(), (vec![], key_source)); + let xonly: bitcoin::key::XOnlyPublicKey = derived_key.to_x_only_pubkey(); + item.tap_key_origins().insert(xonly, (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_bytes(leaf_derived.script().to_vec()), + 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(); @@ -1129,9 +1077,10 @@ fn update_item_with_descriptor_helper( } for leaf_pk in leaf_derived.miniscript().iter_pk() { + let xonly: bitcoin::key::XOnlyPublicKey = leaf_pk.to_x_only_pubkey(); let tapleaf_hashes = &mut item .tap_key_origins() - .get_mut(&leaf_pk.to_x_only_pubkey()) + .get_mut(&xonly) .expect("inserted all keys above") .0; if tapleaf_hashes.last() != Some(&tapleaf_hash) { @@ -1160,13 +1109,28 @@ fn update_item_with_descriptor_helper( Descriptor::Bare(_) | Descriptor::Pkh(_) | Descriptor::Wpkh(_) => {} 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 inner = wsh.inner_script(); + let witness_script = WitnessScriptBuf::from_bytes(inner.to_vec()); + let p2wsh_spk = witness_script + .to_p2wsh() + .expect("witness script size within bounds"); + *item.redeem_script() = + Some(RedeemScriptBuf::from_bytes(p2wsh_spk.into_bytes())); + *item.witness_script() = Some(witness_script); + } + descriptor::ShInner::Wpkh(..) => { + *item.redeem_script() = + Some(RedeemScriptBuf::from_bytes(sh.inner_script().into_bytes())) + } + descriptor::ShInner::Ms(_) => { + *item.redeem_script() = + Some(RedeemScriptBuf::from_bytes(sh.inner_script().into_bytes())) } - descriptor::ShInner::Wpkh(..) => *item.redeem_script() = Some(sh.inner_script()), - descriptor::ShInner::Ms(_) => *item.redeem_script() = Some(sh.inner_script()), }, - Descriptor::Wsh(wsh) => *item.witness_script() = Some(wsh.inner_script()), + Descriptor::Wsh(wsh) => { + *item.witness_script() = + Some(WitnessScriptBuf::from_bytes(wsh.inner_script().into_bytes())) + } Descriptor::Tr(_) => unreachable!("Tr is dealt with separately"), } }; @@ -1370,6 +1334,7 @@ mod tests { use bitcoin::bip32::{DerivationPath, Xpub}; use bitcoin::consensus::encode::deserialize; use bitcoin::key::XOnlyPublicKey; + use bitcoin::script::ScriptBufExt as _; use bitcoin::secp256k1::PublicKey; use bitcoin::{Amount, OutPoint, TxIn, TxOut}; use hex; @@ -1380,8 +1345,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); } @@ -1454,7 +1418,7 @@ mod tests { let first_leaf_hash = { let ms = Miniscript::::from_str(&format!("pkh({})", &key_0_1)).unwrap(); - let first_script = ms.encode(); + let first_script: TapScriptBuf = ms.encode(); assert!(psbt_input .tap_scripts .values() @@ -1527,7 +1491,10 @@ 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(WitnessScriptBuf::from_bytes(derived.explicit_script().unwrap().into_bytes())) + ); assert_eq!(psbt_output.bip32_derivation, psbt_input.bip32_derivation); assert_eq!(psbt_output.witness_script, psbt_input.witness_script); @@ -1548,7 +1515,10 @@ 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(RedeemScriptBuf::from_bytes(derived.explicit_script().unwrap().into_bytes())) + ); assert_eq!(psbt_output.bip32_derivation, psbt_input.bip32_derivation); assert_eq!(psbt_output.witness_script, psbt_input.witness_script); @@ -1564,10 +1534,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(1_000).expect("in range"), + script_pubkey: bitcoin::script::ScriptPubKeyBuf::from_hex( "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c", ) .unwrap(), @@ -1577,11 +1547,11 @@ 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() + ..TxIn::EMPTY_COINBASE }], - output: vec![], + outputs: vec![], }; let mut psbt = Psbt::from_unsigned_tx(tx).unwrap(); @@ -1590,7 +1560,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 +1572,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 +1580,8 @@ 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 = + bitcoin::script::ScriptPubKeyBuf::default(); assert_eq!( psbt.update_input_with_descriptor(0, &desc), Err(UtxoUpdateError::MismatchedScriptPubkey), @@ -1626,10 +1597,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(1_000).expect("in range"), + script_pubkey: bitcoin::script::ScriptPubKeyBuf::from_hex( "5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c", ) .unwrap(), @@ -1647,7 +1618,7 @@ mod tests { Ok(()), "script_pubkey should match" ); - psbt.unsigned_tx.output[0].script_pubkey = ScriptBuf::default(); + psbt.unsigned_tx.outputs[0].script_pubkey = bitcoin::script::ScriptPubKeyBuf::default(); 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..f0f2720d5 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -7,9 +7,9 @@ use std::collections::HashMap; use std::str::FromStr; use bitcoin::hashes::{hash160, ripemd160, sha256}; -use bitcoin::key::XOnlyPublicKey; #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684 use bitcoin::secp256k1; +use bitcoin::XOnlyPublicKey; use crate::miniscript::context::SigType; use crate::{hash256, ToPublicKey, Translator}; @@ -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::from_secp(secp256k1::PublicKey::from_secret_key(sk))) .collect(); let mut pk_map = HashMap::new(); let mut pkh_map = HashMap::new(); @@ -164,14 +163,13 @@ impl StrKeyTranslator { impl StrXOnlyKeyTranslator { pub fn new() -> Self { - let secp = secp256k1::Secp256k1::new(); let sks = random_sks(26); - let pks: Vec<_> = sks + let pks: Vec = sks .iter() .map(|sk| { - let keypair = secp256k1::Keypair::from_secret_key(&secp, sk); - let (pk, _parity) = XOnlyPublicKey::from_keypair(&keypair); - pk + let keypair = secp256k1::Keypair::from_secret_key(sk); + let (pk, _parity) = secp256k1::XOnlyPublicKey::from_keypair(&keypair); + XOnlyPublicKey::from_secp(pk) }) .collect(); let mut pk_map = HashMap::new(); diff --git a/src/util.rs b/src/util.rs index 5de37b780..3a4793748 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2,16 +2,27 @@ 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::hashes::hash160; +use bitcoin::script::PushBytes; use crate::miniscript::context; +use crate::miniscript::limits::MAX_SCRIPT_ELEMENT_SIZE; 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 { + // Equivalent to the CompactSize / VarInt length used by Bitcoin consensus encoding. + if n < 0xFD { + 1 + } else if n <= u16::MAX as usize { + 3 + } else if n <= u32::MAX as usize { + 5 + } else { + 9 + } +} pub(crate) trait ItemSize { fn size(&self) -> usize; @@ -51,11 +62,11 @@ 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 { - let mut b = script::Builder::new(); +pub(crate) fn witness_to_scriptsig(witness: &[Vec]) -> bitcoin::script::ScriptSigBuf { + let mut b = bitcoin::script::Builder::::new(); for (i, wit) in witness.iter().enumerate() { - if let Ok(n) = script::read_scriptint(wit) { - b = b.push_int(n); + if let Ok(n) = bitcoin::script::read_scriptint_non_minimal(wit) { + b = b.push_int(n).expect("not i32::MIN"); } else { if i != witness.len() - 1 { assert!(wit.len() < 73, "All pushes in miniscript are < 73 bytes"); @@ -84,15 +95,15 @@ pub(crate) trait MsKeyBuilder { Ctx: ScriptContext; } -impl MsKeyBuilder for script::Builder { +impl MsKeyBuilder for bitcoin::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::Schnorr => self.push_slice(key.to_x_only_pubkey().serialize()), + context::SigType::Ecdsa => self.push_key(key.to_public_key()), + context::SigType::Schnorr => self.push_slice(key.to_x_only_pubkey().serialize().0), } } @@ -103,9 +114,9 @@ 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())) - } + context::SigType::Schnorr => self.push_slice( + hash160::Hash::hash(&key.to_x_only_pubkey().serialize().0).to_byte_array(), + ), } } } 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);