mithril_stm/aggregate_signature/
signature.rs

1use blake2::digest::{Digest, FixedOutput};
2
3use serde::{Deserialize, Serialize};
4
5use crate::bls_multi_signature::{Signature, VerificationKey};
6use crate::key_reg::RegParty;
7use crate::merkle_tree::BatchPath;
8use crate::{
9    CoreVerifier, StmAggrVerificationKey, StmAggregateSignatureError, StmParameters, StmSigRegParty,
10};
11
12/// `StmMultiSig` uses the "concatenation" proving system (as described in Section 4.3 of the original paper.)
13/// This means that the aggregated signature contains a vector with all individual signatures.
14/// BatchPath is also a part of the aggregate signature which covers path for all signatures.
15#[derive(Debug, Clone, Serialize, Deserialize)]
16#[serde(bound(
17    serialize = "BatchPath<D>: Serialize",
18    deserialize = "BatchPath<D>: Deserialize<'de>"
19))]
20pub struct StmAggrSig<D: Clone + Digest + FixedOutput> {
21    pub(crate) signatures: Vec<StmSigRegParty>,
22    /// The list of unique merkle tree nodes that covers path for all signatures.
23    pub batch_proof: BatchPath<D>,
24}
25
26impl<D: Clone + Digest + FixedOutput + Send + Sync> StmAggrSig<D> {
27    /// Verify all checks from signatures, except for the signature verification itself.
28    ///
29    /// Indices and quorum are checked by `CoreVerifier::preliminary_verify` with `msgp`.
30    /// It collects leaves from signatures and checks the batch proof.
31    /// After batch proof is checked, it collects and returns the signatures and
32    /// verification keys to be used by aggregate verification.
33    fn preliminary_verify(
34        &self,
35        msg: &[u8],
36        avk: &StmAggrVerificationKey<D>,
37        parameters: &StmParameters,
38    ) -> Result<(Vec<Signature>, Vec<VerificationKey>), StmAggregateSignatureError<D>> {
39        let msgp = avk.get_mt_commitment().concat_with_msg(msg);
40        CoreVerifier::preliminary_verify(
41            &avk.get_total_stake(),
42            &self.signatures,
43            parameters,
44            &msgp,
45        )?;
46
47        let leaves = self
48            .signatures
49            .iter()
50            .map(|r| r.reg_party)
51            .collect::<Vec<RegParty>>();
52
53        avk.get_mt_commitment().check(&leaves, &self.batch_proof)?;
54
55        Ok(CoreVerifier::collect_sigs_vks(&self.signatures))
56    }
57
58    /// Verify aggregate signature, by checking that
59    /// * each signature contains only valid indices,
60    /// * the lottery is indeed won by each one of them,
61    /// * the merkle tree path is valid,
62    /// * the aggregate signature validates with respect to the aggregate verification key
63    ///   (aggregation is computed using functions `MSP.BKey` and `MSP.BSig` as described in Section 2.4 of the paper).
64    pub fn verify(
65        &self,
66        msg: &[u8],
67        avk: &StmAggrVerificationKey<D>,
68        parameters: &StmParameters,
69    ) -> Result<(), StmAggregateSignatureError<D>> {
70        let msgp = avk.get_mt_commitment().concat_with_msg(msg);
71        let (sigs, vks) = self.preliminary_verify(msg, avk, parameters)?;
72
73        Signature::verify_aggregate(msgp.as_slice(), &vks, &sigs)?;
74        Ok(())
75    }
76
77    /// Batch verify a set of signatures, with different messages and avks.
78    #[cfg(feature = "batch-verify-aggregates")]
79    pub fn batch_verify(
80        stm_signatures: &[Self],
81        msgs: &[Vec<u8>],
82        avks: &[StmAggrVerificationKey<D>],
83        parameters: &[StmParameters],
84    ) -> Result<(), StmAggregateSignatureError<D>> {
85        let batch_size = stm_signatures.len();
86        assert_eq!(
87            batch_size,
88            msgs.len(),
89            "Number of messages should correspond to size of the batch"
90        );
91        assert_eq!(
92            batch_size,
93            avks.len(),
94            "Number of avks should correspond to size of the batch"
95        );
96        assert_eq!(
97            batch_size,
98            parameters.len(),
99            "Number of parameters should correspond to size of the batch"
100        );
101
102        let mut aggr_sigs = Vec::with_capacity(batch_size);
103        let mut aggr_vks = Vec::with_capacity(batch_size);
104        for (idx, sig_group) in stm_signatures.iter().enumerate() {
105            sig_group.preliminary_verify(&msgs[idx], &avks[idx], &parameters[idx])?;
106            let grouped_sigs: Vec<Signature> = sig_group
107                .signatures
108                .iter()
109                .map(|sig_reg| sig_reg.sig.sigma)
110                .collect();
111            let grouped_vks: Vec<VerificationKey> = sig_group
112                .signatures
113                .iter()
114                .map(|sig_reg| sig_reg.reg_party.0)
115                .collect();
116
117            let (aggr_vk, aggr_sig) = Signature::aggregate(&grouped_vks, &grouped_sigs).unwrap();
118            aggr_sigs.push(aggr_sig);
119            aggr_vks.push(aggr_vk);
120        }
121
122        let concat_msgs: Vec<Vec<u8>> = msgs
123            .iter()
124            .zip(avks.iter())
125            .map(|(msg, avk)| avk.get_mt_commitment().concat_with_msg(msg))
126            .collect();
127
128        Signature::batch_verify_aggregates(&concat_msgs, &aggr_vks, &aggr_sigs)?;
129        Ok(())
130    }
131
132    /// Convert multi signature to bytes
133    /// # Layout
134    /// * Aggregate signature type (u8)
135    /// * Number of the pairs of Signatures and Registered Parties (SigRegParty) (as u64)
136    /// * Pairs of Signatures and Registered Parties (prefixed with their size as u64)
137    /// * Batch proof
138    pub fn to_bytes(&self) -> Vec<u8> {
139        let mut out = Vec::new();
140        // This proof type is not strictly necessary, but it will help to identify
141        // the type of the proof used to aggregate when implementing multiple aggregation proof systems.
142        // We use '0' for concatenation proof.
143        let proof_type: u8 = 0;
144        out.extend_from_slice(&proof_type.to_be_bytes());
145        out.extend_from_slice(&u64::try_from(self.signatures.len()).unwrap().to_be_bytes());
146        for sig_reg in &self.signatures {
147            out.extend_from_slice(
148                &u64::try_from(sig_reg.to_bytes().len())
149                    .unwrap()
150                    .to_be_bytes(),
151            );
152            out.extend_from_slice(&sig_reg.to_bytes());
153        }
154        let proof = &self.batch_proof;
155        out.extend_from_slice(&proof.to_bytes());
156
157        out
158    }
159
160    ///Extract a `StmAggrSig` from a byte slice.
161    pub fn from_bytes(bytes: &[u8]) -> Result<StmAggrSig<D>, StmAggregateSignatureError<D>> {
162        let mut u8_bytes = [0u8; 1];
163        let mut bytes_index = 0;
164
165        u8_bytes.copy_from_slice(
166            bytes
167                .get(..1)
168                .ok_or(StmAggregateSignatureError::SerializationError)?,
169        );
170        bytes_index += 1;
171        let proof_type = u8::from_be_bytes(u8_bytes);
172        if proof_type != 0 {
173            return Err(StmAggregateSignatureError::SerializationError);
174        }
175
176        let mut u64_bytes = [0u8; 8];
177        u64_bytes.copy_from_slice(
178            bytes
179                .get(bytes_index..bytes_index + 8)
180                .ok_or(StmAggregateSignatureError::SerializationError)?,
181        );
182        let total_sigs = usize::try_from(u64::from_be_bytes(u64_bytes))
183            .map_err(|_| StmAggregateSignatureError::SerializationError)?;
184        bytes_index += 8;
185
186        let mut sig_reg_list = Vec::with_capacity(total_sigs);
187        for _ in 0..total_sigs {
188            u64_bytes.copy_from_slice(
189                bytes
190                    .get(bytes_index..bytes_index + 8)
191                    .ok_or(StmAggregateSignatureError::SerializationError)?,
192            );
193            let sig_reg_size = usize::try_from(u64::from_be_bytes(u64_bytes))
194                .map_err(|_| StmAggregateSignatureError::SerializationError)?;
195            let sig_reg = StmSigRegParty::from_bytes::<D>(
196                bytes
197                    .get(bytes_index + 8..bytes_index + 8 + sig_reg_size)
198                    .ok_or(StmAggregateSignatureError::SerializationError)?,
199            )?;
200            bytes_index += 8 + sig_reg_size;
201            sig_reg_list.push(sig_reg);
202        }
203
204        let batch_proof = BatchPath::from_bytes(
205            bytes
206                .get(bytes_index..)
207                .ok_or(StmAggregateSignatureError::SerializationError)?,
208        )?;
209
210        Ok(StmAggrSig {
211            signatures: sig_reg_list,
212            batch_proof,
213        })
214    }
215}