mithril_stm/protocol/aggregate_signature/
aggregate_key.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{
4    ClosedKeyRegistration, MembershipDigest, Stake,
5    membership_commitment::{
6        MerkleBatchPath, MerkleTreeBatchCommitment, MerkleTreeConcatenationLeaf,
7    },
8};
9
10/// Stm aggregate key (batch compatible), which contains the merkle tree commitment and the total stake of the system.
11/// Batch Compat Merkle tree commitment includes the number of leaves in the tree in order to obtain batch path.
12#[derive(Debug, Clone, Serialize, Deserialize)]
13#[serde(bound(
14    serialize = "MerkleBatchPath<D::ConcatenationHash>: Serialize",
15    deserialize = "MerkleBatchPath<D::ConcatenationHash>: Deserialize<'de>"
16))]
17pub struct AggregateVerificationKey<D: MembershipDigest> {
18    mt_commitment: MerkleTreeBatchCommitment<D::ConcatenationHash, MerkleTreeConcatenationLeaf>,
19    total_stake: Stake,
20}
21
22impl<D: MembershipDigest> AggregateVerificationKey<D> {
23    pub(crate) fn get_merkle_tree_batch_commitment(
24        &self,
25    ) -> MerkleTreeBatchCommitment<D::ConcatenationHash, MerkleTreeConcatenationLeaf> {
26        self.mt_commitment.clone()
27    }
28
29    pub fn get_total_stake(&self) -> Stake {
30        self.total_stake
31    }
32}
33
34impl<D: MembershipDigest> PartialEq for AggregateVerificationKey<D> {
35    fn eq(&self, other: &Self) -> bool {
36        self.mt_commitment == other.mt_commitment && self.total_stake == other.total_stake
37    }
38}
39
40impl<D: MembershipDigest> Eq for AggregateVerificationKey<D> {}
41
42impl<D: MembershipDigest> From<&ClosedKeyRegistration<D>> for AggregateVerificationKey<D> {
43    fn from(reg: &ClosedKeyRegistration<D>) -> Self {
44        Self {
45            mt_commitment: reg.merkle_tree.to_merkle_tree_batch_commitment(),
46            total_stake: reg.total_stake,
47        }
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use rand_chacha::ChaCha20Rng;
54    use rand_core::SeedableRng;
55
56    use super::*;
57
58    mod golden {
59
60        use crate::{Clerk, Initializer, KeyRegistration, MithrilMembershipDigest, Parameters};
61
62        use super::*;
63
64        const GOLDEN_JSON: &str = r#"
65        {
66            "mt_commitment":{
67                "root":[4,3,108,183,145,65,166,69,250,202,51,64,90,232,45,103,56,138,102,63,209,245,81,22,120,16,6,96,140,204,210,55],
68                "nr_leaves":4,
69                "hasher":null
70                },
71            "total_stake":6
72        }"#;
73
74        fn golden_value() -> AggregateVerificationKey<MithrilMembershipDigest> {
75            let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
76            let params = Parameters {
77                m: 10,
78                k: 5,
79                phi_f: 0.8,
80            };
81            let number_of_parties = 4;
82            let mut key_reg = KeyRegistration::init();
83            for stake in 0..number_of_parties {
84                let initializer = Initializer::new(params, stake, &mut rng);
85                key_reg.register(initializer.stake, initializer.pk).unwrap();
86            }
87
88            let closed_key_reg: ClosedKeyRegistration<MithrilMembershipDigest> = key_reg.close();
89            let clerk = Clerk::new_clerk_from_closed_key_registration(&params, &closed_key_reg);
90            clerk.compute_aggregate_verification_key()
91        }
92
93        #[test]
94        fn golden_conversions() {
95            let value = serde_json::from_str(GOLDEN_JSON)
96                .expect("This JSON deserialization should not fail");
97            assert_eq!(golden_value(), value);
98
99            let serialized =
100                serde_json::to_string(&value).expect("This JSON serialization should not fail");
101            let golden_serialized = serde_json::to_string(&golden_value())
102                .expect("This JSON serialization should not fail");
103            assert_eq!(golden_serialized, serialized);
104        }
105    }
106}