commonware_cryptography/bls12381/primitives/
ops.rs

1//! Digital signatures over the BLS12-381 curve using G1 as the Public Key (48 bytes)
2//! and G2 as the Signature (96 bytes).
3//!
4//! # Domain Separation Tag (DST)
5//!
6//! All signatures use the `POP` (Proof of Possession) scheme during signing. For Proof-of-Possession (POP) signatures,
7//! the domain separation tag is `BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_`. For signatures over other messages, the
8//! domain separation tag is `BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_`. You can read more about DSTs [here](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-05#section-4.2).
9
10use super::{
11    group::{self, equal, Element, Point, Share, DST, MESSAGE, PROOF_OF_POSSESSION},
12    poly::{self, Eval, PartialSignature},
13    Error,
14};
15use commonware_utils::union_unique;
16use rand::RngCore;
17use rayon::{prelude::*, ThreadPoolBuilder};
18use std::borrow::Cow;
19
20/// Returns a new keypair derived from the provided randomness.
21pub fn keypair<R: RngCore>(rng: &mut R) -> (group::Private, group::Public) {
22    let private = group::Private::rand(rng);
23    let mut public = group::Public::one();
24    public.mul(&private);
25    (private, public)
26}
27
28/// Sign the provided payload with the private key.
29pub fn sign(private: &group::Private, dst: DST, payload: &[u8]) -> group::Signature {
30    let mut s = group::Signature::zero();
31    s.map(dst, payload);
32    s.mul(private);
33    s
34}
35
36/// Verify the signature from the provided public key.
37pub fn verify(
38    public: &group::Public,
39    dst: DST,
40    payload: &[u8],
41    signature: &group::Signature,
42) -> Result<(), Error> {
43    let mut hm = group::Signature::zero();
44    hm.map(dst, payload);
45    if !equal(public, signature, &hm) {
46        return Err(Error::InvalidSignature);
47    }
48    Ok(())
49}
50
51/// Generates a proof of possession for the private key.
52pub fn sign_proof_of_possession(private: &group::Private) -> group::Signature {
53    // Get public key
54    let mut public = group::Public::one();
55    public.mul(private);
56
57    // Sign the public key
58    sign(private, PROOF_OF_POSSESSION, public.serialize().as_slice())
59}
60
61/// Verifies a proof of possession for the provided public key.
62pub fn verify_proof_of_possession(
63    public: &group::Public,
64    signature: &group::Signature,
65) -> Result<(), Error> {
66    verify(
67        public,
68        PROOF_OF_POSSESSION,
69        public.serialize().as_slice(),
70        signature,
71    )
72}
73
74/// Signs the provided message with the private key.
75///
76/// # Determinism
77///
78/// Signatures produced by this function are deterministic and are safe
79/// to use in a consensus-critical context.
80pub fn sign_message(
81    private: &group::Private,
82    namespace: Option<&[u8]>,
83    message: &[u8],
84) -> group::Signature {
85    let payload = match namespace {
86        Some(namespace) => Cow::Owned(union_unique(namespace, message)),
87        None => Cow::Borrowed(message),
88    };
89    sign(private, MESSAGE, &payload)
90}
91
92/// Verifies the signature with the provided public key.
93///
94/// # Warning
95///
96/// This function assumes a group check was already performed on
97/// `public` and `signature`.
98pub fn verify_message(
99    public: &group::Public,
100    namespace: Option<&[u8]>,
101    message: &[u8],
102    signature: &group::Signature,
103) -> Result<(), Error> {
104    let payload = match namespace {
105        Some(namespace) => Cow::Owned(union_unique(namespace, message)),
106        None => Cow::Borrowed(message),
107    };
108    verify(public, MESSAGE, &payload, signature)
109}
110
111/// Generates a proof of possession for the private key share.
112pub fn partial_sign_proof_of_possession(
113    public: &poly::Public,
114    private: &Share,
115) -> PartialSignature {
116    // Get public key
117    let threshold_public = poly::public(public);
118
119    // Sign the public key
120    let sig = sign(
121        &private.private,
122        PROOF_OF_POSSESSION,
123        threshold_public.serialize().as_slice(),
124    );
125    Eval {
126        value: sig,
127        index: private.index,
128    }
129}
130
131/// Verifies the proof of possession for the provided public polynomial.
132///
133/// # Warning
134///
135/// This function assumes a group check was already performed on `signature`.
136pub fn partial_verify_proof_of_possession(
137    public: &poly::Public,
138    partial: &PartialSignature,
139) -> Result<(), Error> {
140    let threshold_public = poly::public(public);
141    let public = public.evaluate(partial.index);
142    verify(
143        &public.value,
144        PROOF_OF_POSSESSION,
145        threshold_public.serialize().as_slice(),
146        &partial.value,
147    )
148}
149
150/// Signs the provided message with the key share.
151pub fn partial_sign_message(
152    private: &Share,
153    namespace: Option<&[u8]>,
154    message: &[u8],
155) -> PartialSignature {
156    let sig = sign_message(&private.private, namespace, message);
157    Eval {
158        value: sig,
159        index: private.index,
160    }
161}
162
163/// Verifies the partial signature against the public polynomial.
164///
165/// # Warning
166///
167/// This function assumes a group check was already performed on `signature`.
168pub fn partial_verify_message(
169    public: &poly::Public,
170    namespace: Option<&[u8]>,
171    message: &[u8],
172    partial: &PartialSignature,
173) -> Result<(), Error> {
174    let public = public.evaluate(partial.index);
175    verify_message(&public.value, namespace, message, &partial.value)
176}
177
178/// Recovers a signature from at least `threshold` partial signatures.
179///
180/// # Determinism
181///
182/// Signatures recovered by this function are deterministic and are safe
183/// to use in a consensus-critical context.
184pub fn threshold_signature_recover(
185    threshold: u32,
186    partials: Vec<PartialSignature>,
187) -> Result<group::Signature, Error> {
188    let sigs = partials.len() as u32;
189    if threshold > sigs {
190        return Err(Error::NotEnoughPartialSignatures(threshold, sigs));
191    }
192    poly::Signature::recover(threshold, partials)
193}
194
195/// Aggregates multiple public keys.
196///
197/// # Warning
198///
199/// This function assumes a group check was already performed on all `public_keys`,
200/// that each `public_key` is unique, and that the caller has a Proof-of-Possession (PoP)
201/// for each `public_key`. If any of these assumptions are violated, an attacker can
202/// exploit this function to verify an incorrect aggregate signature.
203pub fn aggregate_public_keys(public_keys: &[group::Public]) -> group::Public {
204    let mut p = group::Public::zero();
205    for pk in public_keys {
206        p.add(pk);
207    }
208    p
209}
210
211/// Aggregates multiple signatures.
212///
213/// # Warning
214///
215/// This function assumes a group check was already performed on each `signature` and
216/// that each `signature` is unique. If any of these assumptions are violated, an attacker can
217/// exploit this function to verify an incorrect aggregate signature.
218pub fn aggregate_signatures(signatures: &[group::Signature]) -> group::Signature {
219    let mut s = group::Signature::zero();
220    for sig in signatures {
221        s.add(sig);
222    }
223    s
224}
225
226/// Verifies the aggregate signature over a single message from multiple public keys.
227///
228/// # Warning
229///
230/// This function assumes the caller has performed a group check and collected a proof-of-possession
231/// for all provided `public`. This function assumes a group check was already performed on the
232/// `signature`. It is not safe to provide duplicate public keys.
233pub fn aggregate_verify_multiple_public_keys(
234    public: &[group::Public],
235    namespace: Option<&[u8]>,
236    message: &[u8],
237    signature: &group::Signature,
238) -> Result<(), Error> {
239    // Aggregate public keys
240    //
241    // We can take advantage of the bilinearity property of pairings to aggregate public keys
242    // that have all signed the same message (as long as all public keys are unique).
243    let agg_public = aggregate_public_keys(public);
244
245    // Verify the signature
246    verify_message(&agg_public, namespace, message, signature)
247}
248
249/// Verifies the aggregate signature over multiple unique messages from a single public key.
250///
251/// # Warning
252///
253/// This function assumes a group check was already performed on `public` and `signature`. It is not
254/// safe to provide an aggregate public key or to provide duplicate messages.
255///
256/// ## Why not aggregate public keys?
257///
258/// We rely on bilinearity to reduce pairing operations in this function, like in `aggregate_verify_multiple_public_keys`,
259/// and sum hashed messages together before performing a single pairing operation (instead of summing `len(messages)` pairings of
260/// hashed message and public key). If the public key itself is an aggregate of multiple public keys, an attacker can exploit
261/// this optimization to cause this function to return that an aggregate signature is valid when it really isn't.
262pub fn aggregate_verify_multiple_messages(
263    public: &group::Public,
264    namespace: Option<&[u8]>,
265    messages: &[&[u8]],
266    signature: &group::Signature,
267    concurrency: usize,
268) -> Result<(), Error> {
269    // Build a thread pool with the specified concurrency
270    let pool = ThreadPoolBuilder::new()
271        .num_threads(concurrency)
272        .build()
273        .expect("Unable to build thread pool");
274
275    // Perform hashing to curve and summation of messages in parallel
276    let hm_sum = pool.install(|| {
277        messages
278            .par_iter()
279            .map(|msg| {
280                let mut hm = group::Signature::zero();
281                match namespace {
282                    Some(namespace) => hm.map(MESSAGE, &union_unique(namespace, msg)),
283                    None => hm.map(MESSAGE, msg),
284                };
285                hm
286            })
287            .reduce(group::Signature::zero, |mut sum, hm| {
288                sum.add(&hm);
289                sum
290            })
291    });
292
293    // Verify the signature
294    if !equal(public, signature, &hm_sum) {
295        return Err(Error::InvalidSignature);
296    }
297    Ok(())
298}
299
300#[cfg(test)]
301mod tests {
302    use super::*;
303    use crate::bls12381::dkg::ops::generate_shares;
304    use blst::BLST_ERROR;
305    use group::{G1, G1_MESSAGE, G1_PROOF_OF_POSSESSION};
306    use rand::prelude::*;
307
308    #[test]
309    fn test_encoding() {
310        // Encode private/public key
311        let (private, public) = keypair(&mut thread_rng());
312        let (private_bytes, public_bytes) = (private.serialize(), public.serialize());
313
314        // Decode private/public key
315        let (private_decoded, public_decoded) = (
316            group::Private::deserialize(&private_bytes).unwrap(),
317            group::Public::deserialize(&public_bytes).unwrap(),
318        );
319
320        // Ensure equal
321        assert_eq!(private, private_decoded);
322        assert_eq!(public, public_decoded);
323
324        // Ensure blst compatibility
325        blst::min_pk::SecretKey::from_bytes(private_bytes.as_slice()).unwrap();
326        let blst_public_decoded =
327            blst::min_pk::PublicKey::from_bytes(public_bytes.as_slice()).unwrap();
328        blst_public_decoded.validate().unwrap();
329        let blst_public_encoded = blst_public_decoded.compress().to_vec();
330        assert_eq!(public_bytes, blst_public_encoded.as_slice());
331    }
332
333    /// Verify that a given proof-of-possession signature is valid according to `blst`.
334    fn blst_verify_proof_of_possession(
335        public: &group::Public,
336        signature: &group::Signature,
337    ) -> Result<(), BLST_ERROR> {
338        let msg = public.serialize();
339        let public = blst::min_pk::PublicKey::from_bytes(public.serialize().as_slice()).unwrap();
340        let signature =
341            blst::min_pk::Signature::from_bytes(signature.serialize().as_slice()).unwrap();
342        match signature.verify(true, &msg, PROOF_OF_POSSESSION, &[], &public, true) {
343            BLST_ERROR::BLST_SUCCESS => Ok(()),
344            e => Err(e),
345        }
346    }
347
348    #[test]
349    fn test_single_proof_of_possession() {
350        // Generate PoP
351        let (private, public) = keypair(&mut thread_rng());
352        let pop = sign_proof_of_possession(&private);
353
354        // Verify PoP
355        verify_proof_of_possession(&public, &pop).expect("PoP should be valid");
356
357        // Verify PoP using blst
358        blst_verify_proof_of_possession(&public, &pop).expect("PoP should be valid");
359    }
360
361    #[test]
362    fn test_threshold_proof_of_possession() {
363        // Generate PoP
364        let (n, t) = (5, 4);
365        let mut rng = StdRng::seed_from_u64(0);
366        let (public, shares) = generate_shares(&mut rng, None, n, t);
367        let partials: Vec<_> = shares
368            .iter()
369            .map(|s| partial_sign_proof_of_possession(&public, s))
370            .collect();
371        for p in &partials {
372            partial_verify_proof_of_possession(&public, p).expect("signature should be valid");
373        }
374        let threshold_sig = threshold_signature_recover(t, partials).unwrap();
375        let threshold_pub = poly::public(&public);
376
377        // Verify PoP
378        verify_proof_of_possession(&threshold_pub, &threshold_sig)
379            .expect("signature should be valid");
380
381        // Verify PoP using blst
382        blst_verify_proof_of_possession(&threshold_pub, &threshold_sig)
383            .expect("signature should be valid");
384    }
385
386    #[test]
387    fn test_single_proof_of_possession_min_sig() {
388        // Generate keypair
389        let private = group::Private::rand(&mut thread_rng());
390        let mut public = group::G2::one();
391        public.mul(&private);
392        let public_compressed = public.serialize();
393
394        // Generate PoP
395        let mut pop = G1::zero();
396        pop.map(G1_PROOF_OF_POSSESSION, &public_compressed);
397        pop.mul(&private);
398
399        // Verify PoP using blst
400        let public = blst::min_sig::PublicKey::from_bytes(&public_compressed).unwrap();
401        let signature = blst::min_sig::Signature::from_bytes(pop.serialize().as_slice()).unwrap();
402        let result = match signature.verify(
403            true,
404            &public_compressed,
405            G1_PROOF_OF_POSSESSION,
406            &[],
407            &public,
408            true,
409        ) {
410            BLST_ERROR::BLST_SUCCESS => Ok(()),
411            e => Err(e),
412        };
413        result.expect("signature should be valid");
414    }
415
416    /// Verify that a given message signature is valid according to `blst`.
417    fn blst_verify_message(
418        public: &group::Public,
419        msg: &[u8],
420        signature: &group::Signature,
421    ) -> Result<(), BLST_ERROR> {
422        let public = blst::min_pk::PublicKey::from_bytes(public.serialize().as_slice()).unwrap();
423        let signature =
424            blst::min_pk::Signature::from_bytes(signature.serialize().as_slice()).unwrap();
425        match signature.verify(true, msg, MESSAGE, &[], &public, true) {
426            BLST_ERROR::BLST_SUCCESS => Ok(()),
427            e => Err(e),
428        }
429    }
430
431    #[test]
432    fn test_bad_namespace() {
433        let (private, public) = keypair(&mut thread_rng());
434        let msg = &[1, 9, 6, 9];
435        let sig = sign_message(&private, Some(b"good"), msg);
436        assert!(matches!(
437            verify_message(&public, Some(b"bad"), msg, &sig).unwrap_err(),
438            Error::InvalidSignature
439        ));
440    }
441
442    #[test]
443    fn test_single_message() {
444        let (private, public) = keypair(&mut thread_rng());
445        let msg = &[1, 9, 6, 9];
446        let namespace = b"test";
447        let sig = sign_message(&private, Some(namespace), msg);
448        verify_message(&public, Some(namespace), msg, &sig).expect("signature should be valid");
449        let payload = union_unique(namespace, msg);
450        blst_verify_message(&public, &payload, &sig).expect("signature should be valid");
451    }
452
453    #[test]
454    fn test_threshold_message() {
455        // Generate signature
456        let (n, t) = (5, 4);
457        let mut rng = StdRng::seed_from_u64(0);
458        let (public, shares) = generate_shares(&mut rng, None, n, t);
459        let msg = &[1, 9, 6, 9];
460        let namespace = b"test";
461        let partials: Vec<_> = shares
462            .iter()
463            .map(|s| partial_sign_message(s, Some(namespace), msg))
464            .collect();
465        for p in &partials {
466            partial_verify_message(&public, Some(namespace), msg, p)
467                .expect("signature should be valid");
468        }
469        let threshold_sig = threshold_signature_recover(t, partials).unwrap();
470        let threshold_pub = poly::public(&public);
471
472        // Verify the signature
473        verify_message(&threshold_pub, Some(namespace), msg, &threshold_sig)
474            .expect("signature should be valid");
475
476        // Verify the signature using blst
477        let payload = union_unique(namespace, msg);
478        blst_verify_message(&threshold_pub, &payload, &threshold_sig)
479            .expect("signature should be valid");
480    }
481
482    #[test]
483    fn test_single_message_min_sig() {
484        // Generate keypair
485        let private = group::Private::rand(&mut thread_rng());
486        let mut public = group::G2::one();
487        public.mul(&private);
488
489        // Sign message
490        let msg = &[1, 9, 6, 9];
491        let namespace = b"test";
492        let payload = union_unique(namespace, msg);
493        let mut signature = G1::zero();
494        signature.map(G1_MESSAGE, &payload);
495        signature.mul(&private);
496
497        // Verify signature using blst
498        let public = blst::min_sig::PublicKey::from_bytes(public.serialize().as_slice()).unwrap();
499        let signature =
500            blst::min_sig::Signature::from_bytes(signature.serialize().as_slice()).unwrap();
501        let result = match signature.verify(true, &payload, G1_MESSAGE, &[], &public, true) {
502            BLST_ERROR::BLST_SUCCESS => Ok(()),
503            e => Err(e),
504        };
505        result.expect("signature should be valid");
506    }
507
508    fn blst_aggregate_verify_multiple_public_keys(
509        public: &[group::Public],
510        message: &[u8],
511        signature: &group::Signature,
512    ) -> Result<(), BLST_ERROR> {
513        let public = public
514            .iter()
515            .map(|pk| blst::min_pk::PublicKey::from_bytes(pk.serialize().as_slice()).unwrap())
516            .collect::<Vec<_>>();
517        let public = public.iter().collect::<Vec<_>>();
518        let signature =
519            blst::min_pk::Signature::from_bytes(signature.serialize().as_slice()).unwrap();
520        match signature.fast_aggregate_verify(true, message, MESSAGE, &public) {
521            BLST_ERROR::BLST_SUCCESS => Ok(()),
522            e => Err(e),
523        }
524    }
525
526    #[test]
527    fn test_aggregate_verify_multiple_public_keys() {
528        // Generate signatures
529        let (private1, public1) = keypair(&mut thread_rng());
530        let (private2, public2) = keypair(&mut thread_rng());
531        let (private3, public3) = keypair(&mut thread_rng());
532        let namespace = b"test";
533        let message = b"message";
534        let sig1 = sign_message(&private1, Some(namespace), message);
535        let sig2 = sign_message(&private2, Some(namespace), message);
536        let sig3 = sign_message(&private3, Some(namespace), message);
537        let pks = vec![public1, public2, public3];
538        let signatures = vec![sig1, sig2, sig3];
539
540        // Aggregate the signatures
541        let aggregate_sig = aggregate_signatures(&signatures);
542
543        // Verify the aggregated signature
544        aggregate_verify_multiple_public_keys(&pks, Some(namespace), message, &aggregate_sig)
545            .expect("Aggregated signature should be valid");
546
547        // Verify the aggregated signature using blst
548        let payload = union_unique(namespace, message);
549        blst_aggregate_verify_multiple_public_keys(&pks, &payload, &aggregate_sig)
550            .expect("Aggregated signature should be valid");
551    }
552
553    #[test]
554    fn test_aggregate_verify_wrong_public_keys() {
555        // Generate signatures
556        let (private1, public1) = keypair(&mut thread_rng());
557        let (private2, public2) = keypair(&mut thread_rng());
558        let (private3, _) = keypair(&mut thread_rng());
559        let namespace = b"test";
560        let message = b"message";
561        let sig1 = sign_message(&private1, Some(namespace), message);
562        let sig2 = sign_message(&private2, Some(namespace), message);
563        let sig3 = sign_message(&private3, Some(namespace), message);
564        let signatures = vec![sig1, sig2, sig3];
565
566        // Aggregate the signatures
567        let aggregate_sig = aggregate_signatures(&signatures);
568
569        // Verify the aggregated signature
570        let (_, public4) = keypair(&mut thread_rng());
571        let wrong_pks = vec![public1, public2, public4];
572        let result = aggregate_verify_multiple_public_keys(
573            &wrong_pks,
574            Some(namespace),
575            message,
576            &aggregate_sig,
577        );
578        assert!(matches!(result, Err(Error::InvalidSignature)));
579    }
580
581    #[test]
582    fn test_aggregate_verify_wrong_public_key_count() {
583        // Generate signatures
584        let (private1, public1) = keypair(&mut thread_rng());
585        let (private2, public2) = keypair(&mut thread_rng());
586        let (private3, _) = keypair(&mut thread_rng());
587        let namespace = b"test";
588        let message = b"message";
589        let sig1 = sign_message(&private1, Some(namespace), message);
590        let sig2 = sign_message(&private2, Some(namespace), message);
591        let sig3 = sign_message(&private3, Some(namespace), message);
592        let signatures = vec![sig1, sig2, sig3];
593
594        // Aggregate the signatures
595        let aggregate_sig = aggregate_signatures(&signatures);
596
597        // Verify the aggregated signature
598        let wrong_pks = vec![public1, public2];
599        let result = aggregate_verify_multiple_public_keys(
600            &wrong_pks,
601            Some(namespace),
602            message,
603            &aggregate_sig,
604        );
605        assert!(matches!(result, Err(Error::InvalidSignature)));
606    }
607
608    fn blst_aggregate_verify_multiple_messages(
609        public: &group::Public,
610        msgs: &[&[u8]],
611        signature: &group::Signature,
612    ) -> Result<(), BLST_ERROR> {
613        let public = blst::min_pk::PublicKey::from_bytes(public.serialize().as_slice()).unwrap();
614        let pks = vec![&public; msgs.len()];
615        let signature =
616            blst::min_pk::Signature::from_bytes(signature.serialize().as_slice()).unwrap();
617        match signature.aggregate_verify(true, msgs, MESSAGE, &pks, true) {
618            BLST_ERROR::BLST_SUCCESS => Ok(()),
619            e => Err(e),
620        }
621    }
622
623    #[test]
624    fn test_aggregate_verify_multiple_messages() {
625        // Generate signatures
626        let (private, public) = keypair(&mut thread_rng());
627        let messages: Vec<&[u8]> = vec![b"Message 1", b"Message 2", b"Message 3"];
628        let namespace = Some(&b"test"[..]);
629        let signatures: Vec<_> = messages
630            .iter()
631            .map(|msg| sign_message(&private, namespace, msg))
632            .collect();
633
634        // Aggregate the signatures
635        let aggregate_sig = aggregate_signatures(&signatures);
636
637        // Verify the aggregated signature
638        aggregate_verify_multiple_messages(&public, namespace, &messages, &aggregate_sig, 4)
639            .expect("Aggregated signature should be valid");
640
641        // Verify the aggregated signature using blst
642        let messages = messages
643            .iter()
644            .map(|msg| union_unique(b"test", msg))
645            .collect::<Vec<_>>();
646        let messages = messages
647            .iter()
648            .map(|msg| msg.as_slice())
649            .collect::<Vec<_>>();
650        blst_aggregate_verify_multiple_messages(&public, &messages, &aggregate_sig)
651            .expect("Aggregated signature should be valid");
652    }
653
654    #[test]
655    fn test_aggregate_verify_wrong_messages() {
656        // Generate signatures
657        let (private, public) = keypair(&mut thread_rng());
658        let messages: Vec<&[u8]> = vec![b"Message 1", b"Message 2", b"Message 3"];
659        let namespace = Some(&b"test"[..]);
660        let signatures: Vec<_> = messages
661            .iter()
662            .map(|msg| sign_message(&private, namespace, msg))
663            .collect();
664
665        // Aggregate the signatures
666        let aggregate_sig = aggregate_signatures(&signatures);
667
668        // Verify the aggregated signature
669        let wrong_messages: Vec<&[u8]> = vec![b"Message 1", b"Message 2", b"Message 4"];
670        let result = aggregate_verify_multiple_messages(
671            &public,
672            namespace,
673            &wrong_messages,
674            &aggregate_sig,
675            4,
676        );
677        assert!(matches!(result, Err(Error::InvalidSignature)));
678    }
679
680    #[test]
681    fn test_aggregate_verify_wrong_message_count() {
682        // Generate signatures
683        let (private, public) = keypair(&mut thread_rng());
684        let messages: Vec<&[u8]> = vec![b"Message 1", b"Message 2", b"Message 3"];
685        let namespace = Some(&b"test"[..]);
686        let signatures: Vec<_> = messages
687            .iter()
688            .map(|msg| sign_message(&private, namespace, msg))
689            .collect();
690
691        // Aggregate the signatures
692        let aggregate_sig = aggregate_signatures(&signatures);
693
694        // Verify the aggregated signature
695        let wrong_messages: Vec<&[u8]> = vec![b"Message 1", b"Message 2"];
696        let result = aggregate_verify_multiple_messages(
697            &public,
698            namespace,
699            &wrong_messages,
700            &aggregate_sig,
701            4,
702        );
703        assert!(matches!(result, Err(Error::InvalidSignature)));
704    }
705}