MerkleTree insertion proofs (#344)

* implement merkletree insert & insert-proof-verification

* add merkletree circuit to verify insertion proof

wip

* fix merkletree's GraphViz generation for cases with empty siblings

* implement tree insert-verif circuit siblings checks

Note: I've implemented also an alternative version which instead of
inputting a witness value 'divergence_level' it inputs a bitmask. Both
approaches (divergence_level and divergence_bitmask) take the same
amount of constraints (336 constraints for a tree of 32 levels, and for
an hybrid approach it takes 331 constraints but the code gets a bit less
readable). So I've kept with the current implementation (using
divergence_level) which is more easy to follow.

* [tree] modify the strategy for the insert-proof (out-circuit)

* re-implement insert-proof verification circuit

* add pending checks and polish

* add tests for disabled(&enabled) cases that should fail

* update typos.toml config

* Add test with tampering

* add check 5.3, to prevent tampering (at insertion proof circuit)

* move old_leaf_hash computation outside the loop, simplify check 5.3 booleans

* apply @ed255 review suggestions

---------

Co-authored-by: Ahmad <root@ahmadafuni.com>
This commit is contained in:
arnaucube 2025-07-24 12:02:44 +02:00 committed by GitHub
parent 89dfc4e214
commit 745d654048
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 695 additions and 31 deletions

View file

@ -18,6 +18,8 @@ pub enum TreeInnerError {
ProofFail(String), // inclusion / exclusion
#[error("invalid {0} proof")]
InvalidProof(String),
#[error("state transition proof does not verify, reason: {0}")]
StateTransitionProofFail(String),
#[error("key too short (key length: {0}) for the max_depth: {1}")]
TooShortKey(usize, usize),
}
@ -73,6 +75,9 @@ impl TreeError {
pub(crate) fn invalid_proof(obj: String) -> Self {
new!(InvalidProof(obj))
}
pub(crate) fn state_transition_fail(reason: String) -> Self {
new!(StateTransitionProofFail(reason))
}
pub(crate) fn too_short_key(depth: usize, max_depth: usize) -> Self {
new!(TooShortKey(depth, max_depth))
}