commonware_cryptography/bls12381/
scheme.rs

1//! BLS12-381 implementation of the [crate::Verifier] and [crate::Signer] traits.
2//!
3//! This implementation uses the `blst` crate for BLS12-381 operations. This
4//! crate implements serialization according to the "ZCash BLS12-381" specification
5//! (<https://github.com/supranational/blst/tree/master?tab=readme-ov-file#serialization-format>)
6//! and hashes messages according to RFC 9380.
7//!
8//! # Example
9//! ```rust
10//! use commonware_cryptography::{bls12381, PrivateKey, PublicKey, Signature, Verifier as _, Signer as _};
11//! use commonware_math::algebra::Random;
12//! use rand::rngs::OsRng;
13//!
14//! // Generate a new private key
15//! let mut signer = bls12381::PrivateKey::random(&mut OsRng);
16//!
17//! // Create a message to sign
18//! let namespace = b"demo";
19//! let msg = b"hello, world!";
20//!
21//! // Sign the message
22//! let signature = signer.sign(namespace, msg);
23//!
24//! // Verify the signature
25//! assert!(signer.public_key().verify(namespace, msg, &signature));
26//! ```
27
28use super::primitives::{
29    group::{self, Private},
30    ops,
31    variant::{MinPk, Variant},
32};
33use crate::{BatchVerifier, Secret, Signer as _};
34#[cfg(not(feature = "std"))]
35use alloc::vec::Vec;
36use bytes::{Buf, BufMut};
37use commonware_codec::{
38    DecodeExt, EncodeFixed, Error as CodecError, FixedSize, Read, ReadExt, Write,
39};
40use commonware_math::algebra::Random;
41use commonware_parallel::Sequential;
42use commonware_utils::{hex, Array, Span};
43use core::{
44    fmt::{Debug, Display, Formatter},
45    hash::{Hash, Hasher},
46    ops::Deref,
47};
48use rand_core::CryptoRngCore;
49use zeroize::Zeroizing;
50
51const CURVE_NAME: &str = "bls12381";
52
53/// BLS12-381 private key.
54#[derive(Clone, Debug)]
55pub struct PrivateKey {
56    raw: Secret<[u8; group::PRIVATE_KEY_LENGTH]>,
57    key: Private,
58}
59
60impl PartialEq for PrivateKey {
61    fn eq(&self, other: &Self) -> bool {
62        self.raw == other.raw
63    }
64}
65
66impl Eq for PrivateKey {}
67
68impl Write for PrivateKey {
69    fn write(&self, buf: &mut impl BufMut) {
70        self.raw.expose(|raw| raw.write(buf));
71    }
72}
73
74impl Read for PrivateKey {
75    type Cfg = ();
76
77    fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
78        let raw = Zeroizing::new(<[u8; Self::SIZE]>::read(buf)?);
79        let key =
80            Private::decode(raw.as_ref()).map_err(|e| CodecError::Wrapped(CURVE_NAME, e.into()))?;
81        Ok(Self {
82            raw: Secret::new(*raw),
83            key,
84        })
85    }
86}
87
88impl FixedSize for PrivateKey {
89    const SIZE: usize = group::PRIVATE_KEY_LENGTH;
90}
91
92impl From<Private> for PrivateKey {
93    fn from(key: Private) -> Self {
94        let raw = Zeroizing::new(key.expose(|s| s.encode_fixed()));
95        Self {
96            raw: Secret::new(*raw),
97            key,
98        }
99    }
100}
101
102impl Display for PrivateKey {
103    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
104        write!(f, "{:?}", self)
105    }
106}
107
108impl crate::PrivateKey for PrivateKey {}
109
110impl crate::Signer for PrivateKey {
111    type Signature = Signature;
112    type PublicKey = PublicKey;
113
114    fn public_key(&self) -> Self::PublicKey {
115        PublicKey::from(ops::compute_public::<MinPk>(&self.key))
116    }
117
118    fn sign(&self, namespace: &[u8], msg: &[u8]) -> Self::Signature {
119        ops::sign_message::<MinPk>(&self.key, namespace, msg).into()
120    }
121}
122
123impl Random for PrivateKey {
124    fn random(mut rng: impl CryptoRngCore) -> Self {
125        let (private, _) = ops::keypair::<_, MinPk>(&mut rng);
126        private.into()
127    }
128}
129
130#[cfg(feature = "arbitrary")]
131impl arbitrary::Arbitrary<'_> for PrivateKey {
132    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
133        use rand::{rngs::StdRng, SeedableRng};
134
135        let mut rand = StdRng::from_seed(u.arbitrary::<[u8; 32]>()?);
136        Ok(Self::random(&mut rand))
137    }
138}
139
140impl crate::PublicKey for PublicKey {}
141
142impl crate::Verifier for PublicKey {
143    type Signature = Signature;
144
145    fn verify(&self, namespace: &[u8], msg: &[u8], sig: &Self::Signature) -> bool {
146        ops::verify_message::<MinPk>(&self.key, namespace, msg, &sig.signature).is_ok()
147    }
148}
149
150/// BLS12-381 public key.
151#[derive(Clone, Eq, PartialEq)]
152pub struct PublicKey {
153    raw: [u8; <MinPk as Variant>::Public::SIZE],
154    key: <MinPk as Variant>::Public,
155}
156
157impl From<PrivateKey> for PublicKey {
158    fn from(private_key: PrivateKey) -> Self {
159        private_key.public_key()
160    }
161}
162
163impl AsRef<<MinPk as Variant>::Public> for PublicKey {
164    fn as_ref(&self) -> &<MinPk as Variant>::Public {
165        &self.key
166    }
167}
168
169impl Write for PublicKey {
170    fn write(&self, buf: &mut impl BufMut) {
171        self.raw.write(buf);
172    }
173}
174
175impl Read for PublicKey {
176    type Cfg = ();
177
178    fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
179        let raw = <[u8; Self::SIZE]>::read(buf)?;
180        let key = <MinPk as Variant>::Public::decode(raw.as_ref())
181            .map_err(|e| CodecError::Wrapped(CURVE_NAME, e.into()))?;
182        Ok(Self { raw, key })
183    }
184}
185
186impl FixedSize for PublicKey {
187    const SIZE: usize = <MinPk as Variant>::Public::SIZE;
188}
189
190impl Span for PublicKey {}
191
192impl Array for PublicKey {}
193
194impl Hash for PublicKey {
195    fn hash<H: Hasher>(&self, state: &mut H) {
196        self.raw.hash(state);
197    }
198}
199
200impl Ord for PublicKey {
201    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
202        self.raw.cmp(&other.raw)
203    }
204}
205
206impl PartialOrd for PublicKey {
207    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
208        Some(self.cmp(other))
209    }
210}
211
212impl AsRef<[u8]> for PublicKey {
213    fn as_ref(&self) -> &[u8] {
214        &self.raw
215    }
216}
217
218impl Deref for PublicKey {
219    type Target = [u8];
220    fn deref(&self) -> &[u8] {
221        &self.raw
222    }
223}
224
225impl From<<MinPk as Variant>::Public> for PublicKey {
226    fn from(key: <MinPk as Variant>::Public) -> Self {
227        let raw = key.encode_fixed();
228        Self { raw, key }
229    }
230}
231
232impl Debug for PublicKey {
233    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
234        write!(f, "{}", hex(&self.raw))
235    }
236}
237
238impl Display for PublicKey {
239    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
240        write!(f, "{}", hex(&self.raw))
241    }
242}
243
244#[cfg(feature = "arbitrary")]
245impl arbitrary::Arbitrary<'_> for PublicKey {
246    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
247        use crate::Signer;
248        use rand::{rngs::StdRng, SeedableRng};
249
250        let mut rand = StdRng::from_seed(u.arbitrary::<[u8; 32]>()?);
251        let private_key = PrivateKey::random(&mut rand);
252        Ok(private_key.public_key())
253    }
254}
255
256/// BLS12-381 signature.
257#[derive(Clone, Eq, PartialEq)]
258pub struct Signature {
259    raw: [u8; <MinPk as Variant>::Signature::SIZE],
260    signature: <MinPk as Variant>::Signature,
261}
262
263impl crate::Signature for Signature {}
264
265impl AsRef<<MinPk as Variant>::Signature> for Signature {
266    fn as_ref(&self) -> &<MinPk as Variant>::Signature {
267        &self.signature
268    }
269}
270
271impl Write for Signature {
272    fn write(&self, buf: &mut impl BufMut) {
273        self.raw.write(buf);
274    }
275}
276
277impl Read for Signature {
278    type Cfg = ();
279
280    fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
281        let raw = <[u8; Self::SIZE]>::read(buf)?;
282        let signature = <MinPk as Variant>::Signature::decode(raw.as_ref())
283            .map_err(|e| CodecError::Wrapped(CURVE_NAME, e.into()))?;
284        Ok(Self { raw, signature })
285    }
286}
287
288impl FixedSize for Signature {
289    const SIZE: usize = <MinPk as Variant>::Signature::SIZE;
290}
291
292impl Span for Signature {}
293
294impl Array for Signature {}
295
296impl Hash for Signature {
297    fn hash<H: Hasher>(&self, state: &mut H) {
298        self.raw.hash(state);
299    }
300}
301
302impl Ord for Signature {
303    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
304        self.raw.cmp(&other.raw)
305    }
306}
307
308impl PartialOrd for Signature {
309    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
310        Some(self.cmp(other))
311    }
312}
313
314impl AsRef<[u8]> for Signature {
315    fn as_ref(&self) -> &[u8] {
316        &self.raw
317    }
318}
319
320impl Deref for Signature {
321    type Target = [u8];
322    fn deref(&self) -> &[u8] {
323        &self.raw
324    }
325}
326
327impl From<<MinPk as Variant>::Signature> for Signature {
328    fn from(signature: <MinPk as Variant>::Signature) -> Self {
329        let raw = signature.encode_fixed();
330        Self { raw, signature }
331    }
332}
333
334impl Debug for Signature {
335    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
336        write!(f, "{}", hex(&self.raw))
337    }
338}
339
340impl Display for Signature {
341    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
342        write!(f, "{}", hex(&self.raw))
343    }
344}
345
346#[cfg(feature = "arbitrary")]
347impl arbitrary::Arbitrary<'_> for Signature {
348    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
349        use crate::Signer;
350        use rand::{rngs::StdRng, SeedableRng};
351
352        let mut rand = StdRng::from_seed(u.arbitrary::<[u8; 32]>()?);
353        let private_key = PrivateKey::random(&mut rand);
354        let len = u.arbitrary::<usize>()? % 256;
355        let message = u
356            .arbitrary_iter()?
357            .take(len)
358            .collect::<Result<Vec<_>, _>>()?;
359
360        Ok(private_key.sign(b"_COMMONWARE_CRYPTOGRAPHY_BLS12381_TEST", &message))
361    }
362}
363
364/// BLS12-381 batch verifier.
365pub struct Batch {
366    publics: Vec<<MinPk as Variant>::Public>,
367    hms: Vec<<MinPk as Variant>::Signature>,
368    signatures: Vec<<MinPk as Variant>::Signature>,
369}
370
371impl BatchVerifier<PublicKey> for Batch {
372    fn new() -> Self {
373        Self {
374            publics: Vec::new(),
375            hms: Vec::new(),
376            signatures: Vec::new(),
377        }
378    }
379
380    fn add(
381        &mut self,
382        namespace: &[u8],
383        message: &[u8],
384        public_key: &PublicKey,
385        signature: &Signature,
386    ) -> bool {
387        self.publics.push(public_key.key);
388        let hm = ops::hash_with_namespace::<MinPk>(MinPk::MESSAGE, namespace, message);
389        self.hms.push(hm);
390        self.signatures.push(signature.signature);
391        true
392    }
393
394    fn verify<R: CryptoRngCore>(self, rng: &mut R) -> bool {
395        MinPk::batch_verify(rng, &self.publics, &self.hms, &self.signatures, &Sequential).is_ok()
396    }
397}
398
399#[cfg(test)]
400mod tests {
401    use super::*;
402    use crate::{bls12381, Verifier as _};
403    use commonware_codec::{DecodeExt, Encode};
404    use commonware_math::algebra::Random;
405    use commonware_utils::test_rng;
406
407    #[test]
408    fn test_codec_private_key() {
409        let original =
410            parse_private_key("0x263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e3")
411                .unwrap();
412        let encoded = original.encode();
413        assert_eq!(encoded.len(), bls12381::PrivateKey::SIZE);
414        let decoded = bls12381::PrivateKey::decode(encoded).unwrap();
415        assert_eq!(original, decoded);
416    }
417
418    #[test]
419    fn test_codec_public_key() {
420        let original =
421            parse_public_key("0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a")
422            .unwrap();
423        let encoded = original.encode();
424        assert_eq!(encoded.len(), PublicKey::SIZE);
425        let decoded = PublicKey::decode(encoded).unwrap();
426        assert_eq!(original, decoded);
427    }
428
429    #[test]
430    fn test_codec_signature() {
431        let original =
432            parse_signature("0x882730e5d03f6b42c3abc26d3372625034e1d871b65a8a6b900a56dae22da98abbe1b68f85e49fe7652a55ec3d0591c20767677e33e5cbb1207315c41a9ac03be39c2e7668edc043d6cb1d9fd93033caa8a1c5b0e84bedaeb6c64972503a43eb")
433            .unwrap();
434        let encoded = original.encode();
435        assert_eq!(encoded.len(), Signature::SIZE);
436        let decoded = Signature::decode(encoded).unwrap();
437        assert_eq!(original, decoded);
438    }
439
440    fn parse_private_key(private_key: &str) -> Result<PrivateKey, CodecError> {
441        PrivateKey::decode(
442            commonware_utils::from_hex_formatted(private_key)
443                .unwrap()
444                .as_ref(),
445        )
446    }
447
448    fn parse_public_key(public_key: &str) -> Result<PublicKey, CodecError> {
449        PublicKey::decode(
450            commonware_utils::from_hex_formatted(public_key)
451                .unwrap()
452                .as_ref(),
453        )
454    }
455
456    fn parse_signature(signature: &str) -> Result<Signature, CodecError> {
457        Signature::decode(
458            commonware_utils::from_hex_formatted(signature)
459                .unwrap()
460                .as_ref(),
461        )
462    }
463
464    #[test]
465    fn test_from_private() {
466        let mut rng = test_rng();
467        let private = Private::random(&mut rng);
468        let private_key = PrivateKey::from(private);
469        // Verify the key works by signing and verifying
470        let msg = b"test message";
471        let sig = private_key.sign(b"ns", msg);
472        assert!(private_key.public_key().verify(b"ns", msg, &sig));
473    }
474
475    #[test]
476    fn test_private_key_redacted() {
477        let mut rng = test_rng();
478        let private_key = PrivateKey::random(&mut rng);
479        let debug = format!("{:?}", private_key);
480        let display = format!("{}", private_key);
481        assert!(debug.contains("REDACTED"));
482        assert!(display.contains("REDACTED"));
483    }
484
485    #[cfg(feature = "arbitrary")]
486    mod conformance {
487        use super::*;
488        use commonware_codec::conformance::CodecConformance;
489
490        commonware_conformance::conformance_tests! {
491            CodecConformance<PublicKey>,
492            CodecConformance<PrivateKey>,
493            CodecConformance<Signature>,
494        }
495    }
496}