- 
                Notifications
    You must be signed in to change notification settings 
- Fork 487
          feat: SumMerkleDamgardDynamicLength
          #1634
        
          New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces SumMerkleDamgardDynamicLength, a utility function for computing Merkle–Damgård hashes over dynamically sized slices using log-derivative lookup. The implementation is validated through enhanced Poseidon2 circuit tests that verify prefix-hash correctness.
- Adds hash.SumMerkleDamgardDynamicLengthto compute hash at dynamic length usinglogderivlookup
- Updates Poseidon2 test to validate prefix hashes against both incremental hasher and the new function
- Modifies test data generation to use proper field element encoding via fr.Bytesbuffer
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description | 
|---|---|
| std/hash/hash.go | Implements SumMerkleDamgardDynamicLengthfunction using log-derivative lookup for dynamic-length hashing | 
| std/hash/poseidon2/poseidon2_test.go | Expands test to validate prefix hashes and compare incremental hasher with SumMerkleDamgardDynamicLength | 
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
SumMerkleDamgardDynamicLength with testsSumMerkleDamgardDynamicLength
      There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed - I'm not sure about the interfaces right now. I think adding as a general purpose function is unsafe as allows to easily create collisions. I think leaving it up to user implement correctly will cause issues. To overcome, we should do standard method of adding the input width as a last block, but this doubles the constraint count imo.
Secondly - I'd follow current interfaces pattern. All other hasher types are defined as interfaces, but this is a single function. For me it is a bit confusing.
Or - if only used in Linea, then I'd instead add the method there directly as we can have better control already within business logic which would avoid possible collisons.
| // - length: length of the prefix of data to be hashed. The verifier will not accept a value outside the range {0, 1, ..., len(data)}. | ||
| // The gnark prover will refuse to attempt to generate such an unsuccessful proof. | ||
| // - data: the values a prefix of which is to be hashed. | ||
| func SumMerkleDamgardDynamicLength(api frontend.API, f Compressor, initialState frontend.Variable, length frontend.Variable, data []frontend.Variable) frontend.Variable { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this function signature allow for length extension attacks? I.e. lets say:
- IV = 0
- f_0 = compress(IV, msg_0)
- f_1 = compress(f_0, msg_1)
Then, when we do either:
SumMerkleDamgardDynamicLength(api, Compressor, IV, 2, [msg_0, msg_1])
or
SumMerkleDamgardDynamicLength(api, Compressor, f_0, 1, [msg_1, msg_xxx])
we would get the same result? And considering all are user inputs then it could imo lead to possible collisions.
We also provide variable-length mode for binary hashes (see interface BinaryFixedLengthHasher). But there depending on the underlying hash function (sha256, ripemd, sha3) the length is appended to the input, avoid collision problems.
| // The gnark prover will refuse to attempt to generate such an unsuccessful proof. | ||
| // - data: the values a prefix of which is to be hashed. | ||
| func SumMerkleDamgardDynamicLength(api frontend.API, f Compressor, initialState frontend.Variable, length frontend.Variable, data []frontend.Variable) frontend.Variable { | ||
| resT := logderivlookup.New(api) | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And imo this method diverges from the rest of the APIs we use for hashers - otherwise we have defined FieldHasher for algebraic hash, and BinaryHasher/BinaryFixedLengthHasher for binary hashes (the ..FixedLengthHasher providing the same functionality i.e. allowing to dynamically set the input length to be hash).
I recommend following similar patter for consistency -- create FieldFixedLengthHasher interface
type FieldFixedLengthHasher interface {
    FieldHasher
    FixedLengthSum(length frontend.Variable) frontend.Variable
}and then make in MiMC and Poseidon2 packages return this instead of FieldHasher.
A simple utility function that computes the hash of a dynamically sized slice of variables. Used in Linea.
Note
Introduce
SumMerkleDamgardDynamicLengthand update Poseidon2 circuit test to validate incremental prefix hashes against the new utility.std/hash/hash.go):SumMerkleDamgardDynamicLength(api, f, initialState, length, data)to compute Merkle–Damgård hash of a prefix using lookup-based selection.NewMerkleDamgardHasherdocs and importlogderivlookup.std/hash/poseidon2/poseidon2_test.go):Expected[i] = H(Input[:i+1]).hash.SumMerkleDamgardDynamicLengthwith Poseidon2 compressor and IV0.Written by Cursor Bugbot for commit c9dd1c3. This will update automatically on new commits. Configure here.