mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-08 10:31:50 -05:00
Support for Schnorr signatures and integration in SignatureCheckers (BIP 340)
This enables the schnorrsig module in libsecp256k1, adds the relevant types and functions to src/pubkey, as well as in higher-level `SignatureChecker` classes. The (verification side of the) BIP340 test vectors is also added.
This commit is contained in:
parent
5de246ca81
commit
0664f5fe1f
14 changed files with 165 additions and 13 deletions
|
@ -12,7 +12,7 @@
|
|||
</ItemGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\src\secp256k1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
|
|
@ -1645,7 +1645,7 @@ if test x$need_bundled_univalue = xyes; then
|
|||
AC_CONFIG_SUBDIRS([src/univalue])
|
||||
fi
|
||||
|
||||
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --with-bignum=no --enable-module-recovery"
|
||||
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --with-bignum=no --enable-module-recovery --enable-module-schnorrsig --enable-experimental"
|
||||
AC_CONFIG_SUBDIRS([src/secp256k1])
|
||||
|
||||
AC_OUTPUT
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_recovery.h>
|
||||
#include <secp256k1_schnorrsig.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -166,6 +167,20 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
|
|||
return 1;
|
||||
}
|
||||
|
||||
XOnlyPubKey::XOnlyPubKey(Span<const unsigned char> bytes)
|
||||
{
|
||||
assert(bytes.size() == 32);
|
||||
std::copy(bytes.begin(), bytes.end(), m_keydata.begin());
|
||||
}
|
||||
|
||||
bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> sigbytes) const
|
||||
{
|
||||
assert(sigbytes.size() == 64);
|
||||
secp256k1_xonly_pubkey pubkey;
|
||||
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &pubkey, m_keydata.data())) return false;
|
||||
return secp256k1_schnorrsig_verify(secp256k1_context_verify, sigbytes.data(), msg.begin(), &pubkey);
|
||||
}
|
||||
|
||||
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
|
|
20
src/pubkey.h
20
src/pubkey.h
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <hash.h>
|
||||
#include <serialize.h>
|
||||
#include <span.h>
|
||||
#include <uint256.h>
|
||||
|
||||
#include <stdexcept>
|
||||
|
@ -206,6 +207,25 @@ public:
|
|||
bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;
|
||||
};
|
||||
|
||||
class XOnlyPubKey
|
||||
{
|
||||
private:
|
||||
uint256 m_keydata;
|
||||
|
||||
public:
|
||||
/** Construct an x-only pubkey from exactly 32 bytes. */
|
||||
XOnlyPubKey(Span<const unsigned char> bytes);
|
||||
|
||||
/** Verify a Schnorr signature against this public key.
|
||||
*
|
||||
* sigbytes must be exactly 64 bytes.
|
||||
*/
|
||||
bool VerifySchnorr(const uint256& msg, Span<const unsigned char> sigbytes) const;
|
||||
|
||||
const unsigned char& operator[](int pos) const { return *(m_keydata.begin() + pos); }
|
||||
size_t size() const { return m_keydata.size(); }
|
||||
};
|
||||
|
||||
struct CExtPubKey {
|
||||
unsigned char nDepth;
|
||||
unsigned char vchFingerprint[4];
|
||||
|
|
|
@ -1521,6 +1521,12 @@ bool GenericTransactionSignatureChecker<T>::VerifyECDSASignature(const std::vect
|
|||
return pubkey.Verify(sighash, vchSig);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool GenericTransactionSignatureChecker<T>::VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const
|
||||
{
|
||||
return pubkey.VerifySchnorr(sighash, sig);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
|
||||
{
|
||||
|
@ -1543,6 +1549,30 @@ bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vecto
|
|||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool GenericTransactionSignatureChecker<T>::CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey_in, SigVersion sigversion, ScriptError* serror) const
|
||||
{
|
||||
assert(sigversion == SigVersion::TAPROOT);
|
||||
// Schnorr signatures have 32-byte public keys. The caller is responsible for enforcing this.
|
||||
assert(pubkey_in.size() == 32);
|
||||
if (sig.size() != 64 && sig.size() != 65) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_SIZE);
|
||||
|
||||
XOnlyPubKey pubkey{pubkey_in};
|
||||
|
||||
uint8_t hashtype = SIGHASH_DEFAULT;
|
||||
if (sig.size() == 65) {
|
||||
hashtype = SpanPopBack(sig);
|
||||
if (hashtype == SIGHASH_DEFAULT) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_HASHTYPE);
|
||||
}
|
||||
uint256 sighash;
|
||||
assert(this->txdata);
|
||||
if (!SignatureHashSchnorr(sighash, *txTo, nIn, hashtype, sigversion, *this->txdata)) {
|
||||
return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_HASHTYPE);
|
||||
}
|
||||
if (!VerifySchnorrSignature(sig, pubkey, sighash)) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool GenericTransactionSignatureChecker<T>::CheckLockTime(const CScriptNum& nLockTime) const
|
||||
{
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
#define BITCOIN_SCRIPT_INTERPRETER_H
|
||||
|
||||
#include <script/script_error.h>
|
||||
#include <span.h>
|
||||
#include <primitives/transaction.h>
|
||||
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
class CPubKey;
|
||||
class XOnlyPubKey;
|
||||
class CScript;
|
||||
class CTransaction;
|
||||
class CTxOut;
|
||||
|
@ -176,6 +178,11 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptError* serror = nullptr) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool CheckLockTime(const CScriptNum& nLockTime) const
|
||||
{
|
||||
return false;
|
||||
|
@ -200,11 +207,13 @@ private:
|
|||
|
||||
protected:
|
||||
virtual bool VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||
virtual bool VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const;
|
||||
|
||||
public:
|
||||
GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
|
||||
GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
|
||||
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
|
||||
bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptError* serror = nullptr) const override;
|
||||
bool CheckLockTime(const CScriptNum& nLockTime) const override;
|
||||
bool CheckSequence(const CScriptNum& nSequence) const override;
|
||||
};
|
||||
|
|
|
@ -91,6 +91,12 @@ std::string ScriptErrorString(const ScriptError serror)
|
|||
return "Witness provided for non-witness script";
|
||||
case SCRIPT_ERR_WITNESS_PUBKEYTYPE:
|
||||
return "Using non-compressed keys in segwit";
|
||||
case SCRIPT_ERR_SCHNORR_SIG_SIZE:
|
||||
return "Invalid Schnorr signature size";
|
||||
case SCRIPT_ERR_SCHNORR_SIG_HASHTYPE:
|
||||
return "Invalid Schnorr signature hash type";
|
||||
case SCRIPT_ERR_SCHNORR_SIG:
|
||||
return "Invalid Schnorr signature";
|
||||
case SCRIPT_ERR_OP_CODESEPARATOR:
|
||||
return "Using OP_CODESEPARATOR in non-witness script";
|
||||
case SCRIPT_ERR_SIG_FINDANDDELETE:
|
||||
|
|
|
@ -66,6 +66,11 @@ typedef enum ScriptError_t
|
|||
SCRIPT_ERR_WITNESS_UNEXPECTED,
|
||||
SCRIPT_ERR_WITNESS_PUBKEYTYPE,
|
||||
|
||||
/* Taproot */
|
||||
SCRIPT_ERR_SCHNORR_SIG_SIZE,
|
||||
SCRIPT_ERR_SCHNORR_SIG_HASHTYPE,
|
||||
SCRIPT_ERR_SCHNORR_SIG,
|
||||
|
||||
/* Constant scriptCode */
|
||||
SCRIPT_ERR_OP_CODESEPARATOR,
|
||||
SCRIPT_ERR_SIG_FINDANDDELETE,
|
||||
|
|
|
@ -22,8 +22,9 @@ namespace {
|
|||
class CSignatureCache
|
||||
{
|
||||
private:
|
||||
//! Entries are SHA256(nonce || signature hash || public key || signature):
|
||||
CSHA256 m_salted_hasher;
|
||||
//! Entries are SHA256(nonce || 'E' or 'S' || 31 zero bytes || signature hash || public key || signature):
|
||||
CSHA256 m_salted_hasher_ecdsa;
|
||||
CSHA256 m_salted_hasher_schnorr;
|
||||
typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type;
|
||||
map_type setValid;
|
||||
boost::shared_mutex cs_sigcache;
|
||||
|
@ -34,18 +35,30 @@ public:
|
|||
uint256 nonce = GetRandHash();
|
||||
// We want the nonce to be 64 bytes long to force the hasher to process
|
||||
// this chunk, which makes later hash computations more efficient. We
|
||||
// just write our 32-byte entropy twice to fill the 64 bytes.
|
||||
m_salted_hasher.Write(nonce.begin(), 32);
|
||||
m_salted_hasher.Write(nonce.begin(), 32);
|
||||
// just write our 32-byte entropy, and then pad with 'E' for ECDSA and
|
||||
// 'S' for Schnorr (followed by 0 bytes).
|
||||
static constexpr unsigned char PADDING_ECDSA[32] = {'E'};
|
||||
static constexpr unsigned char PADDING_SCHNORR[32] = {'S'};
|
||||
m_salted_hasher_ecdsa.Write(nonce.begin(), 32);
|
||||
m_salted_hasher_ecdsa.Write(PADDING_ECDSA, 32);
|
||||
m_salted_hasher_schnorr.Write(nonce.begin(), 32);
|
||||
m_salted_hasher_schnorr.Write(PADDING_SCHNORR, 32);
|
||||
}
|
||||
|
||||
void
|
||||
ComputeEntryECDSA(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey)
|
||||
{
|
||||
CSHA256 hasher = m_salted_hasher;
|
||||
CSHA256 hasher = m_salted_hasher_ecdsa;
|
||||
hasher.Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin());
|
||||
}
|
||||
|
||||
void
|
||||
ComputeEntrySchnorr(uint256& entry, const uint256 &hash, Span<const unsigned char> sig, const XOnlyPubKey& pubkey)
|
||||
{
|
||||
CSHA256 hasher = m_salted_hasher_schnorr;
|
||||
hasher.Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(sig.data(), sig.size()).Finalize(entry.begin());
|
||||
}
|
||||
|
||||
bool
|
||||
Get(const uint256& entry, const bool erase)
|
||||
{
|
||||
|
@ -97,3 +110,13 @@ bool CachingTransactionSignatureChecker::VerifyECDSASignature(const std::vector<
|
|||
signatureCache.Set(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CachingTransactionSignatureChecker::VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const
|
||||
{
|
||||
uint256 entry;
|
||||
signatureCache.ComputeEntrySchnorr(entry, sighash, sig, pubkey);
|
||||
if (signatureCache.Get(entry, !store)) return true;
|
||||
if (!TransactionSignatureChecker::VerifySchnorrSignature(sig, pubkey, sighash)) return false;
|
||||
if (store) signatureCache.Set(entry);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define BITCOIN_SCRIPT_SIGCACHE_H
|
||||
|
||||
#include <script/interpreter.h>
|
||||
#include <span.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
@ -49,6 +50,7 @@ public:
|
|||
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amountIn, txdataIn), store(storeIn) {}
|
||||
|
||||
bool VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const override;
|
||||
bool VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const override;
|
||||
};
|
||||
|
||||
void InitSignatureCache();
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <pubkey.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <script/keyorigin.h>
|
||||
#include <span.h>
|
||||
#include <streams.h>
|
||||
|
||||
class CKey;
|
||||
|
|
|
@ -35,11 +35,19 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
|||
const bool store = fuzzed_data_provider.ConsumeBool();
|
||||
PrecomputedTransactionData tx_data;
|
||||
CachingTransactionSignatureChecker caching_transaction_signature_checker{mutable_transaction ? &tx : nullptr, n_in, amount, store, tx_data};
|
||||
const std::optional<CPubKey> pub_key = ConsumeDeserializable<CPubKey>(fuzzed_data_provider);
|
||||
if (fuzzed_data_provider.ConsumeBool()) {
|
||||
const auto random_bytes = fuzzed_data_provider.ConsumeBytes<unsigned char>(64);
|
||||
const XOnlyPubKey pub_key(ConsumeUInt256(fuzzed_data_provider));
|
||||
if (random_bytes.size() == 64) {
|
||||
(void)caching_transaction_signature_checker.VerifySchnorrSignature(random_bytes, pub_key, ConsumeUInt256(fuzzed_data_provider));
|
||||
}
|
||||
} else {
|
||||
const auto random_bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
|
||||
const auto pub_key = ConsumeDeserializable<CPubKey>(fuzzed_data_provider);
|
||||
if (pub_key) {
|
||||
const std::vector<uint8_t> random_bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
|
||||
if (!random_bytes.empty()) {
|
||||
(void)caching_transaction_signature_checker.VerifyECDSASignature(random_bytes, *pub_key, ConsumeUInt256(fuzzed_data_provider));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,11 @@ public:
|
|||
return m_fuzzed_data_provider.ConsumeBool();
|
||||
}
|
||||
|
||||
bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptError* serror = nullptr) const override
|
||||
{
|
||||
return m_fuzzed_data_provider.ConsumeBool();
|
||||
}
|
||||
|
||||
bool CheckLockTime(const CScriptNum& nLockTime) const override
|
||||
{
|
||||
return m_fuzzed_data_provider.ConsumeBool();
|
||||
|
|
|
@ -264,4 +264,32 @@ BOOST_AUTO_TEST_CASE(pubkey_unserialize)
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
Loading…
Add table
Reference in a new issue