mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-06-18 04:41:21 +02:00
This method was introduced as a pre-requirement for the v2 transport protocol back then (see PR #14047, commit 463921bb), when it was still BIP151. With the replacement BIP324, this is not needed anymore, and it's also unlikely that any other proposal would need to negate private keys at this abstraction level. (If there is really demand, it's trivial to reintroduce the method.)
347 lines
18 KiB
C++
347 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>
|
|
|
|
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()
|