Conversation
9737ecc to
e7f2062
Compare
There was a problem hiding this comment.
Pull request overview
This PR implements partial range proof verification for merkle tries, focusing on structural validation and boundary proof verification without full trie reconstruction.
Key Changes:
- Implements basic range proof verification checking key ordering, range boundaries, and cryptographic proofs
- Enables previously ignored tests for range proof validation
- Adjusts test logic to skip invalid test cases that would fail with current partial implementation
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
| firewood/src/merkle/mod.rs | Implements verify_range_proof with key ordering checks, boundary validation, and start/end proof verification |
| firewood/src/merkle/tests/range.rs | Removes #[ignore] attributes and adds continue statements to skip test cases that require full verification |
| firewood/src/lib.rs | Changes default logging level from "trace" to "info" |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let merkle = init_merkle(items.clone()); | ||
|
|
||
| for _ in 0..10 { | ||
| 'skip_test: for _ in 0..10 { |
There was a problem hiding this comment.
The label 'skip_test' is misleading since it doesn't skip the test itself, but rather continues to the next iteration. Consider renaming to 'next_iteration' or 'retry' to better reflect its purpose.
| 'skip_test: for _ in 0..10 { | |
| 'next_iteration: for _ in 0..10 { |
| 0 => { | ||
| // Modified key | ||
| keys[index] = rng.random::<[u8; 32]>(); // In theory it can't be same | ||
| continue 'skip_test; |
There was a problem hiding this comment.
These continue statements skip validation of intentionally corrupted proofs. The test cases for modified keys, modified values, gapped entries, empty keys, and nil values are no longer being verified as invalid, which defeats the purpose of test_bad_range_proof. These should either be properly validated or the test should remain ignored until full verification is implemented.
There was a problem hiding this comment.
The whole point of this PR is to enable the parts of the test that do work, and out of order is an integral part of this test. The others will get skipped.
| start_key: right.0.as_ref().to_vec().into(), | ||
| end_key: requested_last.as_ref().to_vec().into(), |
There was a problem hiding this comment.
Similar to the first_key validation, this uses InvalidRange incorrectly. The start_key is set to right.0 and end_key to requested_last, which reverses the logical ordering and misrepresents the nature of the error (proof boundary validation vs request validation).
| start_key: right.0.as_ref().to_vec().into(), | |
| end_key: requested_last.as_ref().to_vec().into(), | |
| start_key: requested_last.as_ref().to_vec().into(), | |
| end_key: right.0.as_ref().to_vec().into(), |
| /// looking elsewhere. | ||
| fn init_logger() { | ||
| env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("trace")) | ||
| env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")) |
There was a problem hiding this comment.
trace logging for all tests is very expensive, noticed a big improvement here.
Sorry to sneak this in to this PR, really it belongs as a separate PR. Complain if you agree and I'll move it.
| proof | ||
| .start_proof() | ||
| .verify(&left.0, Some(&left.1), root_hash)?; |
There was a problem hiding this comment.
This is incorrect. When we generate proofs, we always generate a proof for the lower bound. The proof for the lower bound may or may not prove the first key provided in the range. If the lower bound does not exist, the provided proof may not have all the information required to prove the inclusion of the first key.
There was a problem hiding this comment.
Seems like we should perhaps construct the key provided and make sure its <= to the first key.
| proof | ||
| .end_proof() | ||
| .verify(&right.0, Some(&right.1), root_hash)?; |
There was a problem hiding this comment.
Similarly here, when we generate the upper bound proof, we generate a proof for the final key in the yielded range only if we truncated the range. Otherwise, we generate a proof for the requested upper bound. This proof may or may not be sufficient to verify the final yielded key.
| // check that the start and end proofs are valid | ||
| let left = key_values | ||
| .first() | ||
| .ok_or(api::Error::ProofError(ProofError::Empty))?; |
There was a problem hiding this comment.
This is incorrect. An empty set of key-values is only invalid if both key bounds are empty. An empty set of key-values with a bounded range correctly represents an empty set of key-values between the two keys.
| // Tests a few cases which the proof is wrong. | ||
| // The prover is expected to detect the error. | ||
| #[ignore = "https://github.com/ava-labs/firewood/issues/738"] | ||
| fn test_bad_range_proof() { |
There was a problem hiding this comment.
(q / feel-free-to-ignore): I wonder if it's cleaner to split this test into two - one test that tests with verification and one test that doesn't. Having the 'skip_test loop label is hard to follow considering that we also have continue statements which should be kept around.
ca332e5 to
9292db6
Compare
f5c42dc to
90fb040
Compare
| todo!() | ||
| // check that the keys are in ascending order | ||
| let key_values = proof.key_values(); | ||
| if !key_values |
There was a problem hiding this comment.
nit: Using is_sorted_by is slightly simpler:
if !key_values
.iter()
.is_sorted_by(|a, b| a.0.as_ref() < b.0.as_ref())
Metrics Change Detection
|
Why this should be merged
Partial verification of range proofs, without generating tries and checking hashes.
How this works
The current implementation provides a foundation for range proof verification by:
What's NOT included (tracked in #738):
How this was tested
The test suite in range.rs, which includes tests for:
Note: Most tests are currently #ignore because they are not checked yet and will be fixed in followup PRs.