commonware_cryptography/bls12381/
scheme.rs1use 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#[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#[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#[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
365pub 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 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}