FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Merge ElementsProject/elements#1600: sigcache: harden range proof cac… · ElementsProject/elements@ca17280 · GitHub

Repository navigation

Commit ca17280

Browse files
committed
Merge #1600: sigcache: harden range proof cache keys and add -norangeproofcache option
1bfa1ee doc: update manpages for 23.3.4 (Byron Hambly) 8f0acb8 bump version to 23.3.4 (Byron Hambly) 19d7042 init: add -norangeproofcache startup option to disable range proof cache (Byron Hambly) 1513d63 sigcache: add proof cache key collision-resistance tests (Byron Hambly) 9400096 sigcache: harden proof cache keys with length-prefixed hashing (Byron Hambly) Pull request description: Target branch is elements-23.3.x Switch the range-proof and surjection-proof cache hashers from raw CSHA256 concatenation to CHashWriter . This length-prefixes every field, so distinct argument tuples with byte-identical raw concatenations no longer collide to the same cache key. Both caches retain per-process salted midstates with distinct domain separators ('r' / 's'). Also adds a -norangeproofcache startup option to disable the range proof cache without recompiling. Unit tests cover field-boundary collisions, script sensitivity, domain separation, determinism, and vTags sensitivity. Bump version to 23.3.4 and updates manpages. ACKs for top commit: psgreco: ACK 1bfa1ee Tree-SHA512: ad4088fc76370eb76952147ad0b85704e1ec804fa7c7c2a507b64372050b0105728fdcc18e23468e8f902d2d5493f4e34fa7b717d50f0cf92d0bdc128bb1736f
2 parents 3b3f01e + 1bfa1ee commit ca17280

12 files changed

Lines changed: 268 additions & 49 deletions

‎configure.ac‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ AC_PREREQ([2.69])
22
define(_CLIENT_VERSION_MAJOR, 23)
33
define(_CLIENT_VERSION_MINOR, 3)
44
define(_CLIENT_VERSION_BUILD, 4)
5-
define(_CLIENT_VERSION_RC, 1)
5+
define(_CLIENT_VERSION_RC, 0)
66
define(_CLIENT_VERSION_IS_RELEASE, true)
77
define(_COPYRIGHT_YEAR, 2026)
88
define(_COPYRIGHT_HOLDERS,[The %s developers])

‎doc/man/elements-cli.1‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
2-
.TH ELEMENTS-CLI "1" "June 2026" "elements-cli v23.3.4" "User Commands"
2+
.TH ELEMENTS-CLI "1" "September 2026" "elements-cli v23.3.4" "User Commands"
33
.SH NAME
44
elements-cli \- manual page for elements-cli v23.3.4
55
.SH SYNOPSIS

