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 #[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 #[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}