From 0664f5fe1f77f08d235aa3750b59428257b0b91d Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 11 Sep 2020 14:33:30 -0700 Subject: 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. --- src/script/sigcache.cpp | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'src/script/sigcache.cpp') diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index b9ba006e4..4a6e04f2e 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -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 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& 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 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 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; +} -- cgit v1.2.3