mithril_stm/aggregate_signature/
basic_verifier.rs

1use std::collections::{BTreeMap, HashMap, HashSet};
2
3use crate::bls_multi_signature::{BlsSignature, BlsVerificationKey};
4use crate::key_registration::RegisteredParty;
5use crate::merkle_tree::MerkleTreeLeaf;
6use crate::{
7    AggregationError, CoreVerifierError, Index, Parameters, SingleSignature,
8    SingleSignatureWithRegisteredParty, Stake,
9};
10
11/// Full node verifier including the list of eligible signers and the total stake of the system.
12pub struct BasicVerifier {
13    /// List of registered parties.
14    pub eligible_parties: Vec<RegisteredParty>,
15    /// Total stake of registered parties.
16    pub total_stake: Stake,
17}
18
19impl BasicVerifier {
20    /// Setup a basic verifier for given list of signers.
21    ///     * Collect the unique signers in a hash set,
22    ///     * Calculate the total stake of the eligible signers,
23    ///     * Sort the eligible signers.
24    pub fn setup(public_signers: &[(BlsVerificationKey, Stake)]) -> Self {
25        let mut total_stake: Stake = 0;
26        let mut unique_parties = HashSet::new();
27        for signer in public_signers.iter() {
28            let (res, overflow) = total_stake.overflowing_add(signer.1);
29            if overflow {
30                panic!("Total stake overflow");
31            }
32            total_stake = res;
33            unique_parties.insert(MerkleTreeLeaf(signer.0, signer.1));
34        }
35
36        let mut eligible_parties: Vec<_> = unique_parties.into_iter().collect();
37        eligible_parties.sort_unstable();
38        BasicVerifier {
39            eligible_parties,
40            total_stake,
41        }
42    }
43
44    /// Preliminary verification that checks whether indices are unique and the quorum is achieved.
45    pub(crate) fn preliminary_verify(
46        total_stake: &Stake,
47        signatures: &[SingleSignatureWithRegisteredParty],
48        parameters: &Parameters,
49        msg: &[u8],
50    ) -> Result<(), CoreVerifierError> {
51        let mut nr_indices = 0;
52        let mut unique_indices = HashSet::new();
53
54        for sig_reg in signatures {
55            sig_reg
56                .sig
57                .check_indices(parameters, &sig_reg.reg_party.1, msg, total_stake)?;
58            for &index in &sig_reg.sig.indexes {
59                unique_indices.insert(index);
60                nr_indices += 1;
61            }
62        }
63
64        if nr_indices != unique_indices.len() {
65            return Err(CoreVerifierError::IndexNotUnique);
66        }
67        if (nr_indices as u64) < parameters.k {
68            return Err(CoreVerifierError::NoQuorum(nr_indices as u64, parameters.k));
69        }
70
71        Ok(())
72    }
73
74    /// Given a slice of `sig_reg_list`, this function returns a new list of `sig_reg_list` with only valid indices.
75    /// In case of conflict (having several signatures for the same index)
76    /// it selects the smallest signature (i.e. takes the signature with the smallest scalar).
77    /// The function selects at least `self.k` indexes.
78    ///  # Error
79    /// If there is no sufficient signatures, then the function fails.
80    // todo: We need to agree on a criteria to dedup (by default we use a BTreeMap that guarantees keys order)
81    // todo: not good, because it only removes index if there is a conflict (see benches)
82    pub fn dedup_sigs_for_indices(
83        total_stake: &Stake,
84        params: &Parameters,
85        msg: &[u8],
86        sigs: &[SingleSignatureWithRegisteredParty],
87    ) -> Result<Vec<SingleSignatureWithRegisteredParty>, AggregationError> {
88        let mut sig_by_index: BTreeMap<Index, &SingleSignatureWithRegisteredParty> =
89            BTreeMap::new();
90        let mut removal_idx_by_vk: HashMap<&SingleSignatureWithRegisteredParty, Vec<Index>> =
91            HashMap::new();
92
93        for sig_reg in sigs.iter() {
94            if sig_reg
95                .sig
96                .verify_core(
97                    params,
98                    &sig_reg.reg_party.0,
99                    &sig_reg.reg_party.1,
100                    msg,
101                    total_stake,
102                )
103                .is_err()
104            {
105                continue;
106            }
107            for index in sig_reg.sig.indexes.iter() {
108                let mut insert_this_sig = false;
109                if let Some(&previous_sig) = sig_by_index.get(index) {
110                    let sig_to_remove_index = if sig_reg.sig.sigma < previous_sig.sig.sigma {
111                        insert_this_sig = true;
112                        previous_sig
113                    } else {
114                        sig_reg
115                    };
116
117                    if let Some(indexes) = removal_idx_by_vk.get_mut(sig_to_remove_index) {
118                        indexes.push(*index);
119                    } else {
120                        removal_idx_by_vk.insert(sig_to_remove_index, vec![*index]);
121                    }
122                } else {
123                    insert_this_sig = true;
124                }
125
126                if insert_this_sig {
127                    sig_by_index.insert(*index, sig_reg);
128                }
129            }
130        }
131
132        let mut dedup_sigs: HashSet<SingleSignatureWithRegisteredParty> = HashSet::new();
133        let mut count: u64 = 0;
134
135        for (_, &sig_reg) in sig_by_index.iter() {
136            if dedup_sigs.contains(sig_reg) {
137                continue;
138            }
139            let mut deduped_sig = sig_reg.clone();
140            if let Some(indexes) = removal_idx_by_vk.get(sig_reg) {
141                deduped_sig.sig.indexes = deduped_sig
142                    .sig
143                    .indexes
144                    .clone()
145                    .into_iter()
146                    .filter(|i| !indexes.contains(i))
147                    .collect();
148            }
149
150            let size: Result<u64, _> = deduped_sig.sig.indexes.len().try_into();
151            if let Ok(size) = size {
152                if dedup_sigs.contains(&deduped_sig) {
153                    panic!("Should not reach!");
154                }
155                dedup_sigs.insert(deduped_sig);
156                count += size;
157
158                if count >= params.k {
159                    return Ok(dedup_sigs.into_iter().collect());
160                }
161            }
162        }
163
164        Err(AggregationError::NotEnoughSignatures(count, params.k))
165    }
166
167    /// Collect and return `Vec<BlsSignature>, Vec<BlsVerificationKey>` which will be used
168    /// by the aggregate verification.
169    pub(crate) fn collect_sigs_vks(
170        sig_reg_list: &[SingleSignatureWithRegisteredParty],
171    ) -> (Vec<BlsSignature>, Vec<BlsVerificationKey>) {
172        let sigs = sig_reg_list
173            .iter()
174            .map(|sig_reg| sig_reg.sig.sigma)
175            .collect::<Vec<BlsSignature>>();
176        let vks = sig_reg_list
177            .iter()
178            .map(|sig_reg| sig_reg.reg_party.0)
179            .collect::<Vec<BlsVerificationKey>>();
180
181        (sigs, vks)
182    }
183
184    /// Core verification
185    ///
186    /// Verify a list of signatures with respect to given message with given parameters.
187    pub fn verify(
188        &self,
189        signatures: &[SingleSignature],
190        parameters: &Parameters,
191        msg: &[u8],
192    ) -> Result<(), CoreVerifierError> {
193        let sig_reg_list = signatures
194            .iter()
195            .map(|sig| SingleSignatureWithRegisteredParty {
196                sig: sig.clone(),
197                reg_party: self.eligible_parties[sig.signer_index as usize],
198            })
199            .collect::<Vec<SingleSignatureWithRegisteredParty>>();
200
201        let unique_sigs =
202            Self::dedup_sigs_for_indices(&self.total_stake, parameters, msg, &sig_reg_list)?;
203
204        Self::preliminary_verify(&self.total_stake, &unique_sigs, parameters, msg)?;
205
206        let (sigs, vks) = Self::collect_sigs_vks(&unique_sigs);
207
208        BlsSignature::verify_aggregate(msg.to_vec().as_slice(), &vks, &sigs)?;
209
210        Ok(())
211    }
212}