Skip to content

Commit

Permalink
Merge bitcoin#25331: Add HashWriter without ser-type and ser-version …
Browse files Browse the repository at this point in the history
…and use it where possible

faf9acc Use HashWriter where possible (MacroFake)
faa5425 Add HashWriter without ser-type and ser-version (MacroFake)

Pull request description:

  This was done in the context of bitcoin#25284 , but I think it also makes sense standalone.

  The basic idea is that serialization type should not be initialized when it is not needed. Same for the serialization version.

  So do this here for `HashWriter`. `CHashWriter` remains in places where it is not yet possible.

ACKs for top commit:
  sipa:
    utACK faf9acc
  Empact:
    utACK bitcoin@faf9acc

Tree-SHA512: 544cc712436e49f6e608120bcd3ddc5ea72dd236554ce30fb6cfff34a92d7e67b6e6527336ad0f5b6365e2b2884f4c6508aef775953ccd9312f17752729703f2
  • Loading branch information
fanquake committed Jul 22, 2022
2 parents 86133df + faf9acc commit 510ac41
Show file tree
Hide file tree
Showing 14 changed files with 65 additions and 53 deletions.
2 changes: 1 addition & 1 deletion src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ class SigNetParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay

// message start is defined as the first 4 bytes of the sha256d of the block script
CHashWriter h(SER_DISK, 0);
HashWriter h{};
h << consensus.signet_challenge;
uint256 hash = h.GetHash();
memcpy(pchMessageStart, hash.begin(), 4);
Expand Down
4 changes: 2 additions & 2 deletions src/crypto/muhash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ void Num3072::ToBytes(unsigned char (&out)[BYTE_SIZE]) {
Num3072 MuHash3072::ToNum3072(Span<const unsigned char> in) {
unsigned char tmp[Num3072::BYTE_SIZE];

uint256 hashed_in = (CHashWriter(SER_DISK, 0) << in).GetSHA256();
uint256 hashed_in{(HashWriter{} << in).GetSHA256()};
ChaCha20(hashed_in.data(), hashed_in.size()).Keystream(tmp, Num3072::BYTE_SIZE);
Num3072 out{tmp};

Expand All @@ -318,7 +318,7 @@ void MuHash3072::Finalize(uint256& out) noexcept
unsigned char data[Num3072::BYTE_SIZE];
m_numerator.ToBytes(data);

out = (CHashWriter(SER_DISK, 0) << data).GetSHA256();
out = (HashWriter{} << data).GetSHA256();
}

MuHash3072& MuHash3072::operator*=(const MuHash3072& mul) noexcept
Expand Down
4 changes: 2 additions & 2 deletions src/hash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ uint256 SHA256Uint256(const uint256& input)
return result;
}

CHashWriter TaggedHash(const std::string& tag)
HashWriter TaggedHash(const std::string& tag)
{
CHashWriter writer(SER_GETHASH, 0);
HashWriter writer{};
uint256 taghash;
CSHA256().Write((const unsigned char*)tag.data(), tag.size()).Finalize(taghash.begin());
writer << taghash << taghash;
Expand Down
36 changes: 24 additions & 12 deletions src/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,20 +96,12 @@ inline uint160 Hash160(const T1& in1)
}

/** A writer stream (for serialization) that computes a 256-bit hash. */
class CHashWriter
class HashWriter
{
private:
CSHA256 ctx;

const int nType;
const int nVersion;
public:

CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {}

int GetType() const { return nType; }
int GetVersion() const { return nVersion; }

void write(Span<const std::byte> src)
{
ctx.Write(UCharCast(src.data()), src.size());
Expand Down Expand Up @@ -144,6 +136,26 @@ class CHashWriter
return ReadLE64(result.begin());
}

template <typename T>
HashWriter& operator<<(const T& obj)
{
::Serialize(*this, obj);
return *this;
}
};

