coconut_crypto/signature/
aggregated_signature.rs1use alloc::vec::Vec;
2use ark_ff::PrimeField;
3use itertools::{process_results, Itertools};
4use secret_sharing_and_dkg::common::ParticipantId;
5use serde::{Deserialize, Serialize};
6
7use ark_ec::pairing::Pairing;
8
9use ark_serialize::*;
10use ark_std::cfg_iter;
11use utils::iter::validate;
12
13use super::{error::AggregatedPSError, ps_signature::Signature};
14use crate::helpers::{lagrange_basis_at_0, seq_pairs_satisfy, CheckLeft};
15use utils::owned_pairs;
16
17#[cfg(feature = "parallel")]
18use rayon::prelude::*;
19
20type Result<T, E = AggregatedPSError> = core::result::Result<T, E>;
21
22#[derive(
25 Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize,
26)]
27#[serde(bound = "")]
28pub struct AggregatedSignature<E: Pairing>(Signature<E>);
29utils::impl_deref! { AggregatedSignature<E: Pairing>(Signature<E>) }
30
31impl<E: Pairing> AggregatedSignature<E> {
32 pub fn new<'a, SI>(participant_signatures: SI, &h: &E::G1Affine) -> Result<Self>
36 where
37 SI: IntoIterator<Item = (ParticipantId, &'a Signature<E>)>,
38 {
39 let validator = (
40 |(idx, sig): &(u16, &Signature<E>)| {
41 (sig.sigma_1 != h).then_some(AggregatedPSError::InvalidSigma1For(*idx))
42 },
43 CheckLeft(seq_pairs_satisfy(|a, b| a < b)),
44 );
45
46 let (participant_ids, s): (Vec<_>, Vec<_>) = process_results(
47 validate(participant_signatures, validator).map_ok(|(id, sig)| (id, sig.sigma_2)),
48 |iter| iter.unzip(),
49 )?;
50 if s.is_empty() {
51 Err(AggregatedPSError::NoSignatures)?
52 }
53 if cfg_iter!(participant_ids).any(|p| *p == 0) {
54 return Err(AggregatedPSError::ParticipantIdCantBeZero);
55 }
56 let l = lagrange_basis_at_0(participant_ids)
57 .map(<E::ScalarField as PrimeField>::into_bigint)
58 .collect();
59 let s_mul_l = owned_pairs!(s, l).msm_bigint();
60
61 Ok(Self(Signature::combine(h, s_mul_l)))
62 }
63}
64
65#[cfg(test)]
66mod aggregated_signature_tests {
67 use alloc::vec::Vec;
68 use ark_bls12_381::Bls12_381;
69 type G1 = <Bls12_381 as Pairing>::G1;
70 use ark_ec::{pairing::Pairing, CurveGroup};
71 use ark_ff::UniformRand;
72 use ark_std::{
73 cfg_into_iter,
74 rand::{rngs::StdRng, SeedableRng},
75 };
76 use blake2::Blake2b512;
77
78 use itertools::Itertools;
79 #[cfg(feature = "parallel")]
80 use rayon::prelude::*;
81
82 use crate::{
83 helpers::n_rand,
84 setup::test_setup,
85 signature::{aggregated_signature::AggregatedSignature, error::AggregatedPSError},
86 BlindSignature, CommitmentOrMessage, MessageCommitment, Signature,
87 };
88
89 #[test]
90 fn basic_workflow() {
91 cfg_into_iter!(2..5).for_each(|message_count| {
92 cfg_into_iter!(1..message_count).for_each(|blind_message_count| {
93 cfg_into_iter!(1..8).for_each(|authority_count| {
94 let mut rng = StdRng::seed_from_u64(0u64);
96 let h = G1::rand(&mut rng).into_affine();
97 let (sk, pk, params, msgs) =
98 test_setup::<Bls12_381, Blake2b512, _>(&mut rng, message_count);
99
100 let (blind_msgs, reveal_msgs) = msgs.split_at(blind_message_count as usize);
102 let blind_indices = 0..blind_msgs.len();
103
104 let blindings: Vec<_> = n_rand(&mut rng, blind_msgs.len()).collect();
105 let o_m_pairs = utils::pairs!(blindings, blind_msgs);
106
107 let m_comms: Vec<_> =
108 MessageCommitment::new_iter(o_m_pairs, &h, ¶ms).collect();
109 let comms = m_comms
110 .iter()
111 .copied()
112 .map(CommitmentOrMessage::BlindedMessage)
113 .chain(
114 reveal_msgs
115 .iter()
116 .copied()
117 .map(CommitmentOrMessage::RevealedMessage),
118 );
119
120 let sigs = (1..=authority_count)
121 .map(|_| {
122 let blind_signature =
123 BlindSignature::new(comms.clone(), &sk, &h).unwrap();
124
125 let sig = blind_signature
126 .unblind(blind_indices.clone().zip(blindings.iter()), &pk, &h)
127 .unwrap();
128
129 sig.verify(&msgs, &pk, ¶ms).unwrap();
130
131 sig
132 })
133 .collect_vec();
134
135 let aggregated = AggregatedSignature::new(
136 sigs.iter()
137 .enumerate()
138 .map(|(idx, sig)| (idx as u16 + 1, sig)),
139 &h,
140 )
141 .unwrap();
142 aggregated.verify(&msgs, &pk, ¶ms).unwrap();
143 })
144 })
145 });
146 }
147
148 #[test]
149 fn invalid_sigma_1() {
150 let mut rng = StdRng::seed_from_u64(0u64);
151 let h = G1::rand(&mut rng).into_affine();
152 let sigma_1 = G1::rand(&mut rng).into_affine();
153 let sigma_2 = G1::rand(&mut rng).into_affine();
154
155 assert_eq!(
156 AggregatedSignature::new(
157 Some(Signature::<Bls12_381>::combine(sigma_1, sigma_2))
158 .iter()
159 .enumerate()
160 .map(|(idx, v)| (idx as u16 + 1, v)),
161 &h
162 ),
163 Err(AggregatedPSError::InvalidSigma1For(1))
164 )
165 }
166
167 #[test]
168 fn empty_signature() {
169 let mut rng = StdRng::seed_from_u64(0u64);
170 let h = G1::rand(&mut rng).into_affine();
171
172 assert_eq!(
173 AggregatedSignature::<Bls12_381>::new(None, &h),
174 Err(AggregatedPSError::NoSignatures)
175 );
176 }
177
178 #[test]
179 fn zero_participant_id() {
180 let mut rng = StdRng::seed_from_u64(0u64);
181 let h = G1::rand(&mut rng).into_affine();
182
183 let sig1 = Signature::<Bls12_381>::combine(h.clone(), G1::rand(&mut rng).into_affine());
184 let sig2 = Signature::<Bls12_381>::combine(h.clone(), G1::rand(&mut rng).into_affine());
185 let aggr_sigs = vec![(0, &sig1), (1, &sig2)];
186 assert_eq!(
187 AggregatedSignature::new(aggr_sigs, &h),
188 Err(AggregatedPSError::ParticipantIdCantBeZero)
189 )
190 }
191}