diff --git a/src/Makefile.test.include b/src/Makefile.test.include index fcf5898a5d..e8b3efd81a 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -313,7 +313,8 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/txrequest.cpp \ test/fuzz/utxo_snapshot.cpp \ test/fuzz/validation_load_mempool.cpp \ - test/fuzz/versionbits.cpp + test/fuzz/versionbits.cpp \ + test/fuzz/witness_program.cpp endif # ENABLE_FUZZ_BINARY nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES) diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp index c91172fc08..0ff5bff334 100644 --- a/src/crypto/sha256.cpp +++ b/src/crypto/sha256.cpp @@ -705,6 +705,59 @@ void CSHA256::Midstate(unsigned char hash[OUTPUT_SIZE], uint64_t* len, unsigned } } +std::vector CSHA256::Save() const { + size_t buf_size = bytes % 64; + std::vector result(40 + buf_size); + + WriteBE32(&result[ 0], s[0]); + WriteBE32(&result[ 4], s[1]); + WriteBE32(&result[ 8], s[2]); + WriteBE32(&result[12], s[3]); + WriteBE32(&result[16], s[4]); + WriteBE32(&result[20], s[5]); + WriteBE32(&result[24], s[6]); + WriteBE32(&result[28], s[7]); + + WriteLE64(&result[32], bytes << 3); + + if (buf_size) memcpy(&result[40], buf, buf_size); + + return result; +} + +bool CSHA256::Load(const std::vector& vch) { + if (vch.size() < 40) return false; + + uint64_t bits = ReadLE64(&vch[32]); + size_t buf_size = (bits >> 3) % 64; + + if ((bits & 0x07) != 0 || vch.size() != 40 + buf_size) return false; + + // We want to leave the internal state of the object unchanged if false is returned. + // So no member variables can be modified until now. + + s[0] = ReadBE32(&vch[ 0]); + s[1] = ReadBE32(&vch[ 4]); + s[2] = ReadBE32(&vch[ 8]); + s[3] = ReadBE32(&vch[12]); + s[4] = ReadBE32(&vch[16]); + s[5] = ReadBE32(&vch[20]); + s[6] = ReadBE32(&vch[24]); + s[7] = ReadBE32(&vch[28]); + + bytes = bits >> 3; + if (buf_size) memcpy(buf, &vch[40], buf_size); + + return true; +} + +bool CSHA256::SafeWrite(const unsigned char* data, size_t len) { + const uint64_t SHA256_MAX = 0x1FFFFFFFFFFFFFFF; // SHA256's maximum allowed message length in bytes. + if (SHA256_MAX < bytes || SHA256_MAX - bytes < len) return false; + Write(data, len); + return true; +} + CSHA256& CSHA256::Reset() { bytes = 0; diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h index 7cdcde1956..79d5ad8b82 100644 --- a/src/crypto/sha256.h +++ b/src/crypto/sha256.h @@ -8,6 +8,7 @@ #include #include #include +#include /** A hasher class for SHA-256. */ class CSHA256 @@ -26,7 +27,10 @@ public: //TODO: Midstate is a hack'ish speedup that probably should make way for something //akin to the SHA256D64 speedups void Midstate(unsigned char hash[OUTPUT_SIZE], uint64_t* len, unsigned char *buffer); + std::vector Save() const; + bool Load(const std::vector& vch); CSHA256& Reset(); + bool SafeWrite(const unsigned char* data, size_t len); }; /** Autodetect the best available SHA256 implementation. diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 0857b80022..56dadafc22 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -186,12 +186,20 @@ bool XOnlyPubKey::IsFullyValid() const return secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &pubkey, m_keydata.data()); } -bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span sigbytes) const +bool XOnlyPubKey::VerifySchnorr(const Span msg, Span 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(), 32, &pubkey); + return secp256k1_schnorrsig_verify(secp256k1_context_verify, sigbytes.data(), msg.data(), msg.size(), &pubkey); +} + +// ELEMENTS: this is preserved from an old version of the Taproot code for use in OP_TWEAKVERIFY +bool XOnlyPubKey::CheckPayToContract(const XOnlyPubKey& base, const uint256& hash, bool parity) const +{ + secp256k1_xonly_pubkey base_point; + if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, base.data())) return false; + return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), parity, &base_point, hash.begin()); } static const CHashWriter HASHER_TAPTWEAK_ELEMENTS = TaggedHash("TapTweak/elements"); @@ -215,6 +223,18 @@ bool XOnlyPubKey::CheckTapTweak(const XOnlyPubKey& internal, const uint256& merk return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), parity, &internal_key, tweak.begin()); } +bool CPubKey::TweakMulVerify(const CPubKey& untweaked, const uint256& tweak) const +{ + assert(this->IsCompressed()); + secp256k1_pubkey pk; + if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pk, untweaked.data(), untweaked.size())) return false; + if (!secp256k1_ec_pubkey_tweak_mul(secp256k1_context_verify, &pk, tweak.data())) return false; + unsigned char out_pk[CPubKey::COMPRESSED_SIZE]; + size_t out_len = CPubKey::COMPRESSED_SIZE; + if (!secp256k1_ec_pubkey_serialize(secp256k1_context_verify, out_pk, &out_len, &pk, SECP256K1_EC_COMPRESSED)) return false; + return *this == CPubKey(out_pk, out_pk + out_len); +} + std::optional> XOnlyPubKey::CreateTapTweak(const uint256* merkle_root) const { secp256k1_xonly_pubkey base_point; @@ -226,7 +246,7 @@ std::optional> XOnlyPubKey::CreateTapTweak(const ui std::pair ret; secp256k1_xonly_pubkey out_xonly; if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_verify, &out_xonly, &parity, &out)) return std::nullopt; - secp256k1_xonly_pubkey_serialize(secp256k1_context_verify, ret.first.begin(), &out_xonly); + secp256k1_xonly_pubkey_serialize(secp256k1_context_verify, ret.first.data(), &out_xonly); assert(parity == 0 || parity == 1); ret.second = parity; return ret; diff --git a/src/pubkey.h b/src/pubkey.h index 5ac7c769da..abbe67c24a 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -216,6 +216,9 @@ public: //! Derive BIP32 child pubkey. bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc, std::vector* tweak = nullptr /* ELEMENTS: vector of key tweak values that are filled out if non-null */) const; + + //! Verify that when this public key is tweaked with tweak, the result is res + bool TweakMulVerify(const CPubKey& res, const uint256& tweak) const; }; class XOnlyPubKey @@ -249,7 +252,10 @@ public: * * sigbytes must be exactly 64 bytes. */ - bool VerifySchnorr(const uint256& msg, Span sigbytes) const; + bool VerifySchnorr(const Span msg, Span sigbytes) const; + + // ELEMENTS: this is preserved from an old version of the Taproot code for use in OP_TWEAKVERIFY + bool CheckPayToContract(const XOnlyPubKey& base, const uint256& hash, bool parity) const; /** Compute the Taproot tweak as specified in BIP341, with *this as internal * key: @@ -275,6 +281,7 @@ public: const unsigned char* end() const { return m_keydata.end(); } unsigned char* begin() { return m_keydata.begin(); } unsigned char* end() { return m_keydata.end(); } + unsigned char* data() { return m_keydata.begin(); } bool operator==(const XOnlyPubKey& other) const { return m_keydata == other.m_keydata; } bool operator!=(const XOnlyPubKey& other) const { return m_keydata != other.m_keydata; } bool operator<(const XOnlyPubKey& other) const { return m_keydata < other.m_keydata; } diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index cdad6b07cb..0244737d97 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -5,6 +5,7 @@ #include