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                .key_registration
74                .clone()
75                .into_merkle_tree::<D::ConcatenationHash, RegistrationEntryForConcatenation>()
76                .to_merkle_tree_batch_commitment(),
77            total_stake: reg.total_stake,
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use rand_chacha::ChaCha20Rng;
85    use rand_core::SeedableRng;
86
87    use crate::{
88        KeyRegistration, MithrilMembershipDigest, Parameters, RegistrationEntry,
89        VerificationKeyProofOfPossessionForConcatenation,
90        proof_system::AggregateVerificationKeyForConcatenation,
91        proof_system::concatenation::clerk::ConcatenationClerk, signature_scheme::BlsSigningKey,
92    };
93
94    type D = MithrilMembershipDigest;
95    mod golden {
96        use super::*;
97
98        const GOLDEN_BYTES: &[u8; 48] = &[
99            0, 0, 0, 0, 0, 0, 0, 2, 56, 37, 95, 107, 157, 98, 252, 194, 190, 204, 170, 26, 224, 10,
100            212, 7, 214, 89, 116, 196, 217, 122, 111, 56, 113, 253, 96, 45, 170, 121, 235, 159, 0,
101            0, 0, 0, 0, 0, 0, 2,
102        ];
103
104        fn golden_value() -> AggregateVerificationKeyForConcatenation<D> {
105            let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
106            let params = Parameters {
107                m: 10,
108                k: 5,
109                phi_f: 0.8,
110            };
111            let sk_1 = BlsSigningKey::generate(&mut rng);
112            let sk_2 = BlsSigningKey::generate(&mut rng);
113            let pk_1 = VerificationKeyProofOfPossessionForConcatenation::from(&sk_1);
114            let pk_2 = VerificationKeyProofOfPossessionForConcatenation::from(&sk_2);
115
116            let mut key_reg = KeyRegistration::initialize();
117            let entry1 = RegistrationEntry::new(pk_1, 1).unwrap();
118            let entry2 = RegistrationEntry::new(pk_2, 1).unwrap();
119
120            key_reg.register_by_entry(&entry1).unwrap();
121            key_reg.register_by_entry(&entry2).unwrap();
122            let closed_key_reg = key_reg.close_registration();
123
124            let clerk = ConcatenationClerk::new_clerk_from_closed_key_registration(
125                &params,
126                &closed_key_reg,
127            );
128
129            clerk.compute_aggregate_verification_key_for_concatenation()
130        }
131
132        #[test]
133        fn golden_conversions() {
134            let value = AggregateVerificationKeyForConcatenation::from_bytes(GOLDEN_BYTES)
135                .expect("This from bytes should not fail");
136            assert_eq!(golden_value(), value);
137
138            let serialized = AggregateVerificationKeyForConcatenation::to_bytes(&value);
139            let golden_serialized =
140                AggregateVerificationKeyForConcatenation::to_bytes(&golden_value());
141            assert_eq!(golden_serialized, serialized);
142        }
143    }
144
145    mod golden_json {
146        use super::*;
147
148        const GOLDEN_JSON: &str = r#"
149        {
150            "mt_commitment":{
151                "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],
152                "nr_leaves":2,
153                "hasher":null
154            },
155            "total_stake":2
156        }
157        "#;
158
159        fn golden_value() -> AggregateVerificationKeyForConcatenation<D> {
160            let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
161            let params = Parameters {
162                m: 10,
163                k: 5,
164                phi_f: 0.8,
165            };
166            let sk_1 = BlsSigningKey::generate(&mut rng);
167            let sk_2 = BlsSigningKey::generate(&mut rng);
168            let pk_1 = VerificationKeyProofOfPossessionForConcatenation::from(&sk_1);
169            let pk_2 = VerificationKeyProofOfPossessionForConcatenation::from(&sk_2);
170
171            let mut key_reg = KeyRegistration::initialize();
172            let entry1 = RegistrationEntry::new(pk_1, 1).unwrap();
173            let entry2 = RegistrationEntry::new(pk_2, 1).unwrap();
174
175            key_reg.register_by_entry(&entry1).unwrap();
176            key_reg.register_by_entry(&entry2).unwrap();
177            let closed_key_reg = key_reg.close_registration();
178
179            let clerk = ConcatenationClerk::new_clerk_from_closed_key_registration(
180                &params,
181                &closed_key_reg,
182            );
183
184            clerk.compute_aggregate_verification_key_for_concatenation()
185        }
186
187        #[test]
188        fn golden_conversions() {
189            let value: AggregateVerificationKeyForConcatenation<D> =
190                serde_json::from_str(GOLDEN_JSON)
191                    .expect("This JSON deserialization should not fail");
192
193            let serialized =
194                serde_json::to_string(&value).expect("This JSON serialization should not fail");
195            let golden_serialized = serde_json::to_string(&golden_value())
196                .expect("This JSON serialization should not fail");
197            assert_eq!(golden_serialized, serialized);
198        }
199    }
200}