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