1use crate::{
6 hash::{CryptoHash, CryptoHasher},
7 traits::*,
8 CryptoMaterialError, PrivateKey, PublicKey, Signature, SigningKey, Uniform,
9 ValidCryptoMaterial, ValidCryptoMaterialStringExt, VerifyingKey,
10};
11use anyhow::{anyhow, Result};
12use bls_signatures::{
13 DeserializeUnchecked, PrivateKey as RawPrivateKey,
14 PublicKey as RawPublicKey, Serialize as BLSSerialize,
15 Signature as RawSignature,
16};
17use diem_crypto_derive::{
18 DeserializeKey, SerializeKey, SilentDebug, SilentDisplay,
19};
20use diem_logger::prelude::*;
21use mirai_annotations::*;
22use serde::{Deserialize, Deserializer, Serialize};
23use std::convert::TryFrom;
24
25#[cfg(mirai)]
26use crate::tags::ValidatedPublicKeyTag;
27use std::fmt::{self, Formatter};
28
29pub const BLS_PRIVATE_KEY_LENGTH: usize = 32;
31pub const BLS_PUBLIC_KEY_LENGTH: usize = 48;
33pub const BLS_SIGNATURE_LENGTH: usize = 96;
35
36#[cfg(not(mirai))]
37struct ValidatedPublicKeyTag {}
38
39#[derive(DeserializeKey, SerializeKey, SilentDebug, SilentDisplay)]
41pub struct BLSPrivateKey(RawPrivateKey);
42
43#[cfg(feature = "assert-private-keys-not-cloneable")]
44static_assertions::assert_not_impl_any!(BLSPrivateKey: Clone);
45
46#[cfg(any(test, feature = "cloneable-private-keys"))]
47impl Clone for BLSPrivateKey {
48 fn clone(&self) -> Self {
49 let serialized: &[u8] = &(self.to_bytes());
50 BLSPrivateKey::try_from(serialized).unwrap()
51 }
52}
53
54#[derive(DeserializeKey, Clone, SerializeKey)]
56pub struct BLSPublicKey(RawPublicKey);
57
58#[derive(DeserializeKey, Clone, SerializeKey)]
61pub struct BLSSignature(RawSignature);
62
63impl BLSPrivateKey {
64 pub fn raw_key(self) -> RawPrivateKey { self.0 }
66}
67
68impl PartialEq<Self> for BLSPrivateKey {
69 fn eq(&self, other: &Self) -> bool { self.to_bytes() == other.to_bytes() }
70}
71
72impl Eq for BLSPrivateKey {}
73
74impl SigningKey for BLSPrivateKey {
75 type SignatureMaterial = BLSSignature;
76 type VerifyingKeyMaterial = BLSPublicKey;
77
78 fn sign<T: CryptoHash + Serialize>(
79 &self, message: &T,
80 ) -> Self::SignatureMaterial {
81 let mut bytes = <T::Hasher as CryptoHasher>::seed().to_vec();
82 bcs::serialize_into(&mut bytes, &message)
83 .map_err(|_| CryptoMaterialError::SerializationError)
84 .expect("Serialization of signable material should not fail.");
85 BLSSignature(self.0.sign(bytes))
86 }
87
88 #[cfg(any(test, feature = "fuzzing"))]
89 fn sign_arbitrary_message(
90 &self, message: &[u8],
91 ) -> Self::SignatureMaterial {
92 BLSSignature(self.0.sign(message))
93 }
94}
95
96impl From<RawPublicKey> for BLSPublicKey {
97 fn from(raw: RawPublicKey) -> Self { BLSPublicKey(raw) }
98}
99
100impl VerifyingKey for BLSPublicKey {
101 type SignatureMaterial = BLSSignature;
102 type SigningKeyMaterial = BLSPrivateKey;
103}
104
105impl PrivateKey for BLSPrivateKey {
106 type PublicKeyMaterial = BLSPublicKey;
107}
108
109impl BLSPublicKey {
110 pub fn raw(self) -> RawPublicKey { self.0 }
112}
113
114impl BLSSignature {
115 #[cfg(any(test, feature = "fuzzing"))]
117 pub fn dummy_signature() -> Self {
118 let bytes = [0u8; BLS_SIGNATURE_LENGTH];
119 Self::try_from(&bytes[..]).unwrap()
120 }
121
122 pub fn raw(self) -> RawSignature { self.0 }
124}
125
126impl Signature for BLSSignature {
127 type SigningKeyMaterial = BLSPrivateKey;
128 type VerifyingKeyMaterial = BLSPublicKey;
129
130 fn verify<T: CryptoHash + Serialize>(
131 &self, message: &T, public_key: &Self::VerifyingKeyMaterial,
132 ) -> Result<()> {
133 let mut bytes = <T::Hasher as CryptoHasher>::seed().to_vec();
134 bcs::serialize_into(&mut bytes, &message)
135 .map_err(|_| CryptoMaterialError::SerializationError)?;
136 self.verify_arbitrary_msg(&bytes, public_key)
137 }
138
139 fn verify_arbitrary_msg(
140 &self, message: &[u8], public_key: &Self::VerifyingKeyMaterial,
141 ) -> Result<()> {
142 precondition!(has_tag!(public_key, ValidatedPublicKeyTag));
143 match bls_signatures::verify_messages(
144 &self.0,
145 std::slice::from_ref(&message),
146 std::slice::from_ref(&public_key.0),
147 ) {
148 true => Ok(()),
149 false => Err(anyhow!("Invalid BLS signature!")),
150 }
151 }
152}
153
154impl PublicKey for BLSPublicKey {
155 type PrivateKeyMaterial = BLSPrivateKey;
156}
157
158impl From<&BLSPrivateKey> for BLSPublicKey {
159 fn from(private_key: &BLSPrivateKey) -> Self {
160 BLSPublicKey(private_key.0.public_key())
161 }
162}
163
164impl From<&RawPrivateKey> for BLSPrivateKey {
165 fn from(raw_private_key: &RawPrivateKey) -> Self {
166 BLSPrivateKey(*raw_private_key)
167 }
168}
169
170impl From<RawPrivateKey> for BLSPrivateKey {
171 fn from(raw_private_key: RawPrivateKey) -> Self {
172 BLSPrivateKey(raw_private_key)
173 }
174}
175
176impl From<&RawSignature> for BLSSignature {
177 fn from(raw_signature: &RawSignature) -> Self {
178 BLSSignature(*raw_signature)
179 }
180}
181
182impl From<RawSignature> for BLSSignature {
183 fn from(raw_signature: RawSignature) -> Self { BLSSignature(raw_signature) }
184}
185
186impl TryFrom<&[u8]> for BLSPrivateKey {
187 type Error = CryptoMaterialError;
188
189 fn try_from(
192 bytes: &[u8],
193 ) -> std::result::Result<BLSPrivateKey, CryptoMaterialError> {
194 match RawPrivateKey::from_bytes(bytes) {
195 Ok(sig) => Ok(Self(sig)),
196 Err(_) => Err(CryptoMaterialError::DeserializationError),
197 }
198 }
199}
200
201impl TryFrom<&[u8]> for BLSPublicKey {
202 type Error = CryptoMaterialError;
203
204 fn try_from(
207 bytes: &[u8],
208 ) -> std::result::Result<BLSPublicKey, CryptoMaterialError> {
209 match RawPublicKey::from_bytes(bytes) {
210 Ok(sig) => Ok(Self(sig)),
211 Err(e) => {
212 diem_debug!(
213 "BLSPublicKey debug error: bytes={:?}, err={:?}",
214 bytes,
215 e
216 );
217 Err(CryptoMaterialError::DeserializationError)
218 }
219 }
220 }
221}
222
223impl TryFrom<&[u8]> for BLSSignature {
224 type Error = CryptoMaterialError;
225
226 fn try_from(
229 bytes: &[u8],
230 ) -> std::result::Result<BLSSignature, CryptoMaterialError> {
231 match RawSignature::from_bytes(bytes) {
233 Ok(sig) => Ok(Self(sig)),
234 Err(_) => Err(CryptoMaterialError::DeserializationError),
235 }
236 }
237}
238
239impl std::hash::Hash for BLSPublicKey {
240 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
241 let encoded_pubkey = self.to_bytes();
242 state.write(&encoded_pubkey);
243 }
244}
245
246impl PartialEq for BLSPublicKey {
247 fn eq(&self, other: &BLSPublicKey) -> bool {
248 self.to_bytes() == other.to_bytes()
249 }
250}
251
252impl std::hash::Hash for BLSSignature {
253 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
254 let encoded_pubkey = ValidCryptoMaterial::to_bytes(self);
255 state.write(&encoded_pubkey);
256 }
257}
258
259impl PartialEq for BLSSignature {
260 fn eq(&self, other: &BLSSignature) -> bool {
261 self.to_bytes() == other.to_bytes()
262 }
263}
264
265impl Eq for BLSPublicKey {}
266
267impl Eq for BLSSignature {}
268
269impl ValidCryptoMaterial for BLSPrivateKey {
270 fn to_bytes(&self) -> Vec<u8> { self.0.as_bytes() }
271}
272
273impl Genesis for BLSPrivateKey {
274 fn genesis() -> Self {
275 let mut buf = [0u8; BLS_PRIVATE_KEY_LENGTH];
276 buf[BLS_PRIVATE_KEY_LENGTH - 1] = 1;
277 Self::try_from(buf.as_ref()).unwrap()
278 }
279}
280
281impl ValidCryptoMaterial for BLSPublicKey {
282 fn to_bytes(&self) -> Vec<u8> { self.0.as_bytes() }
283}
284
285impl ValidCryptoMaterial for BLSSignature {
286 fn to_bytes(&self) -> Vec<u8> { self.0.as_bytes() }
287}
288
289impl fmt::Display for BLSPublicKey {
290 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
291 write!(f, "{}", self.to_encoded_string().map_err(|_| fmt::Error)?)
292 }
293}
294
295impl Uniform for BLSPrivateKey {
296 fn generate<R>(rng: &mut R) -> Self
297 where R: ::rand::RngCore + ::rand::CryptoRng {
298 BLSPrivateKey(RawPrivateKey::generate(rng))
299 }
300}
301
302impl fmt::Debug for BLSPublicKey {
303 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304 write!(f, "BLSPublicKey({})", self)
305 }
306}
307
308impl fmt::Display for BLSSignature {
309 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
310 write!(f, "{}", self.to_encoded_string().map_err(|_| fmt::Error)?)
311 }
312}
313
314impl fmt::Debug for BLSSignature {
315 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316 write!(f, "BLSSignature({})", self)
317 }
318}
319
320#[derive(SerializeKey, DeserializeKey)]
323pub struct BLSPublicKeyUnchecked(RawPublicKey);
324#[derive(SerializeKey, DeserializeKey)]
327pub struct BLSSignatureUnchecked(RawSignature);
328
329impl TryFrom<&[u8]> for BLSPublicKeyUnchecked {
330 type Error = CryptoMaterialError;
331
332 fn try_from(
335 bytes: &[u8],
336 ) -> std::result::Result<BLSPublicKeyUnchecked, CryptoMaterialError> {
337 match RawPublicKey::from_bytes_unchecked(bytes) {
338 Ok(sig) => Ok(Self(sig)),
339 Err(e) => {
340 diem_debug!(
341 "BLSPublicKey debug error: bytes={:?}, err={:?}",
342 bytes,
343 e
344 );
345 Err(CryptoMaterialError::DeserializationError)
346 }
347 }
348 }
349}
350
351impl TryFrom<&[u8]> for BLSSignatureUnchecked {
352 type Error = CryptoMaterialError;
353
354 fn try_from(
357 bytes: &[u8],
358 ) -> std::result::Result<BLSSignatureUnchecked, CryptoMaterialError> {
359 match RawSignature::from_bytes_unchecked(bytes) {
361 Ok(sig) => Ok(Self(sig)),
362 Err(_) => Err(CryptoMaterialError::DeserializationError),
363 }
364 }
365}
366
367impl ValidCryptoMaterial for BLSPublicKeyUnchecked {
368 fn to_bytes(&self) -> Vec<u8> { self.0.as_bytes() }
369}
370
371impl ValidCryptoMaterial for BLSSignatureUnchecked {
372 fn to_bytes(&self) -> Vec<u8> { self.0.as_bytes() }
373}
374
375impl From<BLSPublicKeyUnchecked> for BLSPublicKey {
376 fn from(unchecked: BLSPublicKeyUnchecked) -> Self { Self(unchecked.0) }
377}
378
379impl From<BLSSignatureUnchecked> for BLSSignature {
380 fn from(unchecked: BLSSignatureUnchecked) -> Self { Self(unchecked.0) }
381}
382
383pub fn deserialize_bls_public_key_unchecked<'de, D>(
385 deserializer: D,
386) -> Result<BLSPublicKey, D::Error>
387where D: Deserializer<'de> {
388 BLSPublicKeyUnchecked::deserialize(deserializer).map(Into::into)
389}
390
391#[cfg(any(test, feature = "fuzzing"))]
392use crate::test_utils::{self, KeyPair};
393
394#[cfg(any(test, feature = "fuzzing"))]
396pub fn keypair_strategy(
397) -> impl Strategy<Value = KeyPair<BLSPrivateKey, BLSPublicKey>> {
398 test_utils::uniform_keypair_strategy::<BLSPrivateKey, BLSPublicKey>()
399}
400
401#[cfg(any(test, feature = "fuzzing"))]
402use proptest::prelude::*;
403
404#[cfg(any(test, feature = "fuzzing"))]
405impl proptest::arbitrary::Arbitrary for BLSPublicKey {
406 type Parameters = ();
407 type Strategy = BoxedStrategy<Self>;
408
409 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
410 crate::test_utils::uniform_keypair_strategy::<
411 BLSPrivateKey,
412 BLSPublicKey,
413 >()
414 .prop_map(|v| v.public_key)
415 .boxed()
416 }
417}
418
419#[cfg(test)]
420mod test {
421 use crate as diem_crypto;
422 use crate::{
423 bls::{BLSPrivateKey, BLSSignature},
424 SigningKey, Uniform, ValidCryptoMaterial,
425 };
426 use diem_crypto_derive::{BCSCryptoHash, CryptoHasher};
427 use serde::{Deserialize, Serialize};
428 use std::{convert::TryFrom, time::Instant};
429
430 #[derive(Debug, CryptoHasher, BCSCryptoHash, Serialize, Deserialize)]
431 pub struct TestDiemCrypto(pub String);
432 #[test]
433 fn test_bls_sig_decode() {
434 let sk = BLSPrivateKey::generate(&mut rand::thread_rng());
435 let sig = sk.sign(&TestDiemCrypto("".to_string()));
436 let sig_bytes = sig.to_bytes();
437 let start = Instant::now();
438 let _decoded = BLSSignature::try_from(sig_bytes.as_slice()).unwrap();
439 println!("Time elapsed: {} us", start.elapsed().as_micros());
440 }
441}