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