feat(stm): Implementation of the digest trait for the Poseidon hash from Midnight#2936
Conversation
be5010c to
efb1220
Compare
|
I'm not sure the |
@damrobi |
To me the first case would make more sense as you are concatenating 3 different things. If you want to do the second case, the user could concatenate the bytes first in a buffer then hash this one instead. Let's have a look about this later comparing it with Midnight's implementation too. |
There was a problem hiding this comment.
Pull request overview
This PR implements a Digest trait wrapper for the Poseidon hash function from Midnight, enabling its use in SNARK pre-aggregation primitives for the Mithril STM library. The implementation allows the Poseidon hash to be used as the SnarkHash type in Merkle tree constructions.
Changes:
- Added
MidnightPoseidonDigeststruct implementing theDigesttrait (Update, FixedOutput, Reset, HashMarker, OutputSizeUser) - Updated
MithrilMembershipDigest::SnarkHashto useMidnightPoseidonDigestinstead of the Blake2b placeholder - Added comprehensive tests for the digest implementation including edge cases
- Added Merkle tree tests using the new Poseidon digest with the
future_snarkfeature
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 13 comments.
| File | Description |
|---|---|
| mithril-stm/src/signature_scheme/unique_schnorr_signature/jubjub/poseidon_digest.rs | Implements MidnightPoseidonDigest wrapper struct with Digest trait implementation and test suite |
| mithril-stm/src/lib.rs | Updates SnarkHash type alias to use MidnightPoseidonDigest and adds necessary imports |
| mithril-stm/src/membership_commitment/merkle_tree/tree.rs | Adds comprehensive property-based tests for Merkle tree operations using Poseidon digest |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
We have a hash function that in circuit takes as input &[Fq] but in CPU takes &[u8] (to satisfy the trait's interfaces). Hence we need to convert somewhere, when updating or finalizing the hasher, the bytes to field elements. As we work with prime fields, we cannot directly cast the bytes to field elements. We need to either take fewer bytes than our field's prime and cast, take 32 bytes and check we are under the modulus before casting, or take more bytes and somehow hash them to the field. p.s. I am trying to be careful saying "somehow hash to field" here and from now on because we may not choose to use the RFC's function In @kitounliu 's circuit, we always work with field element inputs:
In this code, we could assume that the hasher's &[u8] input already are Fq's byte representation. In that case, we should add some comments on the Poseidon code stating it (perhaps some assert?) and in registration/signing adding the extra conversion (the target must be cast to Fq, and message hashed to Fq). If we don't want to assume that the hasher's &[u8] input already are Fq's byte representations., for instance for the hash function to be generic, the design become a bit delicate.
Second, depending on the choice choice above, we may want to restrict the hasher so that the update function takes a "fixed" number of bytes (e.g. at most 32 bytes or a multiple of 32 bytes). We can ensure that with Maybe I am overthinking, or I missed something out, but we should all agree on what design choice to take. |
hjeljeli32
left a comment
There was a problem hiding this comment.
LGTM. I just left a few comments/suggestions.
All my questions were answered by @damrobi |
e541006 to
f34528e
Compare
curiecrypt
left a comment
There was a problem hiding this comment.
LGTM 👍
Regarding the digest implementation, I don’t see any issues or inconsistencies for the use cases covered in this branch. That said, it’s still hard to be certain whether any problems might occur when we integrate this into other parts of the codebase, we’ll be able to assess that more clearly as we progress.
The documentation looks sufficient and well explained. Thanks for putting in the work on that @rrtoledo, @damrobi .
One concern I do have is the direct use of Midnight library entities in this module (JubjubBase, from_raw, etc). We should add wrappers or use the existing ones for those occurrences. This doesn’t necessarily need to be done in this PR, but it’s something we should plan to do in the near future.
1bd88b8 to
e3bab96
Compare
f34528e to
b8c2e9d
Compare
…h 0s and added some tests
…cated module for hash
b8c2e9d to
495d029
Compare
495d029 to
b58a880
Compare
Content
This PR includes a wrapper that implements the Digest trait to be used with the Poseidon hash function from Midnight.
Pre-submit checklist
Comments
Quick summary of the important traits implemented:
Update: updates the internal buffer with new data, takes a slice of bytes as input.FixedOutput: contains the finalize function that outputs the result of the hash, since Poseidon takes base field elements as input there is a conversion from the bytes of the buffer to JubjubBase elements before applying the hash.I have a question regarding the design of the digest functions:
Last remark, this problem concerns the CPU implementation of Poseidon. In the circuit, we only deal with JubjubBase elements so it is clear what is done. We need to make sure both implementations give the same results.
I think that given the current use of digest in the implementation, it does not matter too much which way we use as the example I gave does not come up but I wanted to check with more people as it might change in the future.
Issue(s)
Relates to #2942