mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-19 14:53:43 +01:00
c7376babd1doc: Clarify distinction between util and common libraries in libraries.md (Ryan Ofsky)4f74c59334util: Move util/string.h functions to util namespace (Ryan Ofsky)4d05d3f3b4util: add TransactionError includes and namespace declarations (Ryan Ofsky)680eafdc74util: move fees.h and error.h to common/messages.h (Ryan Ofsky)02e62c6c9acommon: Add PSBTError enum (Ryan Ofsky)0d44c44ae3util: move error.h TransactionError enum to node/types.h (Ryan Ofsky)9bcce2608dutil: move spanparsing.h to script/parsing.h (Ryan Ofsky)6dd2ad4792util: move spanparsing.h Split functions to string.h (Ryan Ofsky)23cc8ddff4util: move HexStr and HexDigit from util to crypto (TheCharlatan)6861f954f8util: move util/message to common/signmessage (Ryan Ofsky)cc5f29fbeabuild: move memory_cleanse from util to crypto (Ryan Ofsky)5b9309420cbuild: move chainparamsbase from util to common (Ryan Ofsky)ffa27af24dtest: Add check-deps.sh script to check for unexpected library dependencies (Ryan Ofsky) Pull request description: Remove `fees.h`, `errors.h`, and `spanparsing.h` from the util library. Specifically: - Move `Split` functions from `util/spanparsing.h` to `util/string.h`, using `util` namespace for clarity. - Move remaining spanparsing functions to `script/parsing.h` since they are used for descriptor and miniscript parsing. - Combine `util/fees.h` and `util/errors.h` into `common/messages.h` so there is a place for simple functions that generate user messages to live, and these functions are not part of the util library. Motivation for this change is that the util library is a dependency of the kernel, and we should remove functionality from util that shouldn't be called by kernel code or kernel applications. These changes should also improve code organization and make functions easier to discover. Some of these same moves are (or were) part of #28690, but did not help with code organization, or made it worse, so it is better to move them and clean them up in the same PR so code only has to change one time. ACKs for top commit: achow101: ACKc7376babd1TheCharlatan: Re-ACKc7376babd1hebasto: re-ACKc7376babd1. Tree-SHA512: 5bcef16c1255463b1b69270548711e7ff78ca0dd34e300b95e3ca1ce52ceb34f83d9ddb2839e83800ba36b200de30396e504bbb04fa02c6d0c24a16d06ae523d
349 lines
18 KiB
C++
349 lines
18 KiB
C++
// Copyright (c) 2012-2022 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <key.h>
|
|
|
|
#include <common/system.h>
|
|
#include <key_io.h>
|
|
#include <span.h>
|
|
#include <streams.h>
|
|
#include <test/util/random.h>
|
|
#include <test/util/setup_common.h>
|
|
#include <uint256.h>
|
|
#include <util/strencodings.h>
|
|
#include <util/string.h>
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
using util::ToString;
|
|
|
|
static const std::string strSecret1 = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj";
|
|
static const std::string strSecret2 = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3";
|
|
static const std::string strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw";
|
|
static const std::string strSecret2C = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g";
|
|
static const std::string addr1 = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ";
|
|
static const std::string addr2 = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ";
|
|
static const std::string addr1C = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs";
|
|
static const std::string addr2C = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs";
|
|
|
|
static const std::string strAddressBad = "1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF";
|
|
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup)
|
|
|
|
BOOST_AUTO_TEST_CASE(key_test1)
|
|
{
|
|
CKey key1 = DecodeSecret(strSecret1);
|
|
BOOST_CHECK(key1.IsValid() && !key1.IsCompressed());
|
|
CKey key2 = DecodeSecret(strSecret2);
|
|
BOOST_CHECK(key2.IsValid() && !key2.IsCompressed());
|
|
CKey key1C = DecodeSecret(strSecret1C);
|
|
BOOST_CHECK(key1C.IsValid() && key1C.IsCompressed());
|
|
CKey key2C = DecodeSecret(strSecret2C);
|
|
BOOST_CHECK(key2C.IsValid() && key2C.IsCompressed());
|
|
CKey bad_key = DecodeSecret(strAddressBad);
|
|
BOOST_CHECK(!bad_key.IsValid());
|
|
|
|
CPubKey pubkey1 = key1. GetPubKey();
|
|
CPubKey pubkey2 = key2. GetPubKey();
|
|
CPubKey pubkey1C = key1C.GetPubKey();
|
|
CPubKey pubkey2C = key2C.GetPubKey();
|
|
|
|
BOOST_CHECK(key1.VerifyPubKey(pubkey1));
|
|
BOOST_CHECK(!key1.VerifyPubKey(pubkey1C));
|
|
BOOST_CHECK(!key1.VerifyPubKey(pubkey2));
|
|
BOOST_CHECK(!key1.VerifyPubKey(pubkey2C));
|
|
|
|
BOOST_CHECK(!key1C.VerifyPubKey(pubkey1));
|
|
BOOST_CHECK(key1C.VerifyPubKey(pubkey1C));
|
|
BOOST_CHECK(!key1C.VerifyPubKey(pubkey2));
|
|
BOOST_CHECK(!key1C.VerifyPubKey(pubkey2C));
|
|
|
|
BOOST_CHECK(!key2.VerifyPubKey(pubkey1));
|
|
BOOST_CHECK(!key2.VerifyPubKey(pubkey1C));
|
|
BOOST_CHECK(key2.VerifyPubKey(pubkey2));
|
|
BOOST_CHECK(!key2.VerifyPubKey(pubkey2C));
|
|
|
|
BOOST_CHECK(!key2C.VerifyPubKey(pubkey1));
|
|
BOOST_CHECK(!key2C.VerifyPubKey(pubkey1C));
|
|
BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));
|
|
BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));
|
|
|
|
BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(PKHash(pubkey1)));
|
|
BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(PKHash(pubkey2)));
|
|
BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(PKHash(pubkey1C)));
|
|
BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(PKHash(pubkey2C)));
|
|
|
|
for (int n=0; n<16; n++)
|
|
{
|
|
std::string strMsg = strprintf("Very secret message %i: 11", n);
|
|
uint256 hashMsg = Hash(strMsg);
|
|
|
|
// normal signatures
|
|
|
|
std::vector<unsigned char> sign1, sign2, sign1C, sign2C;
|
|
|
|
BOOST_CHECK(key1.Sign (hashMsg, sign1));
|
|
BOOST_CHECK(key2.Sign (hashMsg, sign2));
|
|
BOOST_CHECK(key1C.Sign(hashMsg, sign1C));
|
|
BOOST_CHECK(key2C.Sign(hashMsg, sign2C));
|
|
|
|
BOOST_CHECK( pubkey1.Verify(hashMsg, sign1));
|
|
BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2));
|
|
BOOST_CHECK( pubkey1.Verify(hashMsg, sign1C));
|
|
BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2C));
|
|
|
|
BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1));
|
|
BOOST_CHECK( pubkey2.Verify(hashMsg, sign2));
|
|
BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1C));
|
|
BOOST_CHECK( pubkey2.Verify(hashMsg, sign2C));
|
|
|
|
BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1));
|
|
BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2));
|
|
BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1C));
|
|
BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2C));
|
|
|
|
BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1));
|
|
BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2));
|
|
BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1C));
|
|
BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2C));
|
|
|
|
// compact signatures (with key recovery)
|
|
|
|
std::vector<unsigned char> csign1, csign2, csign1C, csign2C;
|
|
|
|
BOOST_CHECK(key1.SignCompact (hashMsg, csign1));
|
|
BOOST_CHECK(key2.SignCompact (hashMsg, csign2));
|
|
BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C));
|
|
BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C));
|
|
|
|
CPubKey rkey1, rkey2, rkey1C, rkey2C;
|
|
|
|
BOOST_CHECK(rkey1.RecoverCompact (hashMsg, csign1));
|
|
BOOST_CHECK(rkey2.RecoverCompact (hashMsg, csign2));
|
|
BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C));
|
|
BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C));
|
|
|
|
BOOST_CHECK(rkey1 == pubkey1);
|
|
BOOST_CHECK(rkey2 == pubkey2);
|
|
BOOST_CHECK(rkey1C == pubkey1C);
|
|
BOOST_CHECK(rkey2C == pubkey2C);
|
|
}
|
|
|
|
// test deterministic signing
|
|
|
|
std::vector<unsigned char> detsig, detsigc;
|
|
std::string strMsg = "Very deterministic message";
|
|
uint256 hashMsg = Hash(strMsg);
|
|
BOOST_CHECK(key1.Sign(hashMsg, detsig));
|
|
BOOST_CHECK(key1C.Sign(hashMsg, detsigc));
|
|
BOOST_CHECK(detsig == detsigc);
|
|
BOOST_CHECK(detsig == ParseHex("304402205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d022014ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"));
|
|
BOOST_CHECK(key2.Sign(hashMsg, detsig));
|
|
BOOST_CHECK(key2C.Sign(hashMsg, detsigc));
|
|
BOOST_CHECK(detsig == detsigc);
|
|
BOOST_CHECK(detsig == ParseHex("3044022052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd5022061d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"));
|
|
BOOST_CHECK(key1.SignCompact(hashMsg, detsig));
|
|
BOOST_CHECK(key1C.SignCompact(hashMsg, detsigc));
|
|
BOOST_CHECK(detsig == ParseHex("1c5dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"));
|
|
BOOST_CHECK(detsigc == ParseHex("205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"));
|
|
BOOST_CHECK(key2.SignCompact(hashMsg, detsig));
|
|
BOOST_CHECK(key2C.SignCompact(hashMsg, detsigc));
|
|
BOOST_CHECK(detsig == ParseHex("1c52d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"));
|
|
BOOST_CHECK(detsigc == ParseHex("2052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(key_signature_tests)
|
|
{
|
|
// When entropy is specified, we should see at least one high R signature within 20 signatures
|
|
CKey key = DecodeSecret(strSecret1);
|
|
std::string msg = "A message to be signed";
|
|
uint256 msg_hash = Hash(msg);
|
|
std::vector<unsigned char> sig;
|
|
bool found = false;
|
|
|
|
for (int i = 1; i <=20; ++i) {
|
|
sig.clear();
|
|
BOOST_CHECK(key.Sign(msg_hash, sig, false, i));
|
|
found = sig[3] == 0x21 && sig[4] == 0x00;
|
|
if (found) {
|
|
break;
|
|
}
|
|
}
|
|
BOOST_CHECK(found);
|
|
|
|
// When entropy is not specified, we should always see low R signatures that are less than or equal to 70 bytes in 256 tries
|
|
// The low R signatures should always have the value of their "length of R" byte less than or equal to 32
|
|
// We should see at least one signature that is less than 70 bytes.
|
|
bool found_small = false;
|
|
bool found_big = false;
|
|
bool bad_sign = false;
|
|
for (int i = 0; i < 256; ++i) {
|
|
sig.clear();
|
|
std::string msg = "A message to be signed" + ToString(i);
|
|
msg_hash = Hash(msg);
|
|
if (!key.Sign(msg_hash, sig)) {
|
|
bad_sign = true;
|
|
break;
|
|
}
|
|
// sig.size() > 70 implies sig[3] > 32, because S is always low.
|
|
// But check both conditions anyway, just in case this implication is broken for some reason
|
|
if (sig[3] > 32 || sig.size() > 70) {
|
|
found_big = true;
|
|
break;
|
|
}
|
|
found_small |= sig.size() < 70;
|
|
}
|
|
BOOST_CHECK(!bad_sign);
|
|
BOOST_CHECK(!found_big);
|
|
BOOST_CHECK(found_small);
|
|
}
|
|
|
|
static CPubKey UnserializePubkey(const std::vector<uint8_t>& data)
|
|
{
|
|
DataStream stream{};
|
|
stream << data;
|
|
CPubKey pubkey;
|
|
stream >> pubkey;
|
|
return pubkey;
|
|
}
|
|
|
|
static unsigned int GetLen(unsigned char chHeader)
|
|
{
|
|
if (chHeader == 2 || chHeader == 3)
|
|
return CPubKey::COMPRESSED_SIZE;
|
|
if (chHeader == 4 || chHeader == 6 || chHeader == 7)
|
|
return CPubKey::SIZE;
|
|
return 0;
|
|
}
|
|
|
|
static void CmpSerializationPubkey(const CPubKey& pubkey)
|
|
{
|
|
DataStream stream{};
|
|
stream << pubkey;
|
|
CPubKey pubkey2;
|
|
stream >> pubkey2;
|
|
BOOST_CHECK(pubkey == pubkey2);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(pubkey_unserialize)
|
|
{
|
|
for (uint8_t i = 2; i <= 7; ++i) {
|
|
CPubKey key = UnserializePubkey({0x02});
|
|
BOOST_CHECK(!key.IsValid());
|
|
CmpSerializationPubkey(key);
|
|
key = UnserializePubkey(std::vector<uint8_t>(GetLen(i), i));
|
|
CmpSerializationPubkey(key);
|
|
if (i == 5) {
|
|
BOOST_CHECK(!key.IsValid());
|
|
} else {
|
|
BOOST_CHECK(key.IsValid());
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(bip340_test_vectors)
|
|
{
|
|
static const std::vector<std::pair<std::array<std::string, 3>, bool>> VECTORS = {
|
|
{{"F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9", "0000000000000000000000000000000000000000000000000000000000000000", "E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA821525F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0"}, true},
|
|
{{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A"}, true},
|
|
{{"DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8", "7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C", "5831AAEED7B44BB74E5EAB94BA9D4294C49BCF2A60728D8B4C200F50DD313C1BAB745879A5AD954A72C45A91C3A51D3C7ADEA98D82F8481E0E1E03674A6F3FB7"}, true},
|
|
{{"25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "7EB0509757E246F19449885651611CB965ECC1A187DD51B64FDA1EDC9637D5EC97582B9CB13DB3933705B32BA982AF5AF25FD78881EBB32771FC5922EFC66EA3"}, true},
|
|
{{"D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9", "4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703", "00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6376AFB1548AF603B3EB45C9F8207DEE1060CB71C04E80F593060B07D28308D7F4"}, true},
|
|
{{"EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"}, false},
|
|
{{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A14602975563CC27944640AC607CD107AE10923D9EF7A73C643E166BE5EBEAFA34B1AC553E2"}, false},
|
|
{{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "1FA62E331EDBC21C394792D2AB1100A7B432B013DF3F6FF4F99FCB33E0E1515F28890B3EDB6E7189B630448B515CE4F8622A954CFE545735AAEA5134FCCDB2BD"}, false},
|
|
{{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769961764B3AA9B2FFCB6EF947B6887A226E8D7C93E00C5ED0C1834FF0D0C2E6DA6"}, false},
|
|
{{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "0000000000000000000000000000000000000000000000000000000000000000123DDA8328AF9C23A94C1FEECFD123BA4FB73476F0D594DCB65C6425BD186051"}, false},
|
|
{{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "00000000000000000000000000000000000000000000000000000000000000017615FBAF5AE28864013C099742DEADB4DBA87F11AC6754F93780D5A1837CF197"}, false},
|
|
{{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"}, false},
|
|
{{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"}, false},
|
|
{{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"}, false},
|
|
{{"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"}, false}
|
|
};
|
|
|
|
for (const auto& test : VECTORS) {
|
|
auto pubkey = ParseHex(test.first[0]);
|
|
auto msg = ParseHex(test.first[1]);
|
|
auto sig = ParseHex(test.first[2]);
|
|
BOOST_CHECK_EQUAL(XOnlyPubKey(pubkey).VerifySchnorr(uint256(msg), sig), test.second);
|
|
}
|
|
|
|
static const std::vector<std::array<std::string, 5>> SIGN_VECTORS = {
|
|
{{"0000000000000000000000000000000000000000000000000000000000000003", "F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA821525F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0"}},
|
|
{{"B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF", "DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "0000000000000000000000000000000000000000000000000000000000000001", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A"}},
|
|
{{"C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9", "DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8", "C87AA53824B4D7AE2EB035A2B5BBBCCC080E76CDC6D1692C4B0B62D798E6D906", "7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C", "5831AAEED7B44BB74E5EAB94BA9D4294C49BCF2A60728D8B4C200F50DD313C1BAB745879A5AD954A72C45A91C3A51D3C7ADEA98D82F8481E0E1E03674A6F3FB7"}},
|
|
{{"0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710", "25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "7EB0509757E246F19449885651611CB965ECC1A187DD51B64FDA1EDC9637D5EC97582B9CB13DB3933705B32BA982AF5AF25FD78881EBB32771FC5922EFC66EA3"}},
|
|
};
|
|
|
|
for (const auto& [sec_hex, pub_hex, aux_hex, msg_hex, sig_hex] : SIGN_VECTORS) {
|
|
auto sec = ParseHex(sec_hex);
|
|
auto pub = ParseHex(pub_hex);
|
|
uint256 aux256(ParseHex(aux_hex));
|
|
uint256 msg256(ParseHex(msg_hex));
|
|
auto sig = ParseHex(sig_hex);
|
|
unsigned char sig64[64];
|
|
|
|
// Run the untweaked test vectors above, comparing with exact expected signature.
|
|
CKey key;
|
|
key.Set(sec.begin(), sec.end(), true);
|
|
XOnlyPubKey pubkey(key.GetPubKey());
|
|
BOOST_CHECK(std::equal(pubkey.begin(), pubkey.end(), pub.begin(), pub.end()));
|
|
bool ok = key.SignSchnorr(msg256, sig64, nullptr, aux256);
|
|
BOOST_CHECK(ok);
|
|
BOOST_CHECK(std::vector<unsigned char>(sig64, sig64 + 64) == sig);
|
|
// Verify those signatures for good measure.
|
|
BOOST_CHECK(pubkey.VerifySchnorr(msg256, sig64));
|
|
|
|
// Do 10 iterations where we sign with a random Merkle root to tweak,
|
|
// and compare against the resulting tweaked keys, with random aux.
|
|
// In iteration i=0 we tweak with empty Merkle tree.
|
|
for (int i = 0; i < 10; ++i) {
|
|
uint256 merkle_root;
|
|
if (i) merkle_root = InsecureRand256();
|
|
auto tweaked = pubkey.CreateTapTweak(i ? &merkle_root : nullptr);
|
|
BOOST_CHECK(tweaked);
|
|
XOnlyPubKey tweaked_key = tweaked->first;
|
|
aux256 = InsecureRand256();
|
|
bool ok = key.SignSchnorr(msg256, sig64, &merkle_root, aux256);
|
|
BOOST_CHECK(ok);
|
|
BOOST_CHECK(tweaked_key.VerifySchnorr(msg256, sig64));
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(key_ellswift)
|
|
{
|
|
for (const auto& secret : {strSecret1, strSecret2, strSecret1C, strSecret2C}) {
|
|
CKey key = DecodeSecret(secret);
|
|
BOOST_CHECK(key.IsValid());
|
|
|
|
uint256 ent32 = InsecureRand256();
|
|
auto ellswift = key.EllSwiftCreate(AsBytes(Span{ent32}));
|
|
|
|
CPubKey decoded_pubkey = ellswift.Decode();
|
|
if (!key.IsCompressed()) {
|
|
// The decoding constructor returns a compressed pubkey. If the
|
|
// original was uncompressed, we must decompress the decoded one
|
|
// to compare.
|
|
decoded_pubkey.Decompress();
|
|
}
|
|
BOOST_CHECK(key.GetPubKey() == decoded_pubkey);
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(bip341_test_h)
|
|
{
|
|
std::vector<unsigned char> G_uncompressed = ParseHex("0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8");
|
|
HashWriter hw;
|
|
hw.write(MakeByteSpan(G_uncompressed));
|
|
XOnlyPubKey H{hw.GetSHA256()};
|
|
BOOST_CHECK(XOnlyPubKey::NUMS_H == H);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|