‎doc/man/elements-qt.1‎

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
2-
.TH ELEMENTS-QT "1" "June 2026" "elements-qt v23.3.4" "User Commands"
2+
.TH ELEMENTS-QT "1" "September 2026" "elements-qt v23.3.4" "User Commands"
33
.SH NAME
44
elements-qt \- manual page for elements-qt v23.3.4
55
.SH SYNOPSIS
@@ -115,7 +115,7 @@ Do not keep transactions in the mempool longer than <n> hours (default:
115115
.HP
116116
\fB\-par=\fR<n>
117117
.IP
118-
Set the number of script verification threads (\fB\-16\fR to 15, 0 = auto, <0 =
118+
Set the number of script verification threads (\fB\-24\fR to 15, 0 = auto, <0 =
119119
leave that many cores free, default: 0)
120120
.HP
121121
\fB\-persistmempool\fR
@@ -318,10 +318,6 @@ created within past week. 0 = no limit (default: 0M). Optional
318318
suffix units [k|K|m|M|g|G|t|T] (default: M). Lowercase is 1000
319319
base while uppercase is 1024 base
320320
.HP
321-
\fB\-natpmp\fR
322-
.IP
323-
Use NAT\-PMP to map the listening port (default: 0)
324-
.HP
325321
\fB\-networkactive\fR
326322
.IP
327323
Enable all P2P network activity (default: 1). Can be changed by the
@@ -390,10 +386,6 @@ Tor control port to use if onion listening enabled (default:
390386
.IP
391387
Tor control port password (default: empty)
392388
.HP
393-
\fB\-upnp\fR
394-
.IP
395-
Use UPnP to map the listening port (default: 0)
396-
.HP
397389
\fB\-whitebind=\fR<[permissions@]addr>
398390
.IP
399391
Bind to the given address and add permission flags to the peers

‎doc/man/elements-tx.1‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
2-
.TH ELEMENTS-TX "1" "June 2026" "elements-tx v23.3.4" "User Commands"
2+
.TH ELEMENTS-TX "1" "September 2026" "elements-tx v23.3.4" "User Commands"
33
.SH NAME
44
elements-tx \- manual page for elements-tx v23.3.4
55
.SH SYNOPSIS

‎doc/man/elements-util.1‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
2-
.TH ELEMENTS-UTIL "1" "June 2026" "elements-util v23.3.4" "User Commands"
2+
.TH ELEMENTS-UTIL "1" "September 2026" "elements-util v23.3.4" "User Commands"
33
.SH NAME
44
elements-util \- manual page for elements-util v23.3.4
55
.SH SYNOPSIS

‎doc/man/elements-wallet.1‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
2-
.TH ELEMENTS-WALLET "1" "June 2026" "elements-wallet v23.3.4" "User Commands"
2+
.TH ELEMENTS-WALLET "1" "September 2026" "elements-wallet v23.3.4" "User Commands"
33
.SH NAME
44
elements-wallet \- manual page for elements-wallet v23.3.4
55
.SH DESCRIPTION

‎doc/man/elementsd.1‎

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
2-
.TH ELEMENTSD "1" "June 2026" "elementsd v23.3.4" "User Commands"
2+
.TH ELEMENTSD "1" "September 2026" "elementsd v23.3.4" "User Commands"
33
.SH NAME
44
elementsd \- manual page for elementsd v23.3.4
55
.SH SYNOPSIS
@@ -115,7 +115,7 @@ Do not keep transactions in the mempool longer than <n> hours (default:
115115
.HP
116116
\fB\-par=\fR<n>
117117
.IP
118-
Set the number of script verification threads (\fB\-16\fR to 15, 0 = auto, <0 =
118+
Set the number of script verification threads (\fB\-24\fR to 15, 0 = auto, <0 =
119119
leave that many cores free, default: 0)
120120
.HP
121121
\fB\-persistmempool\fR
@@ -318,10 +318,6 @@ created within past week. 0 = no limit (default: 0M). Optional
318318
suffix units [k|K|m|M|g|G|t|T] (default: M). Lowercase is 1000
319319
base while uppercase is 1024 base
320320
.HP
321-
\fB\-natpmp\fR
322-
.IP
323-
Use NAT\-PMP to map the listening port (default: 0)
324-
.HP
325321
\fB\-networkactive\fR
326322
.IP
327323
Enable all P2P network activity (default: 1). Can be changed by the
@@ -390,10 +386,6 @@ Tor control port to use if onion listening enabled (default:
390386
.IP
391387
Tor control port password (default: empty)
392388
.HP
393-
\fB\-upnp\fR
394-
.IP
395-
Use UPnP to map the listening port (default: 0)
396-
.HP
397389
\fB\-whitebind=\fR<[permissions@]addr>
398390
.IP
399391
Bind to the given address and add permission flags to the peers

‎src/Makefile.test.include‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ BITCOIN_TESTS =\
132132
test/serialize_tests.cpp \
133133
test/settings_tests.cpp \
134134
test/sighash_tests.cpp \
135+
test/sigcache_tests.cpp \
135136
test/sigopcount_tests.cpp \
136137
test/skiplist_tests.cpp \
137138
test/sock_tests.cpp \

‎src/init.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@ void SetupServerArgs(ArgsManager& argsman)
556556
argsman.AddArg("-capturemessages", "Capture all P2P messages to disk", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
557557
argsman.AddArg("-mocktime=<n>", "Replace actual time with " + UNIX_EPOCH_TIME + " (default: 0)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
558558
argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
559+
argsman.AddArg("-rangeproofcache", strprintf("Enable the range proof validation cache (default: %u). Use -norangeproofcache to disable.", 1), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
559560
argsman.AddArg("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
560561
argsman.AddArg("-printpriority", strprintf("Log transaction fee rate in " + CURRENCY_UNIT + "/kvB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
561562
argsman.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);

‎src/script/sigcache.cpp‎

Lines changed: 79 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <random.h>
1010
#include <uint256.h>
1111
#include <util/system.h>
12+
#include <hash.h>
1213

1314
#include <cuckoocache.h>
1415

@@ -26,23 +27,23 @@ namespace {
2627
class CSignatureCache
2728
{
2829
private:
29-
//! Entries are SHA256(nonce || 'E' or 'S' || 31 zero bytes || signature hash || public key || signature):
30+
//! Salted SHA256 midstates, domain-separated by signature or proof type.
3031
CSHA256 m_salted_hasher_ecdsa;
3132
CSHA256 m_salted_hasher_schnorr;
32-
CSHA256 m_salted_hasher_range_proof;
33-
CSHA256 m_salted_hasher_surjection_proof;
33+
CHashWriter m_salted_hasher_range_proof;
34+
CHashWriter m_salted_hasher_surjection_proof;
3435
typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type;
3536
map_type setValid;
3637
std::shared_mutex cs_sigcache;
3738

3839
public:
39-
CSignatureCache()
40+
CSignatureCache():
41+
m_salted_hasher_range_proof(SER_GETHASH,0),
42+
m_salted_hasher_surjection_proof(SER_GETHASH,0)
4043
{
4144
uint256 nonce = GetRandHash();
42-
// We want the nonce to be 64 bytes long to force the hasher to process
43-
// this chunk, which makes later hash computations more efficient. We
44-
// just write our 32-byte entropy, and then pad with 'E' for ECDSA and
45-
// 'S' for Schnorr (followed by 0 bytes).
45+
// Use 64-byte, type-specific salted midstates so later hash computations
46+
// can start after the first SHA256 chunk.
4647
static constexpr unsigned char PADDING_ECDSA[32] = {'E'};
4748
static constexpr unsigned char PADDING_SCHNORR[32] = {'S'};
4849
static constexpr unsigned char PADDING_RANGE_PROOF[32] = {'r'};
@@ -51,10 +52,8 @@ class CSignatureCache
5152
m_salted_hasher_ecdsa.Write(PADDING_ECDSA, 32);
5253
m_salted_hasher_schnorr.Write(nonce.begin(), 32);
5354
m_salted_hasher_schnorr.Write(PADDING_SCHNORR, 32);
54-
m_salted_hasher_range_proof.Write(nonce.begin(), 32);
55-
m_salted_hasher_range_proof.Write(PADDING_RANGE_PROOF, 32);
56-
m_salted_hasher_surjection_proof.Write(nonce.begin(), 32);
57-
m_salted_hasher_surjection_proof.Write(PADDING_SURJECTION_PROOF, 32);
55+
m_salted_hasher_range_proof << nonce << PADDING_RANGE_PROOF;
56+
m_salted_hasher_surjection_proof << nonce << PADDING_SURJECTION_PROOF;
5857
}
5958

6059
void
@@ -72,13 +71,39 @@ class CSignatureCache
7271
}
7372

7473
// ELEMENTS:
75-
void ComputeEntryRangeProof(uint256& entry, const std::vector<unsigned char>& proof, const std::vector<unsigned char>& commitment, const std::vector<unsigned char>& asset_commitment, const CScript& scriptPubKey) {
76-
CSHA256 hasher = m_salted_hasher_range_proof;
77-
hasher.Write(proof.data(), proof.size()).Write(commitment.data(), commitment.size()).Write(asset_commitment.data(), asset_commitment.size()).Write(scriptPubKey.data(), scriptPubKey.size()).Finalize(entry.begin());
74+
void ComputeEntryRangeProof(uint256& entry,
75+
const std::vector<unsigned char>& proof,
76+
const std::vector<unsigned char>& commitment,
77+
const std::vector<unsigned char>& asset_commitment,
78+
const CScript& script_pub_key) const
79+
{
80+
CHashWriter hasher = m_salted_hasher_range_proof;
81+
// We commit to both commitments and the scriptPubKey because these are
82+
// committed to by the rangeproof itself; a change in any of them would
83+
// invalidate the proof. Since these are exactly the arguments to
84+
// CachingRangeProofChecker::VerifyRangeProof (below), there is no
85+
// additional data that could affect the rangeproof's validity.
86+
// Serialization length-prefixes every field, including the variable-length
87+
// proof and script, so distinct argument tuples cannot share an encoding.
88+
hasher << proof << commitment << asset_commitment << script_pub_key;
89+
entry = hasher.GetSHA256();
7890
}
79-
void ComputeEntrySurjectionProof(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& proof, const std::vector<unsigned char>& commitment) {
80-
CSHA256 hasher = m_salted_hasher_surjection_proof;
81-
hasher.Write(hash.begin(), 32).Write(proof.data(), proof.size()).Write(commitment.data(), commitment.size()).Finalize(entry.begin());
91+
void ComputeEntrySurjectionProof(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& proof, const std::vector<unsigned char>& commitment, const std::vector<secp256k1_generator>& vTags) const {
92+
CHashWriter hasher = m_salted_hasher_surjection_proof;
93+
// We hash all arguments passed to CachingSurjectionProofChecker::VerifySurjectionProof,
94+
// to ensure that any change in the way that the verification function is called will
95+
// trigger a cache miss and explicit verification. However, we note that the `wtxid`
96+
// (hash) commits to all the other data such that we could technically hash only it.
97+
// We retain the other data as a defense against future refactorings.
98+
//
99+
// Serialize vTags as a flat byte vector (each secp256k1_generator is 64 bytes).
100+
std::vector<unsigned char> vTagsBytes;
101+
vTagsBytes.reserve(vTags.size() * 64);
102+
for (const auto& tag : vTags) {
103+
vTagsBytes.insert(vTagsBytes.end(), std::begin(tag.data), std::end(tag.data));
104+
}
105+
hasher << hash << proof << commitment << vTagsBytes;
106+
entry = hasher.GetSHA256();
82107
}
83108

84109
bool
@@ -154,6 +179,10 @@ bool CachingTransactionSignatureChecker::VerifySchnorrSignature(Span<const unsig
154179
// To be called once in AppInit2/TestingSetup to initialize the rangeproof cache
155180
void InitRangeproofCache()
156181
{
182+
if (!gArgs.GetBoolArg("-rangeproofcache", true)) {
183+
LogPrintf("Range proof cache disabled via -norangeproofcache\n");
184+
return;
185+
}
157186
// nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
158187
// setup_bytes creates the minimum possible cache (2 elements).
159188
size_t nMaxCacheSize = std::min(std::max((int64_t)0, gArgs.GetIntArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) / 4), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
@@ -175,11 +204,18 @@ void InitSurjectionproofCache()
175204

176205
bool CachingRangeProofChecker::VerifyRangeProof(const std::vector<unsigned char>& vchRangeProof, const std::vector<unsigned char>& vchValueCommitment, const std::vector<unsigned char>& vchAssetCommitment, const CScript& scriptPubKey, const secp256k1_context* secp256k1_ctx_verify_amounts) const
177206
{
207+
// ELEMENTS: NOTE FOR FUTURE EDITORS: every argument to this function that
208+
// carries data (i.e. everything except the secp256k1 context, which is
209+
// stateless) MUST be included in ComputeEntryRangeProof. Omitting any
210+
// argument risks returning a cached positive result for a proof that was
211+
// verified with different inputs.
178212
uint256 entry;
179-
rangeProofCache.ComputeEntryRangeProof(entry, vchRangeProof, vchValueCommitment, vchAssetCommitment, scriptPubKey);
180-
181-
if (rangeProofCache.Get(entry, !store)) {
182-
return true;
213+
const bool useCache = gArgs.GetBoolArg("-rangeproofcache", true);
214+
if (useCache) {
215+
rangeProofCache.ComputeEntryRangeProof(entry, vchRangeProof, vchValueCommitment, vchAssetCommitment, scriptPubKey);
216+
if (rangeProofCache.Get(entry, !store)) {
217+
return true;
218+
}
183219
}
184220

185221
if (vchRangeProof.size() == 0) {
@@ -208,7 +244,7 @@ bool CachingRangeProofChecker::VerifyRangeProof(const std::vector<unsigned char>
208244
return false;
209245
}
210246

211-
if (store) {
247+
if (useCache && store) {
212248
rangeProofCache.Set(entry);
213249
}
214250

@@ -227,7 +263,7 @@ bool CachingSurjectionProofChecker::VerifySurjectionProof(secp256k1_surjectionpr
227263
// wtxid commits to all data including surj targets
228264
// we need to specify the proof and output asset point to be unique
229265
uint256 entry;
230-
surjectionProofCache.ComputeEntrySurjectionProof(entry, wtxid, vchproof, std::vector<unsigned char>(std::begin(gen.data), std::end(gen.data)));
266+
surjectionProofCache.ComputeEntrySurjectionProof(entry, wtxid, vchproof, std::vector<unsigned char>(std::begin(gen.data), std::end(gen.data)), vTags);
231267

232268
if (surjectionProofCache.Get(entry, !store)) {
233269
return true;
@@ -244,5 +280,24 @@ bool CachingSurjectionProofChecker::VerifySurjectionProof(secp256k1_surjectionpr
244280
return true;
245281
}
246282

283+
// Test-only hooks (see sigcache.h). Forward to the anonymous-namespace caches.
284+
void TestComputeEntryRangeProof(uint256& entry,
285+
const std::vector<unsigned char>& proof,
286+
const std::vector<unsigned char>& commitment,
287+
const std::vector<unsigned char>& asset_commitment,
288+
const CScript& script_pub_key)
289+
{
290+
rangeProofCache.ComputeEntryRangeProof(entry, proof, commitment, asset_commitment, script_pub_key);
291+
}
292+
293+
void TestComputeEntrySurjectionProof(uint256& entry,
294+
const uint256& hash,
295+
const std::vector<unsigned char>& proof,
296+
const std::vector<unsigned char>& commitment,
297+
const std::vector<secp256k1_generator>& vTags)
298+
{
299+
surjectionProofCache.ComputeEntrySurjectionProof(entry, hash, proof, commitment, vTags);
300+
}
301+
247302
// END ELEMENTS
248303
//

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL