threshold_bls/sig/
tbls.rs

1//! Threshold Signatures implementation for any type which implements
2//! [`SignatureScheme`](../trait.SignatureScheme.html)
3use crate::poly::{Eval, Idx, Poly, PolyError};
4use crate::sig::{Partial, SignatureScheme, ThresholdScheme};
5use serde::{Deserialize, Serialize};
6use thiserror::Error;
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9/// A private share which is part of the threshold signing key
10pub struct Share<S> {
11    /// The share's index in the polynomial
12    pub index: Idx,
13    /// The scalar corresponding to the share's secret
14    pub private: S,
15}
16
17/// Errors associated with threshold signing, verification and aggregation.
18#[derive(Debug, Error)]
19pub enum ThresholdError<I: SignatureScheme> {
20    /// PolyError is raised when the public key could not be recovered
21    #[error("could not recover public key: {0}")]
22    PolyError(PolyError),
23
24    /// BincodeError is raised when there is an error in (de)serialization
25    #[error(transparent)]
26    BincodeError(#[from] bincode::Error),
27
28    /// SignatureError is raised when there is an error in threshold signing
29    #[error("signing error {0}")]
30    SignatureError(I::Error),
31
32    /// NotEnoughPartialSignatures is raised if the signatures provided for aggregation
33    /// were fewer than the threshold
34    #[error("not enough partial signatures: {0}/{1}")]
35    NotEnoughPartialSignatures(usize, usize),
36}
37
38impl<I: SignatureScheme> ThresholdScheme for I {
39    type Error = ThresholdError<I>;
40
41    fn partial_sign(
42        private: &Share<Self::Private>,
43        msg: &[u8],
44    ) -> Result<Vec<u8>, <Self as ThresholdScheme>::Error> {
45        let sig = Self::sign(&private.private, msg).map_err(ThresholdError::SignatureError)?;
46        let partial = Eval {
47            value: sig,
48            index: private.index,
49        };
50        let ret = bincode::serialize(&partial)?;
51        Ok(ret)
52    }
53
54    fn partial_verify(
55        public: &Poly<Self::Public>,
56        msg: &[u8],
57        partial: &[u8],
58    ) -> Result<(), <Self as ThresholdScheme>::Error> {
59        let partial: Eval<Vec<u8>> = bincode::deserialize(partial)?;
60
61        let public_i = public.eval(partial.index);
62
63        Self::verify(&public_i.value, msg, &partial.value).map_err(ThresholdError::SignatureError)
64    }
65
66    fn aggregate(
67        threshold: usize,
68        partials: &[Partial],
69    ) -> Result<Vec<u8>, <Self as ThresholdScheme>::Error> {
70        if threshold > partials.len() {
71            return Err(ThresholdError::NotEnoughPartialSignatures(
72                partials.len(),
73                threshold,
74            ));
75        }
76
77        let valid_partials: Vec<Eval<Self::Signature>> = partials
78            .iter()
79            .map(|partial| {
80                let eval: Eval<Vec<u8>> = bincode::deserialize(partial)?;
81                let sig = bincode::deserialize(&eval.value)?;
82                Ok(Eval {
83                    index: eval.index,
84                    value: sig,
85                })
86            })
87            .collect::<Result<_, <Self as ThresholdScheme>::Error>>()?;
88
89        let recovered_sig = Poly::<Self::Signature>::recover(threshold, valid_partials)
90            .map_err(ThresholdError::PolyError)?;
91        Ok(bincode::serialize(&recovered_sig).expect("could not serialize"))
92    }
93}
94
95#[cfg(feature = "bls12_381")]
96#[cfg(test)]
97mod tests {
98    use super::*;
99    use crate::{
100        curve::bls12381::PairingCurve as PCurve,
101        sig::{
102            bls::{G1Scheme, G2Scheme},
103            Scheme,
104        },
105    };
106
107    type ShareCreator<T> = fn(
108        usize,
109        usize,
110    ) -> (
111        Vec<Share<<T as Scheme>::Private>>,
112        Poly<<T as Scheme>::Public>,
113    );
114
115    fn shares<T: ThresholdScheme>(n: usize, t: usize) -> (Vec<Share<T::Private>>, Poly<T::Public>) {
116        let private = Poly::<T::Private>::new(t - 1);
117        let shares = (0..n)
118            .map(|i| private.eval(i as Idx))
119            .map(|e| Share {
120                index: e.index,
121                private: e.value,
122            })
123            .collect();
124        (shares, private.commit())
125    }
126
127    fn test_threshold_scheme<T: ThresholdScheme + SignatureScheme>(creator: ShareCreator<T>) {
128        let threshold = 4;
129        let (shares, public) = creator(5, threshold);
130        let msg = vec![1, 9, 6, 9];
131
132        let partials: Vec<_> = shares
133            .iter()
134            .map(|s| T::partial_sign(s, &msg).unwrap())
135            .collect();
136
137        assert_eq!(
138            false,
139            partials
140                .iter()
141                .any(|p| T::partial_verify(&public, &msg, &p).is_err())
142        );
143        let final_sig = T::aggregate(threshold, &partials).unwrap();
144
145        T::verify(public.public_key(), &msg, &final_sig).unwrap();
146    }
147
148    #[test]
149    fn threshold_g1() {
150        type S = G1Scheme<PCurve>;
151        test_threshold_scheme::<S>(shares::<S>);
152    }
153
154    #[test]
155    fn threshold_g2() {
156        type S = G2Scheme<PCurve>;
157        test_threshold_scheme::<S>(shares::<S>);
158    }
159}