mithril_stm/signature_scheme/bls_multi_signature/
mod.rs

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