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