1use super::primitives::{
31 group::{self, Private},
32 ops,
33 variant::{MinPk, Variant},
34};
35use crate::{BatchEntry, BatchVerifier, Secret, Signer as _};
36#[cfg(not(feature = "std"))]
37use alloc::vec::Vec;
38use bytes::BufMut;
39use commonware_codec::{
40 Buf, Copying, DecodeExt, EncodeFixed, Error as CodecError, FixedArray, FixedSize, Read,
41 ReadExt, Write,
42};
43use commonware_formatting::Hex;
44use commonware_math::algebra::Random;
45use commonware_parallel::Strategy;
46use commonware_utils::{Array, Span};
47use core::{
48 fmt::{Debug, Display, Formatter},
49 hash::{Hash, Hasher},
50 ops::Deref,
51};
52use rand_core::CryptoRng;
53use zeroize::Zeroizing;
54
55const CURVE_NAME: &str = "bls12381";
56
57#[derive(Clone, Debug)]
59pub struct PrivateKey {
60 raw: Secret<[u8; group::PRIVATE_KEY_LENGTH]>,
61 key: Private,
62}
63
64impl PartialEq for PrivateKey {
65 fn eq(&self, other: &Self) -> bool {
66 self.raw == other.raw
67 }
68}
69
70impl Eq for PrivateKey {}
71
72impl Write for PrivateKey {
73 fn write(&self, buf: &mut impl BufMut) {
74 self.raw.expose(|raw| raw.write(buf));
75 }
76}
77
78impl Read for PrivateKey {
79 type Cfg = ();
80
81 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
82 let raw = Zeroizing::new(<[u8; Self::SIZE]>::read(buf)?);
83 let key = Private::decode(Copying(raw.as_ref()))
84 .map_err(|e| CodecError::Wrapped(CURVE_NAME, e.into()))?;
85 Ok(Self {
86 raw: Secret::new(*raw),
87 key,
88 })
89 }
90}
91
92impl FixedSize for PrivateKey {
93 const SIZE: usize = group::PRIVATE_KEY_LENGTH;
94}
95
96impl From<Private> for PrivateKey {
97 fn from(key: Private) -> Self {
98 let raw = Zeroizing::new(key.expose(|s| s.encode_fixed()));
99 Self {
100 raw: Secret::new(*raw),
101 key,
102 }
103 }
104}
105
106impl Display for PrivateKey {
107 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
108 write!(f, "{:?}", self)
109 }
110}
111
112impl crate::PrivateKey for PrivateKey {}
113
114impl crate::Signer for PrivateKey {
115 type Signature = Signature;
116 type PublicKey = PublicKey;
117
118 fn public_key(&self) -> Self::PublicKey {
119 PublicKey::from(ops::compute_public::<MinPk>(&self.key))
120 }
121
122 fn sign(&self, namespace: &[u8], msg: &[u8]) -> Self::Signature {
123 ops::sign_message::<MinPk>(&self.key, namespace, msg).into()
124 }
125}
126
127impl Random for PrivateKey {
128 fn random(mut rng: impl CryptoRng) -> Self {
129 let (private, _) = ops::keypair::<_, MinPk>(&mut rng);
130 private.into()
131 }
132}
133
134#[cfg(feature = "arbitrary")]
135impl arbitrary::Arbitrary<'_> for PrivateKey {
136 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
137 use rand::{SeedableRng, rngs::StdRng};
138
139 let mut rand = StdRng::from_seed(u.arbitrary::<[u8; 32]>()?);
140 Ok(Self::random(&mut rand))
141 }
142}
143
144impl crate::PublicKey for PublicKey {}
145
146impl crate::Verifier for PublicKey {
147 type Signature = Signature;
148
149 fn verify(&self, namespace: &[u8], msg: &[u8], sig: &Self::Signature) -> bool {
150 ops::verify_message::<MinPk>(&self.key, namespace, msg, &sig.signature).is_ok()
151 }
152}
153
154impl BatchVerifier for PublicKey {
155 fn verify_batch<'a, R, T, F>(
156 rng: &mut R,
157 items: &'a [T],
158 project: F,
159 strategy: &impl Strategy,
160 ) -> bool
161 where
162 R: CryptoRng,
163 T: Sync,
164 F: Fn(usize, &'a T) -> BatchEntry<'a, Self> + Sync,
165 {
166 let hms = strategy.map_collect_vec(items.iter().enumerate(), |(index, item)| {
167 let entry = project(index, item);
168 ops::hash_with_namespace::<MinPk>(MinPk::MESSAGE, entry.namespace, entry.message)
169 });
170 let (publics, signatures): (Vec<_>, Vec<_>) = items
171 .iter()
172 .enumerate()
173 .map(|(index, item)| {
174 let entry = project(index, item);
175 (entry.public_key.key, entry.signature.signature)
176 })
177 .unzip();
178
179 MinPk::batch_verify(rng, &publics, &hms, &signatures, strategy).is_ok()
180 }
181}
182
183#[derive(Clone, Eq, FixedArray)]
185pub struct PublicKey {
186 raw: [u8; <MinPk as Variant>::Public::SIZE],
187 key: <MinPk as Variant>::Public,
188}
189
190impl PartialEq for PublicKey {
191 fn eq(&self, other: &Self) -> bool {
192 self.raw == other.raw
193 }
194}
195
196impl From<PrivateKey> for PublicKey {
197 fn from(private_key: PrivateKey) -> Self {
198 private_key.public_key()
199 }
200}
201
202impl AsRef<<MinPk as Variant>::Public> for PublicKey {
203 fn as_ref(&self) -> &<MinPk as Variant>::Public {
204 &self.key
205 }
206}
207
208impl Write for PublicKey {
209 fn write(&self, buf: &mut impl BufMut) {
210 self.raw.write(buf);
211 }
212}
213
214impl Read for PublicKey {
215 type Cfg = ();
216
217 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
218 let raw = <[u8; Self::SIZE]>::read(buf)?;
219 let key = <MinPk as Variant>::Public::decode(Copying(&raw))
220 .map_err(|e| CodecError::Wrapped(CURVE_NAME, e.into()))?;
221 Ok(Self { raw, key })
222 }
223}
224
225impl FixedSize for PublicKey {
226 const SIZE: usize = <MinPk as Variant>::Public::SIZE;
227}
228
229impl Span for PublicKey {}
230
231impl Array for PublicKey {}
232
233impl Hash for PublicKey {
234 fn hash<H: Hasher>(&self, state: &mut H) {
235 self.raw.hash(state);
236 }
237}
238
239impl Ord for PublicKey {
240 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
241 self.raw.cmp(&other.raw)
242 }
243}
244
245impl PartialOrd for PublicKey {
246 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
247 Some(self.cmp(other))
248 }
249}
250
251impl AsRef<[u8]> for PublicKey {
252 fn as_ref(&self) -> &[u8] {
253 &self.raw
254 }
255}
256
257impl Deref for PublicKey {
258 type Target = [u8];
259 fn deref(&self) -> &[u8] {
260 &self.raw
261 }
262}
263
264impl From<<MinPk as Variant>::Public> for PublicKey {
265 fn from(key: <MinPk as Variant>::Public) -> Self {
266 let raw = key.encode_fixed();
267 Self { raw, key }
268 }
269}
270
271impl Debug for PublicKey {
272 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
273 write!(f, "{}", Hex(&self.raw))
274 }
275}
276
277impl Display for PublicKey {
278 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
279 write!(f, "{}", Hex(&self.raw))
280 }
281}
282
283#[cfg(feature = "arbitrary")]
284impl arbitrary::Arbitrary<'_> for PublicKey {
285 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
286 use crate::Signer;
287 use rand::{SeedableRng, rngs::StdRng};
288
289 let mut rand = StdRng::from_seed(u.arbitrary::<[u8; 32]>()?);
290 let private_key = PrivateKey::random(&mut rand);
291 Ok(private_key.public_key())
292 }
293}
294
295#[derive(Clone, Eq, PartialEq, FixedArray)]
297pub struct Signature {
298 raw: [u8; <MinPk as Variant>::Signature::SIZE],
299 signature: <MinPk as Variant>::Signature,
300}
301
302impl crate::Signature for Signature {}
303
304impl AsRef<<MinPk as Variant>::Signature> for Signature {
305 fn as_ref(&self) -> &<MinPk as Variant>::Signature {
306 &self.signature
307 }
308}
309
310impl Write for Signature {
311 fn write(&self, buf: &mut impl BufMut) {
312 self.raw.write(buf);
313 }
314}
315
316impl Read for Signature {
317 type Cfg = ();
318
319 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
320 let raw = <[u8; Self::SIZE]>::read(buf)?;
321 let signature = <MinPk as Variant>::Signature::decode(Copying(&raw))
322 .map_err(|e| CodecError::Wrapped(CURVE_NAME, e.into()))?;
323 Ok(Self { raw, signature })
324 }
325}
326
327impl FixedSize for Signature {
328 const SIZE: usize = <MinPk as Variant>::Signature::SIZE;
329}
330
331impl Span for Signature {}
332
333impl Array for Signature {}
334
335impl Hash for Signature {
336 fn hash<H: Hasher>(&self, state: &mut H) {
337 self.raw.hash(state);
338 }
339}
340
341impl Ord for Signature {
342 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
343 self.raw.cmp(&other.raw)
344 }
345}
346
347impl PartialOrd for Signature {
348 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
349 Some(self.cmp(other))
350 }
351}
352
353impl AsRef<[u8]> for Signature {
354 fn as_ref(&self) -> &[u8] {
355 &self.raw
356 }
357}
358
359impl Deref for Signature {
360 type Target = [u8];
361 fn deref(&self) -> &[u8] {
362 &self.raw
363 }
364}
365
366impl From<<MinPk as Variant>::Signature> for Signature {
367 fn from(signature: <MinPk as Variant>::Signature) -> Self {
368 let raw = signature.encode_fixed();
369 Self { raw, signature }
370 }
371}
372
373impl Debug for Signature {
374 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
375 write!(f, "{}", Hex(&self.raw))
376 }
377}
378
379impl Display for Signature {
380 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
381 write!(f, "{}", Hex(&self.raw))
382 }
383}
384
385#[cfg(feature = "arbitrary")]
386impl arbitrary::Arbitrary<'_> for Signature {
387 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
388 use crate::Signer;
389 use rand::{SeedableRng, rngs::StdRng};
390
391 let mut rand = StdRng::from_seed(u.arbitrary::<[u8; 32]>()?);
392 let private_key = PrivateKey::random(&mut rand);
393 let len = u.arbitrary::<usize>()? % 256;
394 let message = u
395 .arbitrary_iter()?
396 .take(len)
397 .collect::<Result<Vec<_>, _>>()?;
398
399 Ok(private_key.sign(b"_COMMONWARE_CRYPTOGRAPHY_BLS12381_TEST", &message))
400 }
401}
402
403#[cfg(test)]
404mod tests {
405 use super::*;
406 use crate::{Verifier as _, bls12381};
407 use commonware_codec::{DecodeExt, Encode};
408 use commonware_math::algebra::Random;
409 use commonware_parallel::{Sequential, mocks::explore};
410 use commonware_utils::test_rng;
411
412 #[test]
413 fn test_codec_private_key() {
414 let original =
415 parse_private_key("0x263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e3")
416 .unwrap();
417 let encoded = original.encode();
418 assert_eq!(encoded.len(), bls12381::PrivateKey::SIZE);
419 let decoded = bls12381::PrivateKey::decode(encoded).unwrap();
420 assert_eq!(original, decoded);
421 }
422
423 #[test]
424 fn test_codec_public_key() {
425 let original =
426 parse_public_key("0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a")
427 .unwrap();
428 let encoded = original.encode();
429 assert_eq!(encoded.len(), PublicKey::SIZE);
430 let decoded = PublicKey::decode(encoded).unwrap();
431 assert_eq!(original, decoded);
432 }
433
434 #[test]
435 fn test_codec_signature() {
436 let original =
437 parse_signature("0x882730e5d03f6b42c3abc26d3372625034e1d871b65a8a6b900a56dae22da98abbe1b68f85e49fe7652a55ec3d0591c20767677e33e5cbb1207315c41a9ac03be39c2e7668edc043d6cb1d9fd93033caa8a1c5b0e84bedaeb6c64972503a43eb")
438 .unwrap();
439 let encoded = original.encode();
440 assert_eq!(encoded.len(), Signature::SIZE);
441 let decoded = Signature::decode(encoded).unwrap();
442 assert_eq!(original, decoded);
443 }
444
445 fn parse_private_key(private_key: &str) -> Result<PrivateKey, CodecError> {
446 PrivateKey::decode(commonware_formatting::from_hex(private_key).unwrap())
447 }
448
449 fn parse_public_key(public_key: &str) -> Result<PublicKey, CodecError> {
450 PublicKey::decode(commonware_formatting::from_hex(public_key).unwrap())
451 }
452
453 fn parse_signature(signature: &str) -> Result<Signature, CodecError> {
454 Signature::decode(commonware_formatting::from_hex(signature).unwrap())
455 }
456
457 #[test]
458 fn test_from_private() {
459 let mut rng = test_rng();
460 let private = Private::random(&mut rng);
461 let private_key = PrivateKey::from(private);
462 let msg = b"test message";
464 let sig = private_key.sign(b"ns", msg);
465 assert!(private_key.public_key().verify(b"ns", msg, &sig));
466 }
467
468 #[test]
469 fn test_private_key_redacted() {
470 let mut rng = test_rng();
471 let private_key = PrivateKey::random(&mut rng);
472 let debug = format!("{:?}", private_key);
473 let display = format!("{}", private_key);
474 assert!(debug.contains("REDACTED"));
475 assert!(display.contains("REDACTED"));
476 }
477
478 #[test]
479 fn batch_verify_empty() {
480 let entries: [BatchEntry<'_, PublicKey>; 0] = [];
481 assert!(!PublicKey::verify_batch(
482 &mut test_rng(),
483 &entries,
484 |_, entry| *entry,
485 &Sequential,
486 ));
487 }
488
489 #[test]
490 fn batch_verify_invalid_message() {
491 let mut rng = test_rng();
493 let private_key = PrivateKey::random(&mut rng);
494 let public_key = private_key.public_key();
495 let signature = private_key.sign(b"ns", b"message");
496 let mut entries = [BatchEntry {
497 namespace: b"ns",
498 message: b"message",
499 public_key: &public_key,
500 signature: &signature,
501 }];
502 assert!(PublicKey::verify_batch(
503 &mut rng,
504 &entries,
505 |_, entry| *entry,
506 &Sequential,
507 ));
508
509 entries[0].message = b"invalid";
511 assert!(!PublicKey::verify_batch(
512 &mut rng,
513 &entries,
514 |_, entry| *entry,
515 &Sequential,
516 ));
517 }
518
519 #[test]
520 fn projected_batch_indexes_zero_sized_items() {
521 struct Batch {
522 namespaces: Vec<&'static [u8]>,
523 messages: Vec<Vec<u8>>,
524 signers: Vec<usize>,
525 public_keys: Vec<PublicKey>,
526 signatures: Vec<Signature>,
527 }
528
529 impl Batch {
530 fn verify(&self, strategy: &impl Strategy) -> bool {
531 let items = vec![(); self.messages.len()];
532 PublicKey::verify_batch(
533 &mut test_rng(),
534 &items,
535 |index, ()| BatchEntry {
536 namespace: self.namespaces[index],
537 message: &self.messages[index],
538 public_key: &self.public_keys[self.signers[index]],
539 signature: &self.signatures[index],
540 },
541 strategy,
542 )
543 }
544 }
545
546 let mut rng = test_rng();
549 let keys: Vec<_> = (0..3).map(|_| PrivateKey::random(&mut rng)).collect();
550 let namespaces: Vec<&'static [u8]> = (0..9)
551 .map(|i| [b"".as_slice(), b"alpha", b"beta"][(i / 3) % 3])
552 .collect();
553 let messages: Vec<_> = (0..9).map(|i| vec![i as u8; i * 7]).collect();
554 let signers: Vec<_> = (0..9).map(|i| i % keys.len()).collect();
555 let signatures = (0..9)
556 .map(|i| keys[signers[i]].sign(namespaces[i], &messages[i]))
557 .collect();
558 let mut batch = Batch {
559 namespaces,
560 messages,
561 signers,
562 public_keys: keys.iter().map(|key| key.public_key()).collect(),
563 signatures,
564 };
565
566 let check = |batch: &Batch, expected: bool| {
568 assert_eq!(explore(|strategy| batch.verify(strategy)), expected);
569 };
570 check(&batch, true);
571
572 for index in 0..batch.messages.len() {
574 batch.messages[index].push(0);
575 check(&batch, false);
576 batch.messages[index].pop();
577
578 let namespace = core::mem::replace(&mut batch.namespaces[index], b"other");
579 check(&batch, false);
580 batch.namespaces[index] = namespace;
581
582 let signer = batch.signers[index];
583 batch.signers[index] = (signer + 1) % keys.len();
584 check(&batch, false);
585 batch.signers[index] = signer;
586 }
587
588 check(&batch, true);
590 }
591
592 #[cfg(feature = "arbitrary")]
593 mod conformance {
594 use super::*;
595 use commonware_codec::conformance::CodecConformance;
596
597 commonware_conformance::conformance_tests! {
598 CodecConformance<PublicKey>,
599 CodecConformance<PrivateKey>,
600 CodecConformance<Signature>,
601 }
602 }
603}