Skip to main content

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