-
Notifications
You must be signed in to change notification settings - Fork 53
feat(stm): Add key registration support for pre-aggregation primitives #2932
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: main
Are you sure you want to change the base?
Conversation
fix register test
…sing it in AggregateVerificationKey
| merkle_tree_commitment: MerkleTreeBatchCommitment<D::SnarkHash, MerkleTreeSnarkLeaf>, | ||
| } | ||
|
|
||
| impl<D: MembershipDigest> AggregateVerificationKeyForSnark<D> { |
Check warning
Code scanning / clippy
method get_merkle_tree_commitment is never used Warning
| merkle_tree_commitment: MerkleTreeBatchCommitment<D::SnarkHash, MerkleTreeSnarkLeaf>, | ||
| } | ||
|
|
||
| impl<D: MembershipDigest> AggregateVerificationKeyForSnark<D> { |
Check warning
Code scanning / clippy
method get_merkle_tree_commitment is never used Warning
…move batch and changed type of EligibilityValue
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 adds key registration support for pre-aggregation primitives by introducing a Snark proof system alongside the existing Concatenation proof system. The changes rename the "Future" variant to "Snark" throughout the codebase and implement the foundational structures needed for Snark-based aggregation.
Changes:
- Renamed "Future" to "Snark" across all proof system enums and types for better clarity
- Added Hash trait implementation for SchnorrVerificationKey to support its use in merkle trees
- Introduced new Snark-specific types:
AggregateVerificationKeyForSnark,MerkleTreeSnarkLeaf,VerificationKeyForSnark, andEligibilityValue
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
signature_scheme/unique_schnorr_signature/verification_key.rs |
Adds Hash trait implementation for SchnorrVerificationKey |
protocol/mod.rs |
Introduces VerificationKeyForSnark type alias |
protocol/aggregate_signature/signature.rs |
Renames Future variant to Snark in AggregateSignatureType and AggregateSignature enums |
protocol/aggregate_signature/clerk.rs |
Updates clerk to reference Snark instead of Future |
protocol/aggregate_signature/aggregate_key.rs |
Implements Snark variant for AggregateVerificationKey with serialization support |
proof_system/mod.rs |
Exports new halo2_snark module and its types |
proof_system/halo2_snark/mod.rs |
Creates new module structure for Snark proof system |
proof_system/halo2_snark/aggregate_key.rs |
Implements AggregateVerificationKeyForSnark with merkle tree commitment |
membership_commitment/merkle_tree/leaf.rs |
Adds MerkleTreeSnarkLeaf for Snark-based merkle trees |
lib.rs |
Exports new Snark types and defines EligibilityValue |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// The values that are committed in the Merkle Tree for `ConcatenationProof`. | ||
| /// Namely, a verified `BlsVerificationKey` and its corresponding stake. |
Copilot
AI
Jan 21, 2026
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.
The documentation comment incorrectly refers to both ConcatenationProof and BlsVerificationKey. This struct is for the Snark proof system (not Concatenation) and uses SchnorrVerificationKey (not BLS). The comment should be updated to accurately describe that this is used for the Snark proof system with Schnorr verification keys and eligibility values.
| /// The values that are committed in the Merkle Tree for `ConcatenationProof`. | |
| /// Namely, a verified `BlsVerificationKey` and its corresponding stake. | |
| /// The values that are committed in the Merkle Tree for the Snark proof system. | |
| /// Namely, a verified `SchnorrVerificationKey` and its corresponding eligibility value. |
| #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Hash)] | ||
| pub struct MerkleTreeSnarkLeaf(pub VerificationKeyForSnark, pub EligibilityValue); |
Copilot
AI
Jan 21, 2026
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.
The MerkleTreeSnarkLeaf struct lacks PartialOrd and Ord implementations that are present in MerkleTreeConcatenationLeaf. Given that both structures serve similar purposes (merkle tree leaves with verification keys and values), and that ordering is important for batch opening efficiency as explained in MerkleTreeConcatenationLeaf's documentation, MerkleTreeSnarkLeaf should also implement these traits.
| } | ||
|
|
||
| impl<D: MembershipDigest> AggregateVerificationKeyForSnark<D> { | ||
| /// Get the Merkle tree batch commitment. |
Copilot
AI
Jan 21, 2026
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.
The comment states "Get the Merkle tree batch commitment" but the method name is get_merkle_tree_commitment and returns a MerkleTreeCommitment, not a batch commitment. The documentation should be corrected to accurately describe what is being returned.
| /// Get the Merkle tree batch commitment. | |
| /// Get the Merkle tree commitment. |
|
|
||
| bytes | ||
| } | ||
|
|
Copilot
AI
Jan 21, 2026
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.
The from_bytes method is missing documentation. Public methods should have doc comments explaining their purpose, parameters, return values, and potential errors.
| /// Reconstruct an aggregate verification key for Snark from its byte representation. | |
| /// | |
| /// # Parameters | |
| /// | |
| /// - `bytes`: A byte slice containing the serialized form of this key, as produced by | |
| /// [`AggregateVerificationKeyForSnark::to_bytes`]. | |
| /// | |
| /// # Returns | |
| /// | |
| /// Returns an [`AggregateVerificationKeyForSnark`] instance on success. | |
| /// | |
| /// # Errors | |
| /// | |
| /// Returns an error if `bytes` do not encode a valid underlying | |
| /// [`MerkleTreeCommitment`] and deserialization fails. |
| } | ||
| #[cfg(feature = "future_snark")] | ||
| AggregateVerificationKey::Future => vec![], | ||
| AggregateVerificationKey::Snark(_) => vec![], |
Copilot
AI
Jan 21, 2026
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.
The to_bytes method for AggregateVerificationKey::Snark returns an empty vector, which is inconsistent with the corresponding from_bytes implementation that expects actual data. This asymmetry will cause deserialization to fail or produce incorrect results. The Snark variant should serialize its underlying AggregateVerificationKeyForSnark data.
| AggregateVerificationKey::Snark(_) => vec![], | |
| AggregateVerificationKey::Snark(snark_aggregate_verification_key) => { | |
| snark_aggregate_verification_key.to_bytes() | |
| } |
| #[cfg(feature = "future_snark")] | ||
| /// The values that are committed in the Merkle Tree for `ConcatenationProof`. | ||
| /// Namely, a verified `BlsVerificationKey` and its corresponding stake. | ||
| #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Hash)] | ||
| pub struct MerkleTreeSnarkLeaf(pub VerificationKeyForSnark, pub EligibilityValue); | ||
|
|
||
| #[cfg(feature = "future_snark")] | ||
| impl MerkleTreeLeaf for MerkleTreeSnarkLeaf { | ||
| fn as_bytes_for_merkle_tree(&self) -> Vec<u8> { | ||
| self.to_bytes() | ||
| } | ||
| } | ||
|
|
||
| #[cfg(feature = "future_snark")] | ||
| impl MerkleTreeSnarkLeaf { | ||
| fn to_bytes(self) -> Vec<u8> { | ||
| let mut result = [0u8; 64]; | ||
| result[..32].copy_from_slice(&self.0.to_bytes()); | ||
| result[32..].copy_from_slice(&self.1.to_bytes_le()); | ||
| result.to_vec() | ||
| } | ||
|
|
||
| // TODO: remove this allow dead_code directive when function is called or future_snark is activated | ||
| #[allow(dead_code)] | ||
| pub(crate) fn from_bytes(bytes: &[u8]) -> StmResult<Self> { | ||
| if bytes.len() < 32 { | ||
| return Err(anyhow!(MerkleTreeError::SerializationError)).with_context( | ||
| || "Not enough bytes provided to construct a Merkle tree leaf for Snark.", | ||
| ); | ||
| } | ||
| let schnorr_verification_key = VerificationKeyForSnark::from_bytes(&bytes[..32]) | ||
| .map_err(|_| MerkleTreeError::SerializationError)?; | ||
| let mut u64_bytes = [0u8; 32]; | ||
| u64_bytes.copy_from_slice(&bytes[32..]); | ||
| let eligibility_value = match EligibilityValue::from_bytes_le(&u64_bytes).into_option() { | ||
| Some(base_field_element) => Ok(base_field_element), | ||
| None => Err(anyhow!(MerkleTreeError::SerializationError)), | ||
| }?; | ||
| Ok(MerkleTreeSnarkLeaf( | ||
| schnorr_verification_key, | ||
| eligibility_value, | ||
| )) | ||
| } | ||
| } |
Copilot
AI
Jan 21, 2026
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.
The MerkleTreeSnarkLeaf struct and its methods (to_bytes, from_bytes) lack test coverage. Given that similar functionality for MerkleTreeConcatenationLeaf is tested in the merkle tree test suite, this new leaf type should also include tests to verify serialization/deserialization behavior and the Hash trait implementation.
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||
| pub struct AggregateVerificationKeyForSnark<D: MembershipDigest> { | ||
| merkle_tree_commitment: MerkleTreeCommitment<D::SnarkHash, MerkleTreeSnarkLeaf>, | ||
| } | ||
|
|
||
| impl<D: MembershipDigest> AggregateVerificationKeyForSnark<D> { | ||
| /// Get the Merkle tree batch commitment. | ||
| pub(crate) fn get_merkle_tree_commitment( | ||
| &self, | ||
| ) -> MerkleTreeCommitment<D::SnarkHash, MerkleTreeSnarkLeaf> { | ||
| self.merkle_tree_commitment.clone() | ||
| } | ||
|
|
||
| /// Convert the aggregate verification key for Snark to bytes. | ||
| pub fn to_bytes(&self) -> Vec<u8> { | ||
| let mut bytes = Vec::new(); | ||
| bytes.extend(self.merkle_tree_commitment.to_bytes()); | ||
|
|
||
| bytes | ||
| } | ||
|
|
||
| pub fn from_bytes(bytes: &[u8]) -> StmResult<Self> { | ||
| let size = bytes.len(); | ||
| let merkle_tree_commitment = MerkleTreeCommitment::from_bytes(&bytes[0..size])?; | ||
| Ok(Self { | ||
| merkle_tree_commitment, | ||
| }) | ||
| } | ||
| } |
Copilot
AI
Jan 21, 2026
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.
The new AggregateVerificationKeyForSnark struct and its methods (to_bytes, from_bytes, get_merkle_tree_commitment) lack test coverage. Given that similar structs like AggregateVerificationKeyForConcatenation have comprehensive tests, this new functionality should also include tests to verify serialization/deserialization and other behaviors.
| if bytes.len() < 32 { | ||
| return Err(anyhow!(MerkleTreeError::SerializationError)).with_context( | ||
| || "Not enough bytes provided to construct a Merkle tree leaf for Snark.", | ||
| ); |
Copilot
AI
Jan 21, 2026
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.
The from_bytes method checks if bytes.len() < 32 but then tries to copy 32 bytes from bytes[32..] without verifying that there are at least 64 bytes available. This could cause a panic if the slice is between 32 and 64 bytes. The validation should check for bytes.len() < 64 instead.
| let size = bytes.len(); | ||
| let merkle_tree_commitment = MerkleTreeCommitment::from_bytes(&bytes[0..size])?; |
Copilot
AI
Jan 21, 2026
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.
The slice operation &bytes[0..size] is redundant since it's equivalent to just bytes. The entire byte slice is being passed to from_bytes, making the explicit slicing unnecessary.
| let size = bytes.len(); | |
| let merkle_tree_commitment = MerkleTreeCommitment::from_bytes(&bytes[0..size])?; | |
| let merkle_tree_commitment = MerkleTreeCommitment::from_bytes(bytes)?; |
037d8b7 to
b097651
Compare
Content
This PR includes changes to the stm library, more specifically to the merkle tree, protocol and proof system modules.
Pre-submit checklist
Comments
Issue(s)
Relates to #2792