mithril_stm/proof_system/concatenation/
aggregate_key.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{
4    ClosedKeyRegistration, MembershipDigest, RegistrationEntryForConcatenation, Stake, StmResult,
5    membership_commitment::{
6        MerkleBatchPath, MerkleTreeBatchCommitment, MerkleTreeConcatenationLeaf, MerkleTreeError,
7    },
8};
9
10/// Aggregate verification key of the concatenation proof system.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12#[serde(bound(
13    serialize = "MerkleBatchPath<D::ConcatenationHash>: Serialize",
14    deserialize = "MerkleBatchPath<D::ConcatenationHash>: Deserialize<'de>"
15))]
16pub struct AggregateVerificationKeyForConcatenation<D: MembershipDigest> {
17    mt_commitment: MerkleTreeBatchCommitment<D::ConcatenationHash, MerkleTreeConcatenationLeaf>,
18    total_stake: Stake,
19}
20
21impl<D: MembershipDigest> AggregateVerificationKeyForConcatenation<D> {
22    /// Get the Merkle tree batch commitment.
23    pub(crate) fn get_merkle_tree_batch_commitment(
24        &self,
25    ) -> MerkleTreeBatchCommitment<D::ConcatenationHash, MerkleTreeConcatenationLeaf> {
26        self.mt_commitment.clone()
27    }
28
29    /// Get the total stake.
30    pub fn get_total_stake(&self) -> Stake {
31        self.total_stake
32    }
33
34    /// Convert the aggregate verification key for concatenation to bytes.
35    pub fn to_bytes(&self) -> Vec<u8> {
36        let mut bytes = Vec::new();
37        bytes.extend(self.mt_commitment.to_bytes());
38        bytes.extend(self.total_stake.to_be_bytes());
39
40        bytes
41    }
42
43    pub fn from_bytes(bytes: &[u8]) -> StmResult<Self> {
44        let mut u64_bytes = [0u8; 8];
45        let size = bytes.len();
46
47        u64_bytes.copy_from_slice(&bytes[size - 8..]);
48        let stake = u64::from_be_bytes(u64_bytes);
49        let mt_commitment = MerkleTreeBatchCommitment::from_bytes(
50            bytes.get(..size - 8).ok_or(MerkleTreeError::SerializationError)?,
51        )?;
52        Ok(Self {
53            mt_commitment,
54            total_stake: stake,
55        })
56    }
57}
58
59impl<D: MembershipDigest> PartialEq for AggregateVerificationKeyForConcatenation<D> {
60    fn eq(&self, other: &Self) -> bool {
61        self.mt_commitment == other.mt_commitment && self.total_stake == other.total_stake
62    }
63}
64
65impl<D: MembershipDigest> Eq for AggregateVerificationKeyForConcatenation<D> {}
66
67impl<D: MembershipDigest> From<&ClosedKeyRegistration>
68    for AggregateVerificationKeyForConcatenation<D>
69{
70    fn from(reg: &ClosedKeyRegistration) -> Self {
71        Self {
72            mt_commitment: reg
73                .to_merkle_tree::<D::ConcatenationHash, RegistrationEntryForConcatenation>()
74                .to_merkle_tree_batch_commitment(),
75            total_stake: reg.total_stake,
76        }
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use rand_chacha::ChaCha20Rng;
83    use rand_core::SeedableRng;
84
85    use crate::{
86        KeyRegistration, MithrilMembershipDigest, Parameters, RegistrationEntry,
87        VerificationKeyProofOfPossessionForConcatenation,
88        proof_system::AggregateVerificationKeyForConcatenation,
89        proof_system::concatenation::clerk::ConcatenationClerk, signature_scheme::BlsSigningKey,
90    };
91
92    type D = MithrilMembershipDigest;
93    mod golden {
94        use super::*;
95
96        const GOLDEN_BYTES: &[u8; 48] = &[
97            0, 0, 0, 0, 0, 0, 0, 2, 56, 37, 95, 107, 157, 98, 252, 194, 190, 204, 170, 26, 224, 10,
98            212, 7, 214, 89, 116, 196, 217, 122, 111, 56, 113, 253, 96, 45, 170, 121, 235, 159, 0,
99            0, 0, 0, 0, 0, 0, 2,
100        ];
101
102        fn golden_value() -> AggregateVerificationKeyForConcatenation<D> {
103            let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
104            let params = Parameters {
105                m: 10,
106                k: 5,
107                phi_f: 0.8,
108            };
109            let sk_1 = BlsSigningKey::generate(&mut rng);
110            let sk_2 = BlsSigningKey::generate(&mut rng);
111            let pk_1 = VerificationKeyProofOfPossessionForConcatenation::from(&sk_1);
112            let pk_2 = VerificationKeyProofOfPossessionForConcatenation::from(&sk_2);
113
114            let mut key_reg = KeyRegistration::initialize();
115            let entry1 = RegistrationEntry::new(
116                pk_1,
117                1,
118                #[cfg(feature = "future_snark")]
119                None,
120            )
121            .unwrap();
122            let entry2 = RegistrationEntry::new(
123                pk_2,
124                1,
125                #[cfg(feature = "future_snark")]
126                None,
127            )
128            .unwrap();
129
130            key_reg.register_by_entry(&entry1).unwrap();
131            key_reg.register_by_entry(&entry2).unwrap();
132            let closed_key_reg = key_reg.close_registration();
133
134            let clerk = ConcatenationClerk::new_clerk_from_closed_key_registration(
135                &params,
136                &closed_key_reg,
137            );
138
139            clerk.compute_aggregate_verification_key_for_concatenation()
140        }
141
142        #[test]
143        fn golden_conversions() {
144            let value = AggregateVerificationKeyForConcatenation::from_bytes(GOLDEN_BYTES)
145                .expect("This from bytes should not fail");
146            assert_eq!(golden_value(), value);
147
148            let serialized = AggregateVerificationKeyForConcatenation::to_bytes(&value);
149            let golden_serialized =
150                AggregateVerificationKeyForConcatenation::to_bytes(&golden_value());
151            assert_eq!(golden_serialized, serialized);
152        }
153    }
154
155    mod golden_json {
156        use super::*;
157
158        const GOLDEN_JSON: &str = r#"
159        {
160            "mt_commitment":{
161                "root":[56,37,95,107,157,98,252,194,190,204,170,26,224,10,212,7,214,89,116,196,217,122,111,56,113,253,96,45,170,121,235,159],
162                "nr_leaves":2,
163                "hasher":null
164            },
165            "total_stake":2
166        }
167        "#;
168
169        fn golden_value() -> AggregateVerificationKeyForConcatenation<D> {
170            let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
171            let params = Parameters {
172                m: 10,
173                k: 5,
174                phi_f: 0.8,
175            };
176            let sk_1 = BlsSigningKey::generate(&mut rng);
177            let sk_2 = BlsSigningKey::generate(&mut rng);
178            let pk_1 = VerificationKeyProofOfPossessionForConcatenation::from(&sk_1);
179            let pk_2 = VerificationKeyProofOfPossessionForConcatenation::from(&sk_2);
180
181            let mut key_reg = KeyRegistration::initialize();
182            let entry1 = RegistrationEntry::new(
183                pk_1,
184                1,
185                #[cfg(feature = "future_snark")]
186                None,
187            )
188            .unwrap();
189            let entry2 = RegistrationEntry::new(
190                pk_2,
191                1,
192                #[cfg(feature = "future_snark")]
193                None,
194            )
195            .unwrap();
196
197            key_reg.register_by_entry(&entry1).unwrap();
198            key_reg.register_by_entry(&entry2).unwrap();
199            let closed_key_reg = key_reg.close_registration();
200
201            let clerk = ConcatenationClerk::new_clerk_from_closed_key_registration(
202                &params,
203                &closed_key_reg,
204            );
205
206            clerk.compute_aggregate_verification_key_for_concatenation()
207        }
208
209        #[test]
210        fn golden_conversions() {
211            let value: AggregateVerificationKeyForConcatenation<D> =
212                serde_json::from_str(GOLDEN_JSON)
213                    .expect("This JSON deserialization should not fail");
214
215            let serialized =
216                serde_json::to_string(&value).expect("This JSON serialization should not fail");
217            let golden_serialized = serde_json::to_string(&golden_value())
218                .expect("This JSON serialization should not fail");
219            assert_eq!(golden_serialized, serialized);
220        }
221    }
222}