mithril_stm/signature_scheme/bls_multi_signature/
signature.rs1use anyhow::{Context, anyhow};
2use blake2::{Blake2b, Blake2b512, Digest};
3use blst::{
4 blst_p1, blst_p2,
5 min_sig::{AggregateSignature, PublicKey as BlstVk, Signature as BlstSig},
6 p1_affines, p2_affines,
7};
8use digest::consts::U16;
9use std::{cmp::Ordering, iter::Sum};
10
11use super::{
12 BlsVerificationKey,
13 helper::unsafe_helpers::{p1_affine_to_sig, p2_affine_to_vk, sig_to_p1, vk_from_p2_affine},
14};
15use crate::{Index, MultiSignatureError, StmResult, blst_error_to_stm_error};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub struct BlsSignature(pub BlstSig);
20
21impl BlsSignature {
22 pub fn verify(&self, msg: &[u8], mvk: &BlsVerificationKey) -> StmResult<()> {
24 blst_error_to_stm_error(
25 self.0.validate(true).map_or_else(
26 |e| e,
27 |_| {
28 self.0
29 .verify(false, msg, &[], &[], &mvk.to_blst_verification_key(), false)
30 },
31 ),
32 Some(*self),
33 None,
34 )
35 }
36
37 pub(crate) fn evaluate_dense_mapping(&self, msg: &[u8], index: Index) -> [u8; 64] {
42 let hasher = Blake2b512::new()
43 .chain_update(b"map")
44 .chain_update(msg)
45 .chain_update(index.to_le_bytes())
46 .chain_update(self.to_bytes())
47 .finalize();
48
49 let mut output = [0u8; 64];
50 output.copy_from_slice(&hasher);
51
52 output
53 }
54
55 pub fn to_bytes(self) -> [u8; 48] {
57 self.0.to_bytes()
58 }
59
60 pub fn from_bytes(bytes: &[u8]) -> StmResult<Self> {
65 let bytes = bytes.get(..48).ok_or(MultiSignatureError::SerializationError)?;
66 match BlstSig::sig_validate(bytes, true) {
67 Ok(sig) => Ok(Self(sig)),
68 Err(e) => Err(blst_error_to_stm_error(e, None, None)
69 .expect_err("If deserialization is not successful, blst returns and error different to SUCCESS."))
70 }
71 }
72
73 fn compare_signatures(&self, other: &Self) -> Ordering {
76 let self_bytes = self.to_bytes();
77 let other_bytes = other.to_bytes();
78 let mut result = Ordering::Equal;
79
80 for (i, j) in self_bytes.iter().zip(other_bytes.iter()) {
81 result = i.cmp(j);
82 if result != Ordering::Equal {
83 return result;
84 }
85 }
86 result
87 }
88
89 pub fn aggregate(
94 vks: &[BlsVerificationKey],
95 sigs: &[BlsSignature],
96 ) -> StmResult<(BlsVerificationKey, BlsSignature)> {
97 if vks.len() != sigs.len() || vks.is_empty() {
98 return Err(anyhow!(MultiSignatureError::AggregateSignatureInvalid));
99 }
100
101 if vks.len() < 2 {
102 return Ok((vks[0], sigs[0]));
103 }
104
105 let mut hashed_sigs = Blake2b::<U16>::new();
106 for sig in sigs {
107 hashed_sigs.update(sig.to_bytes());
108 }
109
110 let mut scalars = Vec::with_capacity(vks.len() * 128);
112 let mut signatures = Vec::with_capacity(vks.len());
113 for (index, sig) in sigs.iter().enumerate() {
114 let mut hasher = hashed_sigs.clone();
115 hasher.update(index.to_be_bytes());
116 signatures.push(sig.0);
117 scalars.extend_from_slice(&hasher.finalize());
118 }
119
120 let transmuted_vks: Vec<blst_p2> = vks.iter().map(vk_from_p2_affine).collect();
121 let transmuted_sigs: Vec<blst_p1> = signatures.iter().map(sig_to_p1).collect();
122
123 let grouped_vks = p2_affines::from(transmuted_vks.as_slice());
124 let grouped_sigs = p1_affines::from(transmuted_sigs.as_slice());
125
126 let aggr_vk: BlstVk = p2_affine_to_vk(&grouped_vks.mult(&scalars, 128));
127 let aggr_sig: BlstSig = p1_affine_to_sig(&grouped_sigs.mult(&scalars, 128));
128
129 Ok((BlsVerificationKey(aggr_vk), BlsSignature(aggr_sig)))
130 }
131
132 pub fn verify_aggregate(
135 msg: &[u8],
136 vks: &[BlsVerificationKey],
137 sigs: &[BlsSignature],
138 ) -> StmResult<()> {
139 let (aggr_vk, aggr_sig) = Self::aggregate(vks, sigs).with_context(|| "Multi signature verification failed in aggregation of verification keys and signatures.")?;
140
141 blst_error_to_stm_error(
142 aggr_sig.0.verify(
143 false,
144 msg,
145 &[],
146 &[],
147 &aggr_vk.to_blst_verification_key(),
148 false,
149 ),
150 Some(aggr_sig),
151 None,
152 )
153 }
154
155 pub fn batch_verify_aggregates(
157 msgs: &[Vec<u8>],
158 vks: &[BlsVerificationKey],
159 sigs: &[BlsSignature],
160 ) -> StmResult<()> {
161 let batched_sig: BlstSig = match AggregateSignature::aggregate(
162 &(sigs.iter().map(|sig| &sig.0).collect::<Vec<&BlstSig>>()),
163 false,
164 ) {
165 Ok(sig) => BlstSig::from_aggregate(&sig),
166 Err(e) => return blst_error_to_stm_error(e, None, None),
167 };
168
169 let p2_vks: Vec<BlstVk> = vks.iter().map(|vk| vk.to_blst_verification_key()).collect();
170 let p2_vks_ref: Vec<&BlstVk> = p2_vks.iter().collect();
171 let slice_msgs = msgs.iter().map(|msg| msg.as_slice()).collect::<Vec<&[u8]>>();
172
173 blst_error_to_stm_error(
174 batched_sig.aggregate_verify(false, &slice_msgs, &[], &p2_vks_ref, false),
175 None,
176 None,
177 )
178 .map_err(|_| anyhow!(MultiSignatureError::BatchInvalid))
179 }
180}
181
182impl<'a> Sum<&'a Self> for BlsSignature {
183 fn sum<I>(iter: I) -> Self
184 where
185 I: Iterator<Item = &'a Self>,
186 {
187 let signatures: Vec<&BlstSig> = iter.map(|x| &x.0).collect();
188 assert!(!signatures.is_empty(), "One cannot add an empty vector");
189 let aggregate = AggregateSignature::aggregate(&signatures, false)
190 .expect("An MspSig is always a valid signature. This function only fails if signatures is empty or if the signatures are invalid, none of which can happen.")
191 .to_signature();
192
193 Self(aggregate)
194 }
195}
196
197impl PartialOrd for BlsSignature {
198 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
199 Some(std::cmp::Ord::cmp(self, other))
200 }
201}
202
203impl Ord for BlsSignature {
204 fn cmp(&self, other: &Self) -> Ordering {
205 self.compare_signatures(other)
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 mod golden {
212
213 use rand_chacha::ChaCha20Rng;
214 use rand_core::SeedableRng;
215
216 use crate::signature_scheme::{BlsSignature, BlsSigningKey};
217
218 const GOLDEN_JSON: &str = r#"[132,95,124,197,185,105,193,171,114,182,52,171,205,119,202,188,2,213,61,125,219,242,10,131,53,219,53,197,157,42,152,194,234,161,244,204,2,134,47,179,176,49,200,232,120,241,180,246]"#;
219
220 fn golden_value() -> BlsSignature {
221 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
222 let sk = BlsSigningKey::generate(&mut rng);
223 let msg = [0u8; 32];
224 sk.sign(&msg)
225 }
226
227 #[test]
228 fn golden_conversions() {
229 let value = serde_json::from_str(GOLDEN_JSON)
230 .expect("This JSON deserialization should not fail");
231 assert_eq!(golden_value(), value);
232
233 let serialized =
234 serde_json::to_string(&value).expect("This JSON serialization should not fail");
235 let golden_serialized = serde_json::to_string(&golden_value())
236 .expect("This JSON serialization should not fail");
237 assert_eq!(golden_serialized, serialized);
238 }
239 }
240}