Skip to content

Fix range proof verification cache keying (asset + scriptPubKey) - #1591

Open
delta1 wants to merge 3 commits into
ElementsProject:masterfrom
delta1:rangeproof-cache-master
Open

Fix range proof verification cache keying (asset + scriptPubKey)#1591
delta1 wants to merge 3 commits into
ElementsProject:masterfrom
delta1:rangeproof-cache-master

Conversation

@delta1

@delta1 delta1 commented Aug 31, 2026

Copy link
Copy Markdown
Member

Summary

Fix the range-proof verification cache in CachingRangeProofChecker so a false cache hit can no longer validate a rangeproof under a different asset generator or scriptPubKey, and can no longer bypass the min_value == 0 anti-zero-token guard for spendable outputs.

Background / issue

liquid/elements #211: the rangeproof verification cache (SignatureCache::ComputeEntryRangeProof) was keyed only on (proof, value_commitment). But secp256k1_rangeproof_verify also binds the asset generator and the scriptPubKey (the proof's extra commitment). A cache keyed on the proof + value commitment alone would:

  • accept a previously-seen (proof, commitment) pair under any script via a cache hit (validating a tx under a script it was never committed to), and
  • skip the min_value == 0 guard for spendable outputs on a cache hit, letting a zero-minimum-value (spendable) output pass where it should be rejected.

Fix

ComputeEntryRangeProof now hashes proof + value_commitment + asset_commitment + scriptPubKey. Non-cached paths are unchanged; the fix only widens the cache key to everything the proof actually binds.

Tests

  • test: unit test for range proof cache fix — new rangeproof_cache_binding_test in src/test/blind_tests.cpp. Fails on all 3 assertions (different script, different asset generator, min_value == 0 guard) when the cache-key change is reverted; passes with the fix. blind_tests, script_tests, validation_tests, coins_tests all pass with the fix.
  • test: functional test for range proof cache fix — new feature_rangeproof_cache.py. Rejects the poisoned (cache-hit) transaction on a warm cache and, after restart, on a cold cache; passes with the fix and fails on unfixed code.
  • Regression sanity: feature_confidential_transactions, feature_issuance, feature_sighash_rangeproof all pass.

@delta1

delta1 commented Aug 31, 2026

Copy link
Copy Markdown
Member Author

CI note: all checks pass (lint, ASan+LSan+UBSan+integer, macOS arm64 x2, Win64 x2) except the test each commit job, which fails on interface_zmq.py with TypeError: '<' not supported between instances of 'CTxOutValue' and 'int' in test_framework/messages.py is_valid().

This failure is a pre-existing flaky master test, unrelated to this PR (which touches only src/script/sigcache.cpp/.h and two new test files). It reproduces identically on unrelated PRs today against the same master (e.g. fix_multi_commit run 33401378879) and passes intermittently on others (e.g. run 33410277643). The ZMQ test compares confidential output values (CTxOutValue) to int in the test framework and is not affected by the range-proof cache change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant