mithril_stm/signature_scheme/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!(BlsSigningKey, SigningKeyVisitor, 32);
86impl_serde!(BlsVerificationKey, VerificationKeyVisitor, 96);
87impl_serde!(BlsProofOfPossession, ProofOfPossessionVisitor, 96);
88impl_serde!(BlsSignature, 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::{RngCore, SeedableRng};
96
97    use super::helper::unsafe_helpers::{p1_affine_to_sig, p2_affine_to_vk};
98    use crate::{KeyRegistration, MultiSignatureError, RegisterError};
99
100    use super::*;
101
102    impl PartialEq for BlsSigningKey {
103        fn eq(&self, other: &Self) -> bool {
104            self.to_blst_secret_key().to_bytes() == other.to_blst_secret_key().to_bytes()
105        }
106    }
107
108    impl Eq for BlsSigningKey {}
109
110    proptest! {
111        #![proptest_config(ProptestConfig::with_cases(1000))]
112
113        #[test]
114        fn test_sig(
115            msg in prop::collection::vec(any::<u8>(), 1..128),
116            seed in any::<[u8;32]>(),
117        ) {
118            let sk = BlsSigningKey::generate(&mut ChaCha20Rng::from_seed(seed));
119            let vk = BlsVerificationKey::from(&sk);
120            let sig = sk.sign(&msg);
121
122            sig.verify(&msg, &vk).unwrap();
123        }
124
125        #[test]
126        fn test_invalid_sig(msg in prop::collection::vec(any::<u8>(), 1..128), seed in any::<[u8;32]>()) {
127            let mut rng = ChaCha20Rng::from_seed(seed);
128            let sk1 = BlsSigningKey::generate(&mut rng);
129            let vk1 = BlsVerificationKey::from(&sk1);
130            let sk2 = BlsSigningKey::generate(&mut rng);
131            let fake_sig = sk2.sign(&msg);
132
133            let error = fake_sig.verify(&msg, &vk1).expect_err("Fake signature should not be verified");
134
135            assert!(
136                matches!(
137                    error.downcast_ref::<MultiSignatureError>(),
138                    Some(MultiSignatureError::SignatureInvalid(_))
139                ),
140                "Unexpected error: {error:?}");
141        }
142
143        #[test]
144        fn test_infinity_sig(msg in prop::collection::vec(any::<u8>(), 1..128), seed in any::<[u8;32]>()) {
145            let mut rng = ChaCha20Rng::from_seed(seed);
146            let sk = BlsSigningKey::generate(&mut rng);
147            let vk = BlsVerificationKey::from(&sk);
148
149            let p1 = blst_p1::default();
150            let sig_infinity = BlsSignature(p1_affine_to_sig(&p1));
151
152            let error = sig_infinity.verify(&msg, &vk).expect_err("Verification should fail");
153            assert!(
154                matches!(
155                    error.downcast_ref::<MultiSignatureError>(),
156                    Some(MultiSignatureError::SignatureInfinity(_))
157                ),
158                "Unexpected error: {error:?}");
159        }
160
161        #[test]
162        fn test_infinity_vk(seed in any::<[u8;32]>()) {
163            let mut rng = ChaCha20Rng::from_seed(seed);
164            let sk = BlsSigningKey::generate(&mut rng);
165            let pop = BlsProofOfPossession::from(&sk);
166
167            let p2 = blst_p2::default();
168            let vk_infinity = BlsVerificationKey(p2_affine_to_vk(&p2));
169            let vkpop_infinity = BlsVerificationKeyProofOfPossession { vk: vk_infinity, pop };
170
171            let error = vkpop_infinity.verify_proof_of_possession().expect_err("VK pop infinity should fail");
172            assert!(
173                matches!(
174                    error.downcast_ref::<MultiSignatureError>(),
175                    Some(MultiSignatureError::VerificationKeyInfinity(_))
176                ),
177                "Unexpected error: {error:?}");
178        }
179
180        #[test]
181        fn test_keyreg_with_infinity_vk(num_sigs in 2..16usize, seed in any::<[u8;32]>()) {
182            let mut rng = ChaCha20Rng::from_seed(seed);
183            let mut kr = KeyRegistration::init();
184
185            let sk = BlsSigningKey::generate(&mut rng);
186            let pop = BlsProofOfPossession::from(&sk);
187            let p2 = blst_p2::default();
188            let vk_infinity = BlsVerificationKey(p2_affine_to_vk(&p2));
189            let vkpop_infinity = BlsVerificationKeyProofOfPossession { vk: vk_infinity, pop };
190
191            for _ in 0..num_sigs {
192                let sk = BlsSigningKey::generate(&mut rng);
193                let vkpop = BlsVerificationKeyProofOfPossession::from(&sk);
194                let _ = kr.register(1, vkpop);
195            }
196
197            let error = kr.register(1, vkpop_infinity).expect_err("VK pop infinity should not be registered");
198
199            assert!(
200                matches!(
201                    error.downcast_ref::<RegisterError>(),
202                    Some(RegisterError::KeyInvalid(_))
203                ),
204                "Unexpected error: {error:?}");
205        }
206
207        #[test]
208        fn test_aggregate_sig(msg in prop::collection::vec(any::<u8>(), 1..128),
209                              num_sigs in 2..16,
210                              seed in any::<[u8;32]>(),
211        ) {
212            let mut rng = ChaCha20Rng::from_seed(seed);
213            let mut mvks = Vec::new();
214            let mut sigs = Vec::new();
215            for _ in 0..num_sigs {
216                let sk = BlsSigningKey::generate(&mut rng);
217                let vk = BlsVerificationKey::from(&sk);
218                let sig = sk.sign(&msg);
219                assert!(sig.verify(&msg, &vk).is_ok());
220                sigs.push(sig);
221                mvks.push(vk);
222            }
223
224            let result = BlsSignature::verify_aggregate(&msg, &mvks, &sigs);
225            assert!(result.is_ok(), "Aggregate verification failed {result:?}");
226        }
227
228        #[test]
229        fn test_eval_sanity_check(msg in prop::collection::vec(any::<u8>(), 1..128),
230                                  idx in any::<u64>(),
231                                  seed in any::<[u8;32]>()) {
232            let sk = BlsSigningKey::generate(&mut ChaCha20Rng::from_seed(seed));
233            let sig = sk.sign(&msg);
234            sig.evaluate_dense_mapping(&msg, idx);
235        }
236
237        #[test]
238        fn serialize_deserialize_vk(seed in any::<u64>()) {
239            let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed);
240            let sk = BlsSigningKey::generate(&mut rng);
241            let vk = BlsVerificationKey::from(&sk);
242            let vk_bytes = vk.to_bytes();
243            let vk2 = BlsVerificationKey::from_bytes(&vk_bytes).unwrap();
244            assert_eq!(vk, vk2);
245            let vkpop = BlsVerificationKeyProofOfPossession::from(&sk);
246            let vkpop_bytes = vkpop.to_bytes();
247            let vkpop2: BlsVerificationKeyProofOfPossession = BlsVerificationKeyProofOfPossession::from_bytes(&vkpop_bytes).unwrap();
248            assert_eq!(vkpop, vkpop2);
249        }
250
251        #[test]
252        fn serialize_deserialize_sk(seed in any::<u64>()) {
253            let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed);
254            let sk = BlsSigningKey::generate(&mut rng);
255            let sk_bytes: [u8; 32] = sk.to_bytes();
256            let sk2 = BlsSigningKey::from_bytes(&sk_bytes).unwrap();
257            assert_eq!(sk, sk2);
258        }
259
260        #[test]
261        fn batch_verify(num_batches in 2..10usize,
262                              seed in any::<[u8;32]>(),
263        ) {
264            let mut rng = ChaCha20Rng::from_seed(seed);
265            let num_sigs = 10;
266            let mut batch_msgs = Vec::new();
267            let mut batch_vk = Vec::new();
268            let mut batch_sig = Vec::new();
269            for _ in 0..num_batches {
270                let mut msg = [0u8; 32];
271                rng.fill_bytes(&mut msg);
272                let mut mvks = Vec::new();
273                let mut sigs = Vec::new();
274                for _ in 0..num_sigs {
275                    let sk = BlsSigningKey::generate(&mut rng);
276                    let vk = BlsVerificationKey::from(&sk);
277                    let sig = sk.sign(&msg);
278                    sigs.push(sig);
279                    mvks.push(vk);
280                }
281                assert!(BlsSignature::verify_aggregate(&msg, &mvks, &sigs).is_ok());
282                let (agg_vk, agg_sig) = BlsSignature::aggregate(&mvks, &sigs).unwrap();
283                batch_msgs.push(msg.to_vec());
284                batch_vk.push(agg_vk);
285                batch_sig.push(agg_sig);
286            }
287            assert!(BlsSignature::batch_verify_aggregates(&batch_msgs, &batch_vk, &batch_sig).is_ok());
288
289            // If we have an invalid signature, the batch verification will fail
290            let mut msg = [0u8; 32];
291            rng.fill_bytes(&mut msg);
292            let sk = BlsSigningKey::generate(&mut rng);
293            let fake_sig = sk.sign(&msg);
294            batch_sig[0] = fake_sig;
295
296            let error = BlsSignature::batch_verify_aggregates(&batch_msgs, &batch_vk, &batch_sig).expect_err("Batch verify should fail");
297            assert!(
298                matches!(
299                    error.downcast_ref::<MultiSignatureError>(),
300                    Some(MultiSignatureError::BatchInvalid)
301                ),
302                "Unexpected error: {error:?}");
303        }
304    }
305}