tests: implement BIP341 test vectors

This commit is contained in:
Pieter Wuille
2021-10-27 19:16:01 -04:00
parent ac3037df11
commit f1c33ee4ac
6 changed files with 577 additions and 1 deletions

View File

@@ -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()