Skip to main content

ophelia_blst/
lib.rs

1use ophelia::{BlsSignatureVerify, HashValue, PrivateKey, PublicKey, Signature, ToBlsPublicKey};
2use ophelia::{Bytes, Error};
3use ophelia::{CryptoRng, RngCore};
4use ophelia_derive::SecretDebug;
5
6use blst::{min_pk as bls, BLST_ERROR};
7
8use std::convert::TryFrom;
9
10const DST: &str = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RONUL";
11
12#[derive(thiserror::Error, Debug)]
13pub enum BlsError {
14    #[error("deserialize fail")]
15    Deserialize,
16    #[error("invalid signature")]
17    InvalidSignature,
18    #[error("aggregrate pubkey fail")]
19    AggregatePublicKey,
20    #[error("aggregate signature fail")]
21    AggregateSignature,
22}
23
24#[derive(SecretDebug, Clone)]
25pub struct BlsPrivateKey(bls::SecretKey);
26
27impl TryFrom<&[u8]> for BlsPrivateKey {
28    type Error = Error;
29
30    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
31        use BlsError::*;
32
33        let key = bls::SecretKey::from_bytes(bytes).map_err(|_| Deserialize)?;
34        Ok(BlsPrivateKey(key))
35    }
36}
37
38impl PrivateKey for BlsPrivateKey {
39    type Signature = BlsSignature;
40
41    const LENGTH: usize = 32;
42
43    fn generate<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
44        let mut seed = [0u8; 32];
45        rng.fill_bytes(&mut seed);
46        BlsPrivateKey(bls::SecretKey::key_gen(&seed, &[]).unwrap())
47    }
48
49    fn sign_message(&self, msg: &HashValue) -> Self::Signature {
50        BlsSignature(self.0.sign(msg.as_ref(), DST.as_bytes(), &[]))
51    }
52
53    fn to_bytes(&self) -> Bytes {
54        Bytes::from(self.0.to_bytes().to_vec())
55    }
56}
57
58impl ToBlsPublicKey for BlsPrivateKey {
59    type PublicKey = BlsPublicKey;
60    type CommonReference = String;
61
62    fn pub_key(&self, _cr: &Self::CommonReference) -> BlsPublicKey {
63        BlsPublicKey(self.0.sk_to_pk())
64    }
65}
66
67#[derive(Debug, PartialEq, Clone)]
68pub struct BlsPublicKey(bls::PublicKey);
69
70impl BlsPublicKey {
71    pub fn aggregate(keys: Vec<BlsPublicKey>) -> Result<Self, BlsError> {
72        let keys = keys.iter().map(|k| &k.0).collect::<Vec<_>>();
73        let aggregated_pk = bls::AggregatePublicKey::aggregate(&keys, true)
74            .map_err(|_| BlsError::AggregatePublicKey)?;
75
76        Ok(BlsPublicKey(bls::PublicKey::from_aggregate(&aggregated_pk)))
77    }
78}
79
80impl TryFrom<&[u8]> for BlsPublicKey {
81    type Error = Error;
82
83    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
84        use BlsError::*;
85
86        let key = bls::PublicKey::from_bytes(bytes).map_err(|_| Deserialize)?;
87        Ok(BlsPublicKey(key))
88    }
89}
90
91impl PublicKey for BlsPublicKey {
92    type Signature = BlsPublicKey;
93
94    const LENGTH: usize = 48;
95
96    fn to_bytes(&self) -> Bytes {
97        Bytes::from(self.0.to_bytes().to_vec())
98    }
99}
100
101#[derive(Debug, PartialEq, Clone)]
102pub struct BlsSignature(bls::Signature);
103
104impl BlsSignature {
105    pub fn combine(sigs_pubkeys: Vec<(BlsSignature, BlsPublicKey)>) -> Result<Self, BlsError> {
106        let sigs = sigs_pubkeys
107            .iter()
108            .map(|(sig, _)| &sig.0)
109            .collect::<Vec<_>>();
110        let aggregated_sig = bls::AggregateSignature::aggregate(&sigs, true)
111            .map_err(|_| BlsError::AggregateSignature)?;
112
113        Ok(BlsSignature(bls::Signature::from_aggregate(
114            &aggregated_sig,
115        )))
116    }
117}
118
119impl TryFrom<&[u8]> for BlsSignature {
120    type Error = Error;
121
122    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
123        use BlsError::*;
124
125        let sig = bls::Signature::from_bytes(bytes).map_err(|_| Deserialize)?;
126        Ok(BlsSignature(sig))
127    }
128}
129
130impl Signature for BlsSignature {
131    fn to_bytes(&self) -> Bytes {
132        Bytes::from(self.0.to_bytes().to_vec())
133    }
134}
135
136impl BlsSignatureVerify for BlsSignature {
137    type PublicKey = BlsPublicKey;
138    type CommonReference = String;
139
140    #[cfg(not(feature = "fast"))]
141    fn verify(
142        &self,
143        msg: &HashValue,
144        pubkey: &Self::PublicKey,
145        _cr: &Self::CommonReference,
146    ) -> Result<(), Error> {
147        if self
148            .0
149            .verify(true, msg.as_ref(), DST.as_bytes(), &[], &pubkey.0, true)
150            == BLST_ERROR::BLST_SUCCESS
151        {
152            return Ok(());
153        }
154
155        Err(BlsError::InvalidSignature.into())
156    }
157
158    #[cfg(feature = "fast")]
159    fn verify(
160        &self,
161        msg: &HashValue,
162        pubkey: &Self::PublicKey,
163        _cr: &Self::CommonReference,
164    ) -> Result<(), Error> {
165        if self.0.fast_aggregate_verify_pre_aggregated(
166            true,
167            msg.as_ref(),
168            DST.as_bytes(),
169            &pubkey.0,
170        ) == BLST_ERROR::BLST_SUCCESS
171        {
172            return Ok(());
173        }
174
175        Err(BlsError::InvalidSignature.into())
176    }
177}
178
179#[cfg(test)]
180mod tests {
181    use super::{BlsPrivateKey, BlsPublicKey, BlsSignature};
182
183    use ophelia::{
184        BlsSignatureVerify, HashValue, PrivateKey, PublicKey, Signature, ToBlsPublicKey,
185    };
186    use quickcheck::{Arbitrary, Gen};
187    use rand::rngs::OsRng;
188
189    use std::convert::TryFrom;
190
191    impl Arbitrary for BlsPrivateKey {
192        fn arbitrary(_: &mut Gen) -> BlsPrivateKey {
193            BlsPrivateKey::generate(&mut OsRng)
194        }
195    }
196
197    // Note: test is slow, we only test once.
198    #[test]
199    fn should_generate_workable_key() {
200        let msg = HashValue::from_bytes_unchecked([0u8; 32]);
201        let cr = "fly me to the moon".into();
202
203        let priv_key = BlsPrivateKey::generate(&mut OsRng);
204        let pub_key = priv_key.pub_key(&cr);
205
206        let sig = priv_key.sign_message(&msg);
207        assert!(sig.verify(&msg, &pub_key, &cr).is_ok());
208    }
209
210    // Note: test is slow, we only test once.
211    #[test]
212    fn should_able_serialize_and_deserlize_public_key() {
213        let priv_key = BlsPrivateKey::generate(&mut OsRng);
214        let cr = "fly me to the moon".into();
215        let pub_key = priv_key.pub_key(&cr);
216
217        let same_key = match BlsPublicKey::try_from(pub_key.to_bytes().as_ref()) {
218            Ok(pubkey) => pubkey == pub_key,
219            Err(_) => false,
220        };
221        assert!(same_key)
222    }
223
224    #[test]
225    fn should_able_serialize_and_deserlize_signature() {
226        let msg = HashValue::from_bytes_unchecked([0u8; 32]);
227
228        let priv_key = BlsPrivateKey::generate(&mut OsRng);
229        let sig = priv_key.sign_message(&msg);
230
231        let same_sig = match BlsSignature::try_from(sig.to_bytes().as_ref()) {
232            Ok(s) => s == sig,
233            Err(_) => false,
234        };
235        assert!(same_sig)
236    }
237
238    #[test]
239    fn should_able_combine_sigs_and_keys() {
240        let msg = HashValue::from_bytes_unchecked([0u8; 32]);
241        let cr = "fly me to the moon".into();
242
243        let eva_00 = BlsPrivateKey::generate(&mut OsRng);
244        let sig_00 = eva_00.sign_message(&msg);
245        let plug_00 = eva_00.pub_key(&cr);
246
247        let eva_01 = BlsPrivateKey::generate(&mut OsRng);
248        let sig_01 = eva_01.sign_message(&msg);
249        let plug_01 = eva_01.pub_key(&cr);
250
251        let eva_02 = BlsPrivateKey::generate(&mut OsRng);
252        let sig_02 = eva_02.sign_message(&msg);
253        let plug_02 = eva_02.pub_key(&cr);
254
255        let msig = BlsSignature::combine(vec![
256            (sig_00, plug_00.clone()),
257            (sig_01, plug_01.clone()),
258            (sig_02, plug_02.clone()),
259        ])
260        .unwrap();
261
262        let akey = BlsPublicKey::aggregate(vec![plug_00, plug_01, plug_02]).unwrap();
263
264        assert!(msig.verify(&msg, &akey, &cr).is_ok());
265    }
266}