|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# Copyright (c) 2021 The Bitcoin Core developers |
| 3 | +# Distributed under the MIT software license, see the accompanying |
| 4 | +# file COPYING or http://www.opensource.org/licenses/mit-license.php. |
| 5 | +"""Test generation and spending of P2TR addresses.""" |
| 6 | + |
| 7 | +import random |
| 8 | + |
| 9 | +from test_framework.test_framework import BitcoinTestFramework |
| 10 | +from test_framework.util import assert_equal |
| 11 | +from test_framework.descriptors import descsum_create |
| 12 | +from test_framework.script import (CScript, OP_CHECKSIG, taproot_construct) |
| 13 | +from test_framework.segwit_addr import encode_segwit_address |
| 14 | + |
| 15 | +# xprvs/xpubs, and m/* derived x-only pubkeys (created using independent implementation) |
| 16 | +KEYS = [ |
| 17 | + { |
| 18 | + "xprv": "tprv8ZgxMBicQKsPeNLUGrbv3b7qhUk1LQJZAGMuk9gVuKh9sd4BWGp1eMsehUni6qGb8bjkdwBxCbgNGdh2bYGACK5C5dRTaif9KBKGVnSezxV", |
| 19 | + "xpub": "tpubD6NzVbkrYhZ4XqNGAWGWSzmxGWFwVjVTjZxh2fioKbVYi7Jx8fdbprVWsdW7mHwqjchBVas8TLZG4Xwuz4RKU4iaCqiCvoSkFCzQptqk5Y1", |
| 20 | + "pubs": [ |
| 21 | + "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c18", |
| 22 | + "a30253b018ea6fca966135bf7dd8026915427f24ccf10d4e03f7870f4128569b", |
| 23 | + "a61e5749f2f3db9dc871d7b187e30bfd3297eea2557e9be99897ea8ff7a29a21", |
| 24 | + "8110cf482f66dc37125e619d73075af932521724ffc7108309e88f361efe8c8a", |
| 25 | + ] |
| 26 | + }, |
| 27 | + { |
| 28 | + "xprv": "tprv8ZgxMBicQKsPe98QUPieXy5KFPVjuZNpcC9JY7K7buJEm8nWvJogK4kTda7eLjK9U4PnMNbSjEkpjDJazeBZ4rhYNYD7N6GEdaysj1AYSb5", |
| 29 | + "xpub": "tpubD6NzVbkrYhZ4XcACN3PEwNjRpR1g4tZjBVk5pdMR2B6dbd3HYhdGVZNKofAiFZd9okBserZvv58A6tBX4pE64UpXGNTSesfUW7PpW36HuKz", |
| 30 | + "pubs": [ |
| 31 | + "f95886b02a84928c5c15bdca32784993105f73de27fa6ad8c1a60389b999267c", |
| 32 | + "71522134160685eb779857033bfc84c7626f13556154653a51dd42619064e679", |
| 33 | + "48957b4158b2c5c3f4c000f51fd2cf0fd5ff8868ebfb194256f5e9131fc74bd8", |
| 34 | + "086dda8139b3a84944010648d2b674b70447be3ae59322c09a4907bc80be62c1", |
| 35 | + ] |
| 36 | + }, |
| 37 | + { |
| 38 | + "xprv": "tprv8ZgxMBicQKsPe3ZJmcj9aJ2EPZJYYCh6Lp3v82p75wspgaXmtDZ2RBtkAtWcGnW2VQDzMHQPBkCKMoYTqh1RfJKjv4PcmWVR7KqTpjsdboN", |
| 39 | + "xpub": "tpubD6NzVbkrYhZ4XWb6fGPjyhgLxapUhXszv7ehQYrQWDgDX4nYWcNcbgWcM2RhYo9s2mbZcfZJ8t5LzYcr24FK79zVybsw5Qj3Rtqug8jpJMy", |
| 40 | + "pubs": [ |
| 41 | + "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7", |
| 42 | + "8a104c54cd34acba60c97dd8f1f7abc89ba9587afd88dc928e91aca7b1c50d20", |
| 43 | + "13ba6b252a4eb5ef31d39cb521724cdab19a698323f5c17093f28fb1821d052f", |
| 44 | + "f6c2b4863fd5ba1ba09e3a890caed8b75ffbe013ebab31a06ab87cd6f72506af", |
| 45 | + ] |
| 46 | + }, |
| 47 | + { |
| 48 | + "xprv": "tprv8ZgxMBicQKsPdKziibn63Rm6aNzp7dSjDnufZMStXr71Huz7iihCRpbZZZ6Voy5HyuHCWx6foHMipzMzUq4tZrtkZ24DJwz5EeNWdsuwX5h", |
| 49 | + "xpub": "tpubD6NzVbkrYhZ4Wo2WcFSgSqRD9QWkGxddo6WSqsVBx7uQ8QEtM7WncKDRjhFEexK119NigyCsFygA4b7sAPQxqebyFGAZ9XVV1BtcgNzbCRR", |
| 50 | + "pubs": [ |
| 51 | + "03a669ea926f381582ec4a000b9472ba8a17347f5fb159eddd4a07036a6718eb", |
| 52 | + "bbf56b14b119bccafb686adec2e3d2a6b51b1626213590c3afa815d1fd36f85d", |
| 53 | + "2994519e31bbc238a07d82f85c9832b831705d2ee4a2dbb477ecec8a3f570fe5", |
| 54 | + "68991b5c139a4c479f8c89d6254d288c533aefc0c5b91fac6c89019c4de64988", |
| 55 | + ] |
| 56 | + }, |
| 57 | + { |
| 58 | + "xprv": "tprv8ZgxMBicQKsPen4PGtDwURYnCtVMDejyE8vVwMGhQWfVqB2FBPdekhTacDW4vmsKTsgC1wsncVqXiZdX2YFGAnKoLXYf42M78fQJFzuDYFN", |
| 59 | + "xpub": "tpubD6NzVbkrYhZ4YF6BAXtXsqCtmv1HNyvsoSXHDsJzpnTtffH1onTEwC5SnLzCHPKPebh2i7Gxvi9kJNADcpuSmH8oM3rCYcHVtdXHjpYoKnX", |
| 60 | + "pubs": [ |
| 61 | + "aba457d16a8d59151c387f24d1eb887efbe24644c1ee64b261282e7baebdb247", |
| 62 | + "c8558b7caf198e892032d91f1a48ee9bdc25462b83b4d0ac62bb7fb2a0df630e", |
| 63 | + "8a4bcaba0e970685858d133a4d0079c8b55bbc755599e212285691eb779ce3dc", |
| 64 | + "b0d68ada13e0d954b3921b88160d4453e9c151131c2b7c724e08f538a666ceb3", |
| 65 | + ] |
| 66 | + }, |
| 67 | + { |
| 68 | + "xprv": "tprv8ZgxMBicQKsPd91vCgRmbzA13wyip2RimYeVEkAyZvsEN5pUSB3T43SEBxPsytkxb42d64W2EiRE9CewpJQkzR8HKHLV8Uhk4dMF5yRPaTv", |
| 69 | + "xpub": "tpubD6NzVbkrYhZ4Wc3i6L6N1Pp7cyVeyMcdLrFGXGDGzCfdCa5F4Zs3EY46N72Ws8QDEUYBVwXfDfda2UKSseSdU1fsBegJBhGCZyxkf28bkQ6", |
| 70 | + "pubs": [ |
| 71 | + "9b4d495b74887815a1ff623c055c6eac6b6b2e07d2a016d6526ebac71dd99744", |
| 72 | + "8e971b781b7ce7ab742d80278f2dfe7dd330f3efd6d00047f4a2071f2e7553cb", |
| 73 | + "b811d66739b9f07435ccda907ec5cd225355321c35e0a7c7791232f24cf10632", |
| 74 | + "4cd27a5552c272bc80ba544e9cc6340bb906969f5e7a1510b6cef9592683fbc9", |
| 75 | + ] |
| 76 | + }, |
| 77 | + { |
| 78 | + "xprv": "tprv8ZgxMBicQKsPdEhLRxxwzTv2t18j7ruoffPeqAwVA2qXJ2P66RaMZLUWQ85SjoA7xPxdSgCB9UZ72m65qbnaLPtFTfHVP3MEmkpZk1Bv8RT", |
| 79 | + "xpub": "tpubD6NzVbkrYhZ4Whj8KcdYPsa9T2efHC6iExzS7gynaJdv8WdripPwjq6NaH5gQJGrLmvUwHY1smhiakUosXNDTEa6qfKUQdLKV6DJBre6XvQ", |
| 80 | + "pubs": [ |
| 81 | + "d0c19def28bb1b39451c1a814737615983967780d223b79969ba692182c6006b", |
| 82 | + "cb1d1b1dc62fec1894d4c3d9a1b6738e5ff9c273a64f74e9ab363095f45e9c47", |
| 83 | + "245be588f41acfaeb9481aa132717db56ee1e23eb289729fe2b8bde8f9a00830", |
| 84 | + "5bc4ad6d6187fa82728c85a073b428483295288f8aef5722e47305b5872f7169", |
| 85 | + ] |
| 86 | + }, |
| 87 | + { |
| 88 | + "xprv": "tprv8ZgxMBicQKsPcxbqxzcMAwQpiCD8x6qaZEJTxdKxw4w9GuMzDACTD9yhEsHGfqQcfYX4LivosLDDngTykYEp9JnTdcqY7cHqU8PpeFFKyV3", |
| 89 | + "xpub": "tpubD6NzVbkrYhZ4WRddreGwaM4wHDj57S2V8XuFF9NGMLjY7PckqZ23PebZR1wGA4w84uX2vZphdZVsnREjij1ibYjEBTaTVQCEZCLs4xUDapx", |
| 90 | + "pubs": [ |
| 91 | + "065cc1b92bd99e5a3e626e8296a366b2d132688eb43aea19bc14fd8f43bf07fb", |
| 92 | + "5b95633a7dda34578b6985e6bfd85d83ec38b7ded892a9b74a3d899c85890562", |
| 93 | + "dc86d434b9a34495c8e845b969d51f80d19a8df03b400353ffe8036a0c22eb60", |
| 94 | + "06c8ffde238745b29ae8a97ae533e1f3edf214bba6ec58b5e7b9451d1d61ec19", |
| 95 | + ] |
| 96 | + }, |
| 97 | + { |
| 98 | + "xprv": "tprv8ZgxMBicQKsPe6zLoU8MTTXgsdJVNBErrYGpoGwHf5VGvwUzdNc7NHeCSzkJkniCxBhZWujXjmD4HZmBBrnr3URgJjM6GxRgMmEhLdqNTWG", |
| 99 | + "xpub": "tpubD6NzVbkrYhZ4Xa28h7nwrsBoSepRXWRmRqsc5nyb5MHfmRjmFmRhYnG4d9dC7uxixN5AfsEv1Lz3mCAuWvERyvPgKozHUVjfo8EG6foJGy7", |
| 100 | + "pubs": [ |
| 101 | + "d826a0a53abb6ffc60df25b9c152870578faef4b2eb5a09bdd672bbe32cdd79b", |
| 102 | + "939365e0359ff6bc6f6404ee220714c5d4a0d1e36838b9e2081ede217674e2ba", |
| 103 | + "4e8767edcf7d3d90258cfbbea01b784f4d2de813c4277b51279cf808bac410a2", |
| 104 | + "d42a2c280940bfc6ede971ae72cde2e1df96c6da7dab06a132900c6751ade208", |
| 105 | + ] |
| 106 | + }, |
| 107 | + { |
| 108 | + "xprv": "tprv8ZgxMBicQKsPeB5o5oCsN2dVxM2mtJiYERQEBRc4JNwC1DFGYaEdNkmh8jJYVPU76YhkFoRoWTdh1p3yQGykG8TfDW34dKgrgSx28gswUyL", |
| 109 | + "xpub": "tpubD6NzVbkrYhZ4Xe7aySsTmSHcXNYi3duSoj11TweMiejaqhW3Ay4DZFPZJses4sfpk4b9VHRhn8v4cKTMjugMM3hqXcqSSmRdiW8QvASXjfY", |
| 110 | + "pubs": [ |
| 111 | + "e360564b2e0e8d06681b6336a29d0750210e8f34afd9afb5e6fd5fe6dba26c81", |
| 112 | + "76b4900f00a1dcce463b6d8e02b768518fce4f9ecd6679a13ad78ea1e4815ad3", |
| 113 | + "5575556e263c8ed52e99ab02147cc05a738869afe0039911b5a60a780f4e43d2", |
| 114 | + "593b00e2c8d4bd6dda0fd9e238888acf427bb4e128887fd5a40e0e9da78cbc01", |
| 115 | + ] |
| 116 | + }, |
| 117 | + { |
| 118 | + "xprv": "tprv8ZgxMBicQKsPfEH6jHemkGDjZRnAaKFJVGH8pQU638E6SdbX9hxit1tK2sfFPfL6KS7v8FfUKxstbfEpzSymbdfBM9Y5UkrxErF9fJaKLK3", |
| 119 | + "xpub": "tpubD6NzVbkrYhZ4YhJtcwKN9fsr8TJ6jeSD4Zsv6vWPTQ2VH7rHn6nK4WWBCzKK7FkdVVwm3iztCU1UmStY4hX6gRbBmp9UzK9C59dQEzeXS12", |
| 120 | + "pubs": [ |
| 121 | + "7631cacec3343052d87ef4d0065f61dde82d7d2db0c1cc02ef61ef3c982ea763", |
| 122 | + "c05e44a9e735d1b1bef62e2c0d886e6fb4923b2649b67828290f5cacc51c71b7", |
| 123 | + "b33198b20701afe933226c92fd0e3d51d3f266f1113d864dbd026ae3166ef7f2", |
| 124 | + "f99643ac3f4072ee4a949301e86963a9ca0ad57f2ef29f6b84fda037d7cac85b", |
| 125 | + ] |
| 126 | + }, |
| 127 | + { |
| 128 | + "xprv": "tprv8ZgxMBicQKsPdNWU38dT6aGxtqJR4oYS5kPpLVBcuKiiu7gqTYqMMqhUG6DP7pPahzPQu36sWSmeLCP1C4AwqcR5FX2RyRoZfd4B8pAnSdX", |
| 129 | + "xpub": "tpubD6NzVbkrYhZ4WqYFvnJ3Vyw5TrpME8jLf3zbd1DvKbX7jbwc5wewYLKLSFRzZWV6hZj7XhsXAy7fhE5jB25DiWyNM3ztXbsXHRVCrp5BiPY", |
| 130 | + "pubs": [ |
| 131 | + "2258b1c3160be0864a541854eec9164a572f094f7562628281a8073bb89173a7", |
| 132 | + "83df59d0a5c951cdd62b7ab225a62079f48d2a333a86e66c35420d101446e92e", |
| 133 | + "2a654bf234d819055312f9ca03fad5836f9163b09cdd24d29678f694842b874a", |
| 134 | + "aa0334ab910047387c912a21ec0dab806a47ffa38365060dbc5d47c18c6e66e7", |
| 135 | + ] |
| 136 | + }, |
| 137 | + { |
| 138 | + "xprv": "tprv8mGPkMVz5mZuJDnC2NjjAv7E9Zqa5LCgX4zawbZu5nzTtLb5kGhPwycX4H1gtW1f5ZdTKTNtQJ61hk71F2TdcQ93EFDTpUcPBr98QRji615", |
| 139 | + "xpub": "tpubDHxRtmYEE9FaBgoyv2QKaKmLibMWEfPb6NbNE7cCW4nripqrNfWz8UEPEPbHCrakwLvwFfsqoaf4pjX4gWStp4nECRf1QwBKPkLqnY8pHbj", |
| 140 | + "pubs": [ |
| 141 | + "00a9da96087a72258f83b338ef7f0ea8cbbe05da5f18f091eb397d1ecbf7c3d3", |
| 142 | + "b2749b74d51a78f5fe3ebb3a7c0ff266a468cade143dfa265c57e325177edf00", |
| 143 | + "6b8747a6bbe4440d7386658476da51f6e49a220508a7ec77fe7bccc3e7baa916", |
| 144 | + "4674bf4d9ebbe01bf0aceaca2472f63198655ecf2df810f8d69b38421972318e", |
| 145 | + ] |
| 146 | + } |
| 147 | +] |
| 148 | + |
| 149 | +CHANGE_XPRV = "tprv8ZgxMBicQKsPcyDrWwiecVnTtFmfRwbfFqEfR4ZGWvq5aTTwLBWmAm5zrbMcYtb9gQNFfhRfqhhrBG37U3nhmXxEgeEPBJGHAPrHCrAd1WX" |
| 150 | +CHANGE_XPUB = "tpubD6NzVbkrYhZ4WSFeQbPF1uSaTHHbbGnZq8qShabZwCdUQwihxaLMMFhs2kidGF2qrRKiQVqw8VoyuTHj1bZqmMXMeciaU1gBjWA1sim2zUB" |
| 151 | + |
| 152 | +# Point with no known discrete log. |
| 153 | +H_POINT = "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0" |
| 154 | + |
| 155 | + |
| 156 | +def key(hex_key): |
| 157 | + """Construct an x-only pubkey from its hex representation.""" |
| 158 | + return bytes.fromhex(hex_key) |
| 159 | + |
| 160 | +def pk(hex_key): |
| 161 | + """Construct a script expression for taproot_construct for pk(hex_key).""" |
| 162 | + return (None, CScript([bytes.fromhex(hex_key), OP_CHECKSIG])) |
| 163 | + |
| 164 | +def compute_taproot_address(pubkey, scripts): |
| 165 | + """Compute the address for a taproot output with given inner key and scripts.""" |
| 166 | + tap = taproot_construct(pubkey, scripts) |
| 167 | + assert tap.scriptPubKey[0] == 0x51 |
| 168 | + assert tap.scriptPubKey[1] == 0x20 |
| 169 | + return encode_segwit_address("bcrt", 1, tap.scriptPubKey[2:]) |
| 170 | + |
| 171 | +class WalletTaprootTest(BitcoinTestFramework): |
| 172 | + """Test generation and spending of P2TR address outputs.""" |
| 173 | + |
| 174 | + def set_test_params(self): |
| 175 | + self.num_nodes = 2 |
| 176 | + self.setup_clean_chain = True |
| 177 | + self.extra_args = [['-keypool=100'], ['-keypool=100']] |
| 178 | + self.supports_cli = False |
| 179 | + |
| 180 | + def skip_test_if_missing_module(self): |
| 181 | + self.skip_if_no_wallet() |
| 182 | + self.skip_if_no_sqlite() |
| 183 | + |
| 184 | + def setup_network(self): |
| 185 | + self.setup_nodes() |
| 186 | + |
| 187 | + def init_wallet(self, i): |
| 188 | + pass |
| 189 | + |
| 190 | + @staticmethod |
| 191 | + def rand_keys(n): |
| 192 | + ret = [] |
| 193 | + idxes = set() |
| 194 | + for _ in range(n): |
| 195 | + while True: |
| 196 | + i = random.randrange(len(KEYS)) |
| 197 | + if not i in idxes: |
| 198 | + break |
| 199 | + idxes.add(i) |
| 200 | + ret.append(KEYS[i]) |
| 201 | + return ret |
| 202 | + |
| 203 | + @staticmethod |
| 204 | + def make_desc(pattern, privmap, keys, pub_only = False): |
| 205 | + pat = pattern.replace("$H", H_POINT) |
| 206 | + for i in range(len(privmap)): |
| 207 | + if privmap[i] and not pub_only: |
| 208 | + pat = pat.replace("$%i" % (i + 1), keys[i]['xprv']) |
| 209 | + else: |
| 210 | + pat = pat.replace("$%i" % (i + 1), keys[i]['xpub']) |
| 211 | + return descsum_create(pat) |
| 212 | + |
| 213 | + @staticmethod |
| 214 | + def make_addr(treefn, keys, i): |
| 215 | + args = [] |
| 216 | + for j in range(len(keys)): |
| 217 | + args.append(keys[j]['pubs'][i]) |
| 218 | + return compute_taproot_address(*treefn(*args)) |
| 219 | + |
| 220 | + def do_test_addr(self, comment, pattern, privmap, treefn, keys): |
| 221 | + self.log.info("Testing %s address derivation" % comment) |
| 222 | + desc = self.make_desc(pattern, privmap, keys, False) |
| 223 | + desc_pub = self.make_desc(pattern, privmap, keys, True) |
| 224 | + assert_equal(self.nodes[0].getdescriptorinfo(desc)['descriptor'], desc_pub) |
| 225 | + result = self.addr_gen.importdescriptors([{"desc": desc_pub, "active": True, "timestamp": "now"}]) |
| 226 | + assert(result[0]['success']) |
| 227 | + for i in range(4): |
| 228 | + addr_g = self.addr_gen.getnewaddress(address_type='bech32') |
| 229 | + if treefn is not None: |
| 230 | + addr_r = self.make_addr(treefn, keys, i) |
| 231 | + assert_equal(addr_g, addr_r) |
| 232 | + |
| 233 | + def do_test(self, comment, pattern, privmap, treefn, nkeys): |
| 234 | + keys = self.rand_keys(nkeys) |
| 235 | + self.do_test_addr(comment, pattern, privmap, treefn, keys) |
| 236 | + |
| 237 | + def run_test(self): |
| 238 | + self.log.info("Creating wallets...") |
| 239 | + self.nodes[0].createwallet(wallet_name="addr_gen", descriptors=True, disable_private_keys=True, blank=True) |
| 240 | + self.addr_gen = self.nodes[0].get_wallet_rpc("addr_gen") |
| 241 | + |
| 242 | + self.do_test( |
| 243 | + "tr(XPRV)", |
| 244 | + "tr($1/*)", |
| 245 | + [True], |
| 246 | + lambda k1: (key(k1), []), |
| 247 | + 1 |
| 248 | + ) |
| 249 | + self.do_test( |
| 250 | + "tr(H,XPRV)", |
| 251 | + "tr($H,pk($1/*))", |
| 252 | + [True], |
| 253 | + lambda k1: (key(H_POINT), [pk(k1)]), |
| 254 | + 1 |
| 255 | + ) |
| 256 | + self.do_test( |
| 257 | + "tr(XPRV,{H,{H,XPUB}})", |
| 258 | + "tr($1/*,{pk($H),{pk($H),pk($2/*)}})", |
| 259 | + [True, False], |
| 260 | + lambda k1, k2: (key(k1), [pk(H_POINT), [pk(H_POINT), pk(k2)]]), |
| 261 | + 2 |
| 262 | + ) |
| 263 | + self.do_test( |
| 264 | + "tr(XPUB,{{H,{H,XPUB}},{H,{H,{H,XPRV}}}})", |
| 265 | + "tr($1/*,{{pk($H),{pk($H),pk($2/*)}},{pk($H),{pk($H),{pk($H),pk($3/*)}}}})", |
| 266 | + [False, False, True], |
| 267 | + lambda k1, k2, k3: (key(k1), [[pk(H_POINT), [pk(H_POINT), pk(k2)]], [pk(H_POINT), [pk(H_POINT), [pk(H_POINT), pk(k3)]]]]), |
| 268 | + 3 |
| 269 | + ) |
| 270 | + |
| 271 | +if __name__ == '__main__': |
| 272 | + WalletTaprootTest().main() |
0 commit comments