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>
|
</ItemGroup>
|
||||||
<ItemDefinitionGroup>
|
<ItemDefinitionGroup>
|
||||||
<ClCompile>
|
<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>
|
<AdditionalIncludeDirectories>..\..\src\secp256k1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
|
|
@ -1645,7 +1645,7 @@ if test x$need_bundled_univalue = xyes; then
|
||||||
AC_CONFIG_SUBDIRS([src/univalue])
|
AC_CONFIG_SUBDIRS([src/univalue])
|
||||||
fi
|
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_CONFIG_SUBDIRS([src/secp256k1])
|
||||||
|
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <secp256k1.h>
|
#include <secp256k1.h>
|
||||||
#include <secp256k1_recovery.h>
|
#include <secp256k1_recovery.h>
|
||||||
|
#include <secp256k1_schnorrsig.h>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -166,6 +167,20 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
|
||||||
return 1;
|
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 {
|
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
|
||||||
if (!IsValid())
|
if (!IsValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
20
src/pubkey.h
20
src/pubkey.h
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <hash.h>
|
#include <hash.h>
|
||||||
#include <serialize.h>
|
#include <serialize.h>
|
||||||
|
#include <span.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
@ -206,6 +207,25 @@ public:
|
||||||
bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;
|
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 {
|
struct CExtPubKey {
|
||||||
unsigned char nDepth;
|
unsigned char nDepth;
|
||||||
unsigned char vchFingerprint[4];
|
unsigned char vchFingerprint[4];
|
||||||
|
|
|
@ -1521,6 +1521,12 @@ bool GenericTransactionSignatureChecker<T>::VerifyECDSASignature(const std::vect
|
||||||
return pubkey.Verify(sighash, vchSig);
|
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>
|
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
|
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;
|
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>
|
template <class T>
|
||||||
bool GenericTransactionSignatureChecker<T>::CheckLockTime(const CScriptNum& nLockTime) const
|
bool GenericTransactionSignatureChecker<T>::CheckLockTime(const CScriptNum& nLockTime) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,12 +7,14 @@
|
||||||
#define BITCOIN_SCRIPT_INTERPRETER_H
|
#define BITCOIN_SCRIPT_INTERPRETER_H
|
||||||
|
|
||||||
#include <script/script_error.h>
|
#include <script/script_error.h>
|
||||||
|
#include <span.h>
|
||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
class CPubKey;
|
class CPubKey;
|
||||||
|
class XOnlyPubKey;
|
||||||
class CScript;
|
class CScript;
|
||||||
class CTransaction;
|
class CTransaction;
|
||||||
class CTxOut;
|
class CTxOut;
|
||||||
|
@ -176,6 +178,11 @@ public:
|
||||||
return false;
|
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
|
virtual bool CheckLockTime(const CScriptNum& nLockTime) const
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -200,11 +207,13 @@ private:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
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:
|
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) : 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) {}
|
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 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 CheckLockTime(const CScriptNum& nLockTime) const override;
|
||||||
bool CheckSequence(const CScriptNum& nSequence) 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";
|
return "Witness provided for non-witness script";
|
||||||
case SCRIPT_ERR_WITNESS_PUBKEYTYPE:
|
case SCRIPT_ERR_WITNESS_PUBKEYTYPE:
|
||||||
return "Using non-compressed keys in segwit";
|
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:
|
case SCRIPT_ERR_OP_CODESEPARATOR:
|
||||||
return "Using OP_CODESEPARATOR in non-witness script";
|
return "Using OP_CODESEPARATOR in non-witness script";
|
||||||
case SCRIPT_ERR_SIG_FINDANDDELETE:
|
case SCRIPT_ERR_SIG_FINDANDDELETE:
|
||||||
|
|
|
@ -66,6 +66,11 @@ typedef enum ScriptError_t
|
||||||
SCRIPT_ERR_WITNESS_UNEXPECTED,
|
SCRIPT_ERR_WITNESS_UNEXPECTED,
|
||||||
SCRIPT_ERR_WITNESS_PUBKEYTYPE,
|
SCRIPT_ERR_WITNESS_PUBKEYTYPE,
|
||||||
|
|
||||||
|
/* Taproot */
|
||||||
|
SCRIPT_ERR_SCHNORR_SIG_SIZE,
|
||||||
|
SCRIPT_ERR_SCHNORR_SIG_HASHTYPE,
|
||||||
|
SCRIPT_ERR_SCHNORR_SIG,
|
||||||
|
|
||||||
/* Constant scriptCode */
|
/* Constant scriptCode */
|
||||||
SCRIPT_ERR_OP_CODESEPARATOR,
|
SCRIPT_ERR_OP_CODESEPARATOR,
|
||||||
SCRIPT_ERR_SIG_FINDANDDELETE,
|
SCRIPT_ERR_SIG_FINDANDDELETE,
|
||||||
|
|
|
@ -22,8 +22,9 @@ namespace {
|
||||||
class CSignatureCache
|
class CSignatureCache
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
//! Entries are SHA256(nonce || signature hash || public key || signature):
|
//! Entries are SHA256(nonce || 'E' or 'S' || 31 zero bytes || signature hash || public key || signature):
|
||||||
CSHA256 m_salted_hasher;
|
CSHA256 m_salted_hasher_ecdsa;
|
||||||
|
CSHA256 m_salted_hasher_schnorr;
|
||||||
typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type;
|
typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type;
|
||||||
map_type setValid;
|
map_type setValid;
|
||||||
boost::shared_mutex cs_sigcache;
|
boost::shared_mutex cs_sigcache;
|
||||||
|
@ -34,18 +35,30 @@ public:
|
||||||
uint256 nonce = GetRandHash();
|
uint256 nonce = GetRandHash();
|
||||||
// We want the nonce to be 64 bytes long to force the hasher to process
|
// 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
|
// this chunk, which makes later hash computations more efficient. We
|
||||||
// just write our 32-byte entropy twice to fill the 64 bytes.
|
// just write our 32-byte entropy, and then pad with 'E' for ECDSA and
|
||||||
m_salted_hasher.Write(nonce.begin(), 32);
|
// 'S' for Schnorr (followed by 0 bytes).
|
||||||
m_salted_hasher.Write(nonce.begin(), 32);
|
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
|
void
|
||||||
ComputeEntryECDSA(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey)
|
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());
|
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
|
bool
|
||||||
Get(const uint256& entry, const bool erase)
|
Get(const uint256& entry, const bool erase)
|
||||||
{
|
{
|
||||||
|
@ -97,3 +110,13 @@ bool CachingTransactionSignatureChecker::VerifyECDSASignature(const std::vector<
|
||||||
signatureCache.Set(entry);
|
signatureCache.Set(entry);
|
||||||
return true;
|
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
|
#define BITCOIN_SCRIPT_SIGCACHE_H
|
||||||
|
|
||||||
#include <script/interpreter.h>
|
#include <script/interpreter.h>
|
||||||
|
#include <span.h>
|
||||||
|
|
||||||
#include <vector>
|
#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) {}
|
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 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();
|
void InitSignatureCache();
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <pubkey.h>
|
#include <pubkey.h>
|
||||||
#include <script/interpreter.h>
|
#include <script/interpreter.h>
|
||||||
#include <script/keyorigin.h>
|
#include <script/keyorigin.h>
|
||||||
|
#include <span.h>
|
||||||
#include <streams.h>
|
#include <streams.h>
|
||||||
|
|
||||||
class CKey;
|
class CKey;
|
||||||
|
|
|
@ -35,11 +35,19 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
||||||
const bool store = fuzzed_data_provider.ConsumeBool();
|
const bool store = fuzzed_data_provider.ConsumeBool();
|
||||||
PrecomputedTransactionData tx_data;
|
PrecomputedTransactionData tx_data;
|
||||||
CachingTransactionSignatureChecker caching_transaction_signature_checker{mutable_transaction ? &tx : nullptr, n_in, amount, store, 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()) {
|
||||||
if (pub_key) {
|
const auto random_bytes = fuzzed_data_provider.ConsumeBytes<unsigned char>(64);
|
||||||
const std::vector<uint8_t> random_bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
|
const XOnlyPubKey pub_key(ConsumeUInt256(fuzzed_data_provider));
|
||||||
if (!random_bytes.empty()) {
|
if (random_bytes.size() == 64) {
|
||||||
(void)caching_transaction_signature_checker.VerifyECDSASignature(random_bytes, *pub_key, ConsumeUInt256(fuzzed_data_provider));
|
(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) {
|
||||||
|
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();
|
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
|
bool CheckLockTime(const CScriptNum& nLockTime) const override
|
||||||
{
|
{
|
||||||
return m_fuzzed_data_provider.ConsumeBool();
|
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()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
Loading…
Add table
Reference in a new issue