mithril_stm/bls_multi_signature/
mod.rs

1//! BLST Multi-signature module
2
3pub(super) mod helper;
4mod proof_of_possession;
5mod signature;
6mod signing_key;
7mod verification_key;
8
9pub use proof_of_possession::*;
10pub use signature::*;
11pub use signing_key::*;
12pub use verification_key::*;
13
14use serde::{
15    de::Visitor,
16    {Deserialize, Deserializer, Serialize, Serializer},
17};
18
19/// String used to generate the proofs of possession.
20pub(crate) const POP: &[u8] = b"PoP";
21
22// ---------------------------------------------------------------------
23// Serde implementation
24// ---------------------------------------------------------------------
25
26macro_rules! impl_serde {
27    ($st:ty,$visitor:ident,$size:expr) => {
28        impl Serialize for $st {
29            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
30            where
31                S: Serializer,
32            {
33                use serde::ser::SerializeTuple;
34                let mut seq = serializer.serialize_tuple($size)?;
35                for e in self.to_bytes().iter() {
36                    seq.serialize_element(e)?;
37                }
38                seq.end()
39            }
40        }
41
42        impl<'de> Deserialize<'de> for $st {
43            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
44            where
45                D: Deserializer<'de>,
46            {
47                struct $visitor;
48
49                impl<'de> Visitor<'de> for $visitor {
50                    type Value = $st;
51
52                    fn expecting(
53                        &self,
54                        formatter: &mut ::core::fmt::Formatter,
55                    ) -> ::core::fmt::Result {
56                        formatter
57                            .write_str(format!("a multi signature {}", stringify!($st)).as_str())
58                    }
59
60                    fn visit_seq<A>(self, mut seq: A) -> Result<$st, A::Error>
61                    where
62                        A: serde::de::SeqAccess<'de>,
63                    {
64                        let mut bytes = [0u8; $size];
65                        for i in 0..$size {
66                            bytes[i] =
67                                seq.next_element()?.ok_or(serde::de::Error::invalid_length(
68                                    i,
69                                    &format!("expected bytes{}", $size.to_string()).as_str(),
70                                ))?;
71                        }
72                        <$st>::from_bytes(&bytes).map_err(|_| {
73                            serde::de::Error::custom(
74                                &format!("deserialization failed [{}]", stringify!($st)).as_str(),
75                            )
76                        })
77                    }
78                }
79
80                deserializer.deserialize_tuple($size, $visitor)
81            }
82        }
83    };
84}
85impl_serde!(SigningKey, SigningKeyVisitor, 32);
86impl_serde!(VerificationKey, VerificationKeyVisitor, 96);
87impl_serde!(ProofOfPossession, ProofOfPossessionVisitor, 96);
88impl_serde!(Signature, SignatureVisitor, 48);
89
90#[cfg(test)]
91mod tests {
92    use blst::{blst_p1, blst_p2};
93    use proptest::prelude::*;
94    use rand_chacha::ChaCha20Rng;
95    use rand_core::SeedableRng;
96
97    use crate::bls_multi_signature::helper::unsafe_helpers::{p1_affine_to_sig, p2_affine_to_vk};
98    use crate::error::{MultiSignatureError, RegisterError};
99    use crate::key_reg::KeyReg;
100
101    use super::*;
102
103    impl PartialEq for SigningKey {
104        fn eq(&self, other: &Self) -> bool {
105            self.to_blst_sk().to_bytes() == other.to_blst_sk().to_bytes()
106        }
107    }
108
109    impl Eq for SigningKey {}
110
111    proptest! {
112        #![proptest_config(ProptestConfig::with_cases(1000))]
113
114        #[test]
115        fn test_sig(
116            msg in prop::collection::vec(any::<u8>(), 1..128),
117            seed in any::<[u8;32]>(),
118        ) {
119            let sk = SigningKey::gen(&mut ChaCha20Rng::from_seed(seed));
120            let vk = VerificationKey::from(&sk);
121            let sig = sk.sign(&msg);
122
123            sig.verify(&msg, &vk).unwrap();
124        }
125
126        #[test]
127        fn test_invalid_sig(msg in prop::collection::vec(any::<u8>(), 1..128), seed in any::<[u8;32]>()) {
128            let mut rng = ChaCha20Rng::from_seed(seed);
129            let sk1 = SigningKey::gen(&mut rng);
130            let vk1 = VerificationKey::from(&sk1);
131            let sk2 = SigningKey::gen(&mut rng);
132            let fake_sig = sk2.sign(&msg);
133
134            let result = fake_sig.verify(&msg, &vk1);
135            assert_eq!(result, Err(MultiSignatureError::SignatureInvalid(fake_sig)));
136        }
137
138        #[test]
139        fn test_infinity_sig(msg in prop::collection::vec(any::<u8>(), 1..128), seed in any::<[u8;32]>()) {
140            let mut rng = ChaCha20Rng::from_seed(seed);
141            let sk = SigningKey::gen(&mut rng);
142            let vk = VerificationKey::from(&sk);
143
144            let p1 = blst_p1::default();
145            let sig_infinity = Signature(p1_affine_to_sig(&p1));
146
147            let result = sig_infinity.verify(&msg, &vk);
148            assert_eq!(result, Err(MultiSignatureError::SignatureInfinity(sig_infinity)));
149        }
150
151        #[test]
152        fn test_infinity_vk(seed in any::<[u8;32]>()) {
153            let mut rng = ChaCha20Rng::from_seed(seed);
154            let sk = SigningKey::gen(&mut rng);
155            let pop = ProofOfPossession::from(&sk);
156
157            let p2 = blst_p2::default();
158            let vk_infinity = VerificationKey(p2_affine_to_vk(&p2));
159            let vkpop_infinity = VerificationKeyPoP { vk: vk_infinity, pop };
160
161            let result = vkpop_infinity.check();
162            assert_eq!(result, Err(MultiSignatureError::VerificationKeyInfinity(Box::new(vkpop_infinity.vk))));
163        }
164
165        #[test]
166        fn test_keyreg_with_infinity_vk(num_sigs in 2..16usize, seed in any::<[u8;32]>()) {
167            let mut rng = ChaCha20Rng::from_seed(seed);
168            let mut kr = KeyReg::init();
169
170            let sk = SigningKey::gen(&mut rng);
171            let pop = ProofOfPossession::from(&sk);
172            let p2 = blst_p2::default();
173            let vk_infinity = VerificationKey(p2_affine_to_vk(&p2));
174            let vkpop_infinity = VerificationKeyPoP { vk: vk_infinity, pop };
175
176            for _ in 0..num_sigs {
177                let sk = SigningKey::gen(&mut rng);
178                let vkpop = VerificationKeyPoP::from(&sk);
179                let _ = kr.register(1, vkpop);
180            }
181
182            let result = kr.register(1, vkpop_infinity);
183            assert_eq!(result, Err(RegisterError::VerificationKeyInfinity(Box::new(vkpop_infinity.vk))));
184        }
185
186        #[test]
187        fn test_aggregate_sig(msg in prop::collection::vec(any::<u8>(), 1..128),
188                              num_sigs in 2..16,
189                              seed in any::<[u8;32]>(),
190        ) {
191            let mut rng = ChaCha20Rng::from_seed(seed);
192            let mut mvks = Vec::new();
193            let mut sigs = Vec::new();
194            for _ in 0..num_sigs {
195                let sk = SigningKey::gen(&mut rng);
196                let vk = VerificationKey::from(&sk);
197                let sig = sk.sign(&msg);
198                assert!(sig.verify(&msg, &vk).is_ok());
199                sigs.push(sig);
200                mvks.push(vk);
201            }
202
203            let result = Signature::verify_aggregate(&msg, &mvks, &sigs);
204            assert!(result.is_ok(), "Aggregate verification failed {result:?}");
205        }
206
207        #[test]
208        fn test_eval_sanity_check(msg in prop::collection::vec(any::<u8>(), 1..128),
209                                  idx in any::<u64>(),
210                                  seed in any::<[u8;32]>()) {
211            let sk = SigningKey::gen(&mut ChaCha20Rng::from_seed(seed));
212            let sig = sk.sign(&msg);
213            sig.eval(&msg, idx);
214        }
215
216        #[test]
217        fn serialize_deserialize_vk(seed in any::<u64>()) {
218            let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed);
219            let sk = SigningKey::gen(&mut rng);
220            let vk = VerificationKey::from(&sk);
221            let vk_bytes = vk.to_bytes();
222            let vk2 = VerificationKey::from_bytes(&vk_bytes).unwrap();
223            assert_eq!(vk, vk2);
224            let vkpop = VerificationKeyPoP::from(&sk);
225            let vkpop_bytes = vkpop.to_bytes();
226            let vkpop2: VerificationKeyPoP = VerificationKeyPoP::from_bytes(&vkpop_bytes).unwrap();
227            assert_eq!(vkpop, vkpop2);
228
229            // Now we test serde
230            let encoded = bincode::serde::encode_to_vec(vk, bincode::config::legacy()).unwrap();
231            assert_eq!(encoded, vk_bytes);
232            let (decoded,_) = bincode::serde::decode_from_slice::<VerificationKey,_>(&encoded, bincode::config::legacy()).unwrap();
233            assert_eq!(vk, decoded);
234            let encoded = bincode::serde::encode_to_vec(vkpop, bincode::config::legacy()).unwrap();
235            let (decoded,_) = bincode::serde::decode_from_slice::<VerificationKeyPoP,_>(&encoded, bincode::config::legacy()).unwrap();
236            assert_eq!(vkpop, decoded);
237        }
238
239        #[test]
240        fn serialize_deserialize_sk(seed in any::<u64>()) {
241            let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed);
242            let sk = SigningKey::gen(&mut rng);
243            let sk_bytes: [u8; 32] = sk.to_bytes();
244            let sk2 = SigningKey::from_bytes(&sk_bytes).unwrap();
245            assert_eq!(sk, sk2);
246
247            // Now we test serde
248            let encoded = bincode::serde::encode_to_vec(&sk, bincode::config::legacy()).unwrap();
249            let (decoded,_) = bincode::serde::decode_from_slice::<SigningKey,_>(&encoded, bincode::config::legacy()).unwrap();
250            assert_eq!(sk, decoded);
251
252            // See that it is consistent with raw serialisation
253            let (decoded_bytes,_) = bincode::serde::decode_from_slice::<SigningKey,_>(&sk_bytes, bincode::config::legacy()).unwrap();
254            assert_eq!(sk, decoded_bytes);
255        }
256
257        #[test]
258        fn batch_verify(num_batches in 2..10usize,
259                              seed in any::<[u8;32]>(),
260        ) {
261            let mut rng = ChaCha20Rng::from_seed(seed);
262            let num_sigs = 10;
263            let mut batch_msgs = Vec::new();
264            let mut batch_vk = Vec::new();
265            let mut batch_sig = Vec::new();
266            for _ in 0..num_batches {
267                let mut msg = [0u8; 32];
268                rng.fill_bytes(&mut msg);
269                let mut mvks = Vec::new();
270                let mut sigs = Vec::new();
271                for _ in 0..num_sigs {
272                    let sk = SigningKey::gen(&mut rng);
273                    let vk = VerificationKey::from(&sk);
274                    let sig = sk.sign(&msg);
275                    sigs.push(sig);
276                    mvks.push(vk);
277                }
278                assert!(Signature::verify_aggregate(&msg, &mvks, &sigs).is_ok());
279                let (agg_vk, agg_sig) = Signature::aggregate(&mvks, &sigs).unwrap();
280                batch_msgs.push(msg.to_vec());
281                batch_vk.push(agg_vk);
282                batch_sig.push(agg_sig);
283            }
284            assert!(Signature::batch_verify_aggregates(&batch_msgs, &batch_vk, &batch_sig).is_ok());
285
286            // If we have an invalid signature, the batch verification will fail
287            let mut msg = [0u8; 32];
288            rng.fill_bytes(&mut msg);
289            let sk = SigningKey::gen(&mut rng);
290            let fake_sig = sk.sign(&msg);
291            batch_sig[0] = fake_sig;
292
293            let batch_result = Signature::batch_verify_aggregates(&batch_msgs, &batch_vk, &batch_sig);
294            assert_eq!(batch_result, Err(MultiSignatureError::BatchInvalid));
295        }
296    }
297}