diff options
author | W. J. van der Laan <laanwj@protonmail.com> | 2021-11-15 18:27:49 +0100 |
---|---|---|
committer | W. J. van der Laan <laanwj@protonmail.com> | 2021-11-15 20:32:42 +0100 |
commit | 5ccab7187b35142e03c15dd55390e45b3d233c52 (patch) | |
tree | 14c15a51221682a2c07c78026096b89fa83e2689 /src/test/script_tests.cpp | |
parent | 7f0f853373703a020529dd9394fca525475086b7 (diff) | |
parent | f1c33ee4ac1056289f2e67b75755388549ada4ca (diff) | |
download | bitcoin-5ccab7187b35142e03c15dd55390e45b3d233c52.tar.xz |
Merge bitcoin/bitcoin#23394: Taproot wallet test vectors (generation+tests)
f1c33ee4ac1056289f2e67b75755388549ada4ca tests: implement BIP341 test vectors (Pieter Wuille)
ac3037df1196b1d95ade2dfad4699ad3a6074903 tests: BIP341 test vector generation (Pieter Wuille)
ca83ffc2ea5fe08f16fff7df71c040d067f2afb0 tests: add deterministic signing mode to ECDSA (Pieter Wuille)
c98c53f20cadeda53f6a9323f72363593d174f68 tests: abstract out precomputed BIP341 signature hash elements (Pieter Wuille)
a5bde018b42cd38979fee71d870e0140b10c73d6 tests: give feature_taproot access to sighash preimages (Pieter Wuille)
51408250969e7ed171378369a995c90d4f813189 tests: add more fields to TaprootInfo (Pieter Wuille)
2478c6730a81dda3c56cb99087caf6abe49c85f5 Make signing follow BIP340 exactly w.r.t. aux randomness (Pieter Wuille)
Pull request description:
This PR adds code to `test/functional/feature_taproot.py` which runs through a (deterministic) scenario covering several aspects of the wallet side of BIP341 (scriptPubKey computation from keys/scripts, control block computation, key path spending), with the ability to output test vectors in mediawiki format based on this scenario. The generated tests are then also included directly in `src/test/script_tests.cpp` and `src/test/script_standard_tests.cpp`.
I intend to add these test vectors to BIP341 itself: https://github.com/bitcoin/bips/pull/1225
ACKs for top commit:
laanwj:
Code review ACK f1c33ee4ac1056289f2e67b75755388549ada4ca
Tree-SHA512: fcf7109539cb214d3190516b205cd32d2b1b452f14aa66f4107acfaa8bfc7d368f626857f1935665a4342eabc0b9ee8aba608a7c0a2494bec0b498e723439c9d
Diffstat (limited to 'src/test/script_tests.cpp')
-rw-r--r-- | src/test/script_tests.cpp | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 2c39cbffb9..a89eab68e9 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <test/data/script_tests.json.h> +#include <test/data/bip341_wallet_vectors.json.h> #include <core_io.h> #include <fs.h> @@ -1743,4 +1744,79 @@ BOOST_AUTO_TEST_CASE(script_assets_test) file.close(); } +BOOST_AUTO_TEST_CASE(bip341_keypath_test_vectors) +{ + UniValue tests; + tests.read((const char*)json_tests::bip341_wallet_vectors, sizeof(json_tests::bip341_wallet_vectors)); + + const auto& vectors = tests["keyPathSpending"]; + + for (const auto& vec : vectors.getValues()) { + auto txhex = ParseHex(vec["given"]["rawUnsignedTx"].get_str()); + CMutableTransaction tx; + VectorReader(SER_NETWORK, PROTOCOL_VERSION, txhex, 0) >> tx; + std::vector<CTxOut> utxos; + for (const auto& utxo_spent : vec["given"]["utxosSpent"].getValues()) { + auto script_bytes = ParseHex(utxo_spent["scriptPubKey"].get_str()); + CScript script{script_bytes.begin(), script_bytes.end()}; + CAmount amount{utxo_spent["amountSats"].get_int()}; + utxos.emplace_back(amount, script); + } + + PrecomputedTransactionData txdata; + txdata.Init(tx, std::vector<CTxOut>{utxos}, true); + + BOOST_CHECK(txdata.m_bip341_taproot_ready); + BOOST_CHECK_EQUAL(HexStr(txdata.m_spent_amounts_single_hash), vec["intermediary"]["hashAmounts"].get_str()); + BOOST_CHECK_EQUAL(HexStr(txdata.m_outputs_single_hash), vec["intermediary"]["hashOutputs"].get_str()); + BOOST_CHECK_EQUAL(HexStr(txdata.m_prevouts_single_hash), vec["intermediary"]["hashPrevouts"].get_str()); + BOOST_CHECK_EQUAL(HexStr(txdata.m_spent_scripts_single_hash), vec["intermediary"]["hashScriptPubkeys"].get_str()); + BOOST_CHECK_EQUAL(HexStr(txdata.m_sequences_single_hash), vec["intermediary"]["hashSequences"].get_str()); + + for (const auto& input : vec["inputSpending"].getValues()) { + int txinpos = input["given"]["txinIndex"].get_int(); + int hashtype = input["given"]["hashType"].get_int(); + + // Load key. + auto privkey = ParseHex(input["given"]["internalPrivkey"].get_str()); + CKey key; + key.Set(privkey.begin(), privkey.end(), true); + + // Load Merkle root. + uint256 merkle_root; + if (!input["given"]["merkleRoot"].isNull()) { + merkle_root = uint256{ParseHex(input["given"]["merkleRoot"].get_str())}; + } + + // Compute and verify (internal) public key. + XOnlyPubKey pubkey{key.GetPubKey()}; + BOOST_CHECK_EQUAL(HexStr(pubkey), input["intermediary"]["internalPubkey"].get_str()); + + // Sign and verify signature. + FlatSigningProvider provider; + provider.keys[key.GetPubKey().GetID()] = key; + MutableTransactionSignatureCreator creator(&tx, txinpos, utxos[txinpos].nValue, &txdata, hashtype); + std::vector<unsigned char> signature; + BOOST_CHECK(creator.CreateSchnorrSig(provider, signature, pubkey, nullptr, &merkle_root, SigVersion::TAPROOT)); + BOOST_CHECK_EQUAL(HexStr(signature), input["expected"]["witness"][0].get_str()); + + // We can't observe the tweak used inside the signing logic, so verify by recomputing it. + BOOST_CHECK_EQUAL(HexStr(pubkey.ComputeTapTweakHash(merkle_root.IsNull() ? nullptr : &merkle_root)), input["intermediary"]["tweak"].get_str()); + + // We can't observe the sighash used inside the signing logic, so verify by recomputing it. + ScriptExecutionData sed; + sed.m_annex_init = true; + sed.m_annex_present = false; + uint256 sighash; + BOOST_CHECK(SignatureHashSchnorr(sighash, sed, tx, txinpos, hashtype, SigVersion::TAPROOT, txdata, MissingDataBehavior::FAIL)); + BOOST_CHECK_EQUAL(HexStr(sighash), input["intermediary"]["sigHash"].get_str()); + + // To verify the sigmsg, hash the expected sigmsg, and compare it with the (expected) sighash. + BOOST_CHECK_EQUAL(HexStr((CHashWriter(HASHER_TAPSIGHASH) << MakeSpan(ParseHex(input["intermediary"]["sigMsg"].get_str()))).GetSHA256()), input["intermediary"]["sigHash"].get_str()); + } + + } + +} + BOOST_AUTO_TEST_SUITE_END() |