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