class CHashWriter : public HashWriter
{
private:
const int nType;
const int nVersion;

public:
CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {}

int GetType() const { return nType; }
int GetVersion() const { return nVersion; }

template<typename T>
CHashWriter& operator<<(const T& obj) {
// Serialize to this stream
Expand Down Expand Up @@ -203,12 +215,12 @@ unsigned int MurmurHash3(unsigned int nHashSeed, Span<const unsigned char> vData

void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);

/** Return a CHashWriter primed for tagged hashes (as specified in BIP 340).
/** Return a HashWriter primed for tagged hashes (as specified in BIP 340).
*
* The returned object will have SHA256(tag) written to it twice (= 64 bytes).
* A tagged hash can be computed by feeding the message into this object, and
* then calling CHashWriter::GetSHA256().
* then calling HashWriter::GetSHA256().
*/
CHashWriter TaggedHash(const std::string& tag);
HashWriter TaggedHash(const std::string& tag);

#endif // BITCOIN_HASH_H
8 changes: 4 additions & 4 deletions src/kernel/coinstats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ CDataStream TxOutSer(const COutPoint& outpoint, const Coin& coin) {
//! It is also possible, though very unlikely, that a change in this
//! construction could cause a previously invalid (and potentially malicious)
//! UTXO snapshot to be considered valid.
static void ApplyHash(CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
static void ApplyHash(HashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
{
for (auto it = outputs.begin(); it != outputs.end(); ++it) {
if (it == outputs.begin()) {
Expand Down Expand Up @@ -159,7 +159,7 @@ std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsV
bool success = [&]() -> bool {
switch (hash_type) {
case(CoinStatsHashType::HASH_SERIALIZED): {
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
HashWriter ss{};
return ComputeUTXOStats(view, stats, ss, interruption_point);
}
case(CoinStatsHashType::MUHASH): {
Expand All @@ -180,15 +180,15 @@ std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsV
}

// The legacy hash serializes the hashBlock
static void PrepareHash(CHashWriter& ss, const CCoinsStats& stats)
static void PrepareHash(HashWriter& ss, const CCoinsStats& stats)
{
ss << stats.hashBlock;
}
// MuHash does not need the prepare step
static void PrepareHash(MuHash3072& muhash, CCoinsStats& stats) {}
static void PrepareHash(std::nullptr_t, CCoinsStats& stats) {}

static void FinalizeHash(CHashWriter& ss, CCoinsStats& stats)
static void FinalizeHash(HashWriter& ss, CCoinsStats& stats)
{
stats.hashSerialized = ss.GetHash();
}
Expand Down
2 changes: 1 addition & 1 deletion src/node/blockstorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const
fileout << blockundo;

// calculate & write checksum
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
HashWriter hasher{};
hasher << hashBlock;
hasher << blockundo;
fileout << hasher.GetHash();
Expand Down
6 changes: 3 additions & 3 deletions src/pubkey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,16 +211,16 @@ bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> si
return secp256k1_schnorrsig_verify(secp256k1_context_verify, sigbytes.data(), msg.begin(), 32, &pubkey);
}

static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak");
static const HashWriter HASHER_TAPTWEAK{TaggedHash("TapTweak")};

uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root) const
{
if (merkle_root == nullptr) {
// We have no scripts. The actual tweak does not matter, but follow BIP341 here to
// allow for reproducible tweaking.
return (CHashWriter(HASHER_TAPTWEAK) << m_keydata).GetSHA256();
return (HashWriter{HASHER_TAPTWEAK} << m_keydata).GetSHA256();
} else {
return (CHashWriter(HASHER_TAPTWEAK) << m_keydata << *merkle_root).GetSHA256();
return (HashWriter{HASHER_TAPTWEAK} << m_keydata << *merkle_root).GetSHA256();
}
}

Expand Down
32 changes: 16 additions & 16 deletions src/script/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1342,7 +1342,7 @@ class CTransactionSignatureSerializer
template <class T>
uint256 GetPrevoutsSHA256(const T& txTo)
{
CHashWriter ss(SER_GETHASH, 0);
HashWriter ss{};
for (const auto& txin : txTo.vin) {
ss << txin.prevout;
}
Expand All @@ -1353,7 +1353,7 @@ uint256 GetPrevoutsSHA256(const T& txTo)
template <class T>
uint256 GetSequencesSHA256(const T& txTo)
{
CHashWriter ss(SER_GETHASH, 0);
HashWriter ss{};
for (const auto& txin : txTo.vin) {
ss << txin.nSequence;
}
Expand All @@ -1364,7 +1364,7 @@ uint256 GetSequencesSHA256(const T& txTo)
template <class T>
uint256 GetOutputsSHA256(const T& txTo)
{
CHashWriter ss(SER_GETHASH, 0);
HashWriter ss{};
for (const auto& txout : txTo.vout) {
ss << txout;
}
Expand All @@ -1374,7 +1374,7 @@ uint256 GetOutputsSHA256(const T& txTo)
/** Compute the (single) SHA256 of the concatenation of all amounts spent by a tx. */
uint256 GetSpentAmountsSHA256(const std::vector<CTxOut>& outputs_spent)
{
CHashWriter ss(SER_GETHASH, 0);
HashWriter ss{};
for (const auto& txout : outputs_spent) {
ss << txout.nValue;
}
Expand All @@ -1384,7 +1384,7 @@ uint256 GetSpentAmountsSHA256(const std::vector<CTxOut>& outputs_spent)
/** Compute the (single) SHA256 of the concatenation of all scriptPubKeys spent by a tx. */
uint256 GetSpentScriptsSHA256(const std::vector<CTxOut>& outputs_spent)
{
CHashWriter ss(SER_GETHASH, 0);
HashWriter ss{};
for (const auto& txout : outputs_spent) {
ss << txout.scriptPubKey;
}
Expand Down Expand Up @@ -1458,9 +1458,9 @@ template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo,
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);

const CHashWriter HASHER_TAPSIGHASH = TaggedHash("TapSighash");
const CHashWriter HASHER_TAPLEAF = TaggedHash("TapLeaf");
const CHashWriter HASHER_TAPBRANCH = TaggedHash("TapBranch");
const HashWriter HASHER_TAPSIGHASH{TaggedHash("TapSighash")};
const HashWriter HASHER_TAPLEAF{TaggedHash("TapLeaf")};
const HashWriter HASHER_TAPBRANCH{TaggedHash("TapBranch")};

static bool HandleMissingData(MissingDataBehavior mdb)
{
Expand Down Expand Up @@ -1499,7 +1499,7 @@ bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, cons
return HandleMissingData(mdb);
}

CHashWriter ss = HASHER_TAPSIGHASH;
HashWriter ss{HASHER_TAPSIGHASH};

// Epoch
static constexpr uint8_t EPOCH = 0;
Expand Down Expand Up @@ -1544,7 +1544,7 @@ bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, cons
if (output_type == SIGHASH_SINGLE) {
if (in_pos >= tx_to.vout.size()) return false;
if (!execdata.m_output_hash) {
CHashWriter sha_single_output(SER_GETHASH, 0);
HashWriter sha_single_output{};
sha_single_output << tx_to.vout[in_pos];
execdata.m_output_hash = sha_single_output.GetSHA256();
}
Expand Down Expand Up @@ -1587,12 +1587,12 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
hashOutputs = cacheready ? cache->hashOutputs : SHA256Uint256(GetOutputsSHA256(txTo));
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
CHashWriter ss(SER_GETHASH, 0);
HashWriter ss{};
ss << txTo.vout[nIn];
hashOutputs = ss.GetHash();
}

CHashWriter ss(SER_GETHASH, 0);
HashWriter ss{};
// Version
ss << txTo.nVersion;
// Input prevouts/nSequence (none/all, depending on flags)
Expand Down Expand Up @@ -1627,7 +1627,7 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
CTransactionSignatureSerializer<T> txTmp(txTo, scriptCode, nIn, nHashType);

// Serialize and hash
CHashWriter ss(SER_GETHASH, 0);
HashWriter ss{};
ss << txTmp << nHashType;
return ss.GetHash();
}
Expand Down Expand Up @@ -1827,7 +1827,7 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS

uint256 ComputeTapleafHash(uint8_t leaf_version, const CScript& script)
{
return (CHashWriter(HASHER_TAPLEAF) << leaf_version << script).GetSHA256();
return (HashWriter{HASHER_TAPLEAF} << leaf_version << script).GetSHA256();
}

uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint256& tapleaf_hash)
Expand All @@ -1839,7 +1839,7 @@ uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint25
const int path_len = (control.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
uint256 k = tapleaf_hash;
for (int i = 0; i < path_len; ++i) {
CHashWriter ss_branch{HASHER_TAPBRANCH};
HashWriter ss_branch{HASHER_TAPBRANCH};
Span node{Span{control}.subspan(TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE)};
if (std::lexicographical_compare(k.begin(), k.end(), node.begin(), node.end())) {
ss_branch << k << node;
Expand Down Expand Up @@ -1902,7 +1902,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
// Drop annex (this is non-standard; see IsWitnessStandard)
const valtype& annex = SpanPopBack(stack);
execdata.m_annex_hash = (CHashWriter(SER_GETHASH, 0) << annex).GetSHA256();
execdata.m_annex_hash = (HashWriter{} << annex).GetSHA256();
execdata.m_annex_present = true;
} else {
execdata.m_annex_present = false;
Expand Down
6 changes: 3 additions & 3 deletions src/script/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,9 @@ static constexpr size_t TAPROOT_CONTROL_NODE_SIZE = 32;
static constexpr size_t TAPROOT_CONTROL_MAX_NODE_COUNT = 128;
static constexpr size_t TAPROOT_CONTROL_MAX_SIZE = TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT;

extern const CHashWriter HASHER_TAPSIGHASH; //!< Hasher with tag "TapSighash" pre-fed to it.
extern const CHashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it.
extern const CHashWriter HASHER_TAPBRANCH; //!< Hasher with tag "TapBranch" pre-fed to it.
extern const HashWriter HASHER_TAPSIGHASH; //!< Hasher with tag "TapSighash" pre-fed to it.
extern const HashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it.
extern const HashWriter HASHER_TAPBRANCH; //!< Hasher with tag "TapBranch" pre-fed to it.

template <class T>
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
Expand Down
2 changes: 1 addition & 1 deletion src/script/sign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ static bool SignTaprootScript(const SigningProvider& provider, const BaseSignatu
if (leaf_version != TAPROOT_LEAF_TAPSCRIPT) return false;
SigVersion sigversion = SigVersion::TAPSCRIPT;

uint256 leaf_hash = (CHashWriter(HASHER_TAPLEAF) << uint8_t(leaf_version) << script).GetSHA256();
uint256 leaf_hash = (HashWriter{HASHER_TAPLEAF} << uint8_t(leaf_version) << script).GetSHA256();

// <xonly pubkey> OP_CHECKSIG
if (script.size() == 34 && script[33] == OP_CHECKSIG && script[0] == 0x20) {
Expand Down
8 changes: 4 additions & 4 deletions src/script/standard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,9 +375,9 @@ bool IsValidDestination(const CTxDestination& dest) {
}
/* Lexicographically sort a and b's hash, and compute parent hash. */
if (a.hash < b.hash) {
ret.hash = (CHashWriter(HASHER_TAPBRANCH) << a.hash << b.hash).GetSHA256();
ret.hash = (HashWriter{HASHER_TAPBRANCH} << a.hash << b.hash).GetSHA256();
} else {
ret.hash = (CHashWriter(HASHER_TAPBRANCH) << b.hash << a.hash).GetSHA256();
ret.hash = (HashWriter{HASHER_TAPBRANCH} << b.hash << a.hash).GetSHA256();
}
return ret;
}
Expand Down Expand Up @@ -452,7 +452,7 @@ TaprootBuilder& TaprootBuilder::Add(int depth, const CScript& script, int leaf_v
if (!IsValid()) return *this;
/* Construct NodeInfo object with leaf hash and (if track is true) also leaf information. */
NodeInfo node;
node.hash = (CHashWriter{HASHER_TAPLEAF} << uint8_t(leaf_version) << script).GetSHA256();
node.hash = (HashWriter{HASHER_TAPLEAF} << uint8_t(leaf_version) << script).GetSHA256();
if (track) node.leaves.emplace_back(LeafInfo{script, leaf_version, {}});
/* Insert into the branch. */
Insert(std::move(node), depth);
Expand Down Expand Up @@ -610,7 +610,7 @@ std::optional<std::vector<std::tuple<int, CScript, int>>> InferTaprootTree(const
node.done = true;
stack.pop_back();
} else if (node.sub[0]->done && !node.sub[1]->done && !node.sub[1]->explored && !node.sub[1]->hash.IsNull() &&
(CHashWriter{HASHER_TAPBRANCH} << node.sub[1]->hash << node.sub[1]->hash).GetSHA256() == node.hash) {
(HashWriter{HASHER_TAPBRANCH} << node.sub[1]->hash << node.sub[1]->hash).GetSHA256() == node.hash) {
// Whenever there are nodes with two identical subtrees under it, we run into a problem:
// the control blocks for the leaves underneath those will be identical as well, and thus
// they will all be matched to the same path in the tree. The result is that at the location
Expand Down
2 changes: 1 addition & 1 deletion src/test/script_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1813,7 +1813,7 @@ BOOST_AUTO_TEST_CASE(bip341_keypath_test_vectors)
BOOST_CHECK_EQUAL(HexStr(sighash), input["intermediary"]["sigHash"].get_str());

// To verify the sigmsg, hash the expected sigmsg, and compare it with the (expected) sighash.
BOOST_CHECK_EQUAL(HexStr((CHashWriter(HASHER_TAPSIGHASH) << Span{ParseHex(input["intermediary"]["sigMsg"].get_str())}).GetSHA256()), input["intermediary"]["sigHash"].get_str());
BOOST_CHECK_EQUAL(HexStr((HashWriter{HASHER_TAPSIGHASH} << Span{ParseHex(input["intermediary"]["sigMsg"].get_str())}).GetSHA256()), input["intermediary"]["sigHash"].get_str());
}

}
Expand Down
2 changes: 1 addition & 1 deletion src/util/message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ bool MessageSign(

uint256 MessageHash(const std::string& message)
{
CHashWriter hasher(SER_GETHASH, 0);
HashWriter hasher{};
hasher << MESSAGE_MAGIC << message;

return hasher.GetHash();
Expand Down
4 changes: 2 additions & 2 deletions src/wallet/dump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ bool DumpWallet(const ArgsManager& args, CWallet& wallet, bilingual_str& error)
return false;
}

CHashWriter hasher(0, 0);
HashWriter hasher{};

WalletDatabase& db = wallet.GetDatabase();
std::unique_ptr<DatabaseBatch> batch = db.MakeBatch();
Expand Down Expand Up @@ -132,7 +132,7 @@ bool CreateFromDump(const ArgsManager& args, const std::string& name, const fs::
std::ifstream dump_file{dump_path};

// Compute the checksum
CHashWriter hasher(0, 0);
HashWriter hasher{};
uint256 checksum;

// Check the magic and version
Expand Down

0 comments on commit 510ac41

Please sign in to comment.