Skip to main content

aptos_sdk/crypto/
bls12381.rs

1//! BLS12-381 signature scheme implementation.
2//!
3//! BLS signatures support aggregation, which is used for validator
4//! consensus signatures on Aptos.
5
6use crate::crypto::traits::{PublicKey, Signature, Signer, Verifier};
7use crate::error::{AptosError, AptosResult};
8use blst::BLST_ERROR;
9use blst::min_pk::{PublicKey as BlstPublicKey, SecretKey, Signature as BlstSignature};
10use rand::RngCore;
11use serde::{Deserialize, Serialize};
12use std::fmt;
13use zeroize::Zeroize;
14
15/// BLS12-381 private key length in bytes.
16pub const BLS12381_PRIVATE_KEY_LENGTH: usize = 32;
17/// BLS12-381 public key length in bytes (compressed).
18pub const BLS12381_PUBLIC_KEY_LENGTH: usize = 48;
19/// BLS12-381 signature length in bytes (compressed).
20pub const BLS12381_SIGNATURE_LENGTH: usize = 96;
21/// BLS12-381 proof of possession length in bytes.
22pub const BLS12381_POP_LENGTH: usize = 96;
23
24/// The domain separation tag for BLS signatures in Aptos.
25const DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";
26/// The domain separation tag for BLS proof of possession.
27const DST_POP: &[u8] = b"BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";
28
29/// A BLS12-381 private key.
30#[derive(Clone, Zeroize)]
31#[zeroize(drop)]
32pub struct Bls12381PrivateKey {
33    #[zeroize(skip)]
34    #[allow(unused)] // Field is used; lint false positive from Zeroize derive
35    inner: SecretKey,
36}
37
38impl Bls12381PrivateKey {
39    /// Generates a new random BLS12-381 private key.
40    ///
41    /// # Panics
42    ///
43    /// This function will not panic in normal operation. The internal `expect`
44    /// is a defensive check for the blst library's key generation, which only
45    /// fails if the input keying material (IKM) is less than 32 bytes. Since
46    /// we always provide exactly 32 bytes of random data, this cannot fail.
47    pub fn generate() -> Self {
48        let mut ikm = [0u8; 32];
49        rand::rngs::OsRng.fill_bytes(&mut ikm);
50        // SAFETY: key_gen only fails if IKM is < 32 bytes. We provide exactly 32.
51        let secret_key = SecretKey::key_gen(&ikm, &[])
52            .expect("internal error: BLS key generation failed with 32-byte IKM");
53        Self { inner: secret_key }
54    }
55
56    /// Creates a private key from a 32-byte seed.
57    ///
58    /// This uses the BLS key derivation function to derive a key from the seed.
59    ///
60    /// # Errors
61    ///
62    /// Returns an error if the seed is less than 32 bytes or if key derivation fails.
63    pub fn from_seed(seed: &[u8]) -> AptosResult<Self> {
64        if seed.len() < 32 {
65            return Err(AptosError::InvalidPrivateKey(
66                "seed must be at least 32 bytes".to_string(),
67            ));
68        }
69        let secret_key = SecretKey::key_gen(seed, &[])
70            .map_err(|e| AptosError::InvalidPrivateKey(format!("{e:?}")))?;
71        Ok(Self { inner: secret_key })
72    }
73
74    /// Creates a private key from raw bytes.
75    ///
76    /// # Errors
77    ///
78    /// Returns an error if the bytes length is not 32 bytes or if the key deserialization fails.
79    pub fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
80        if bytes.len() != BLS12381_PRIVATE_KEY_LENGTH {
81            return Err(AptosError::InvalidPrivateKey(format!(
82                "expected {} bytes, got {}",
83                BLS12381_PRIVATE_KEY_LENGTH,
84                bytes.len()
85            )));
86        }
87        let secret_key = SecretKey::from_bytes(bytes)
88            .map_err(|e| AptosError::InvalidPrivateKey(format!("{e:?}")))?;
89        Ok(Self { inner: secret_key })
90    }
91
92    /// Creates a private key from a hex string.
93    ///
94    /// # Errors
95    ///
96    /// Returns an error if hex decoding fails or if the resulting bytes are invalid.
97    pub fn from_hex(hex_str: &str) -> AptosResult<Self> {
98        let bytes = const_hex::decode(hex_str)?;
99        Self::from_bytes(&bytes)
100    }
101
102    /// Returns the private key as bytes.
103    pub fn to_bytes(&self) -> [u8; BLS12381_PRIVATE_KEY_LENGTH] {
104        self.inner.to_bytes()
105    }
106
107    /// Returns the private key as a hex string.
108    pub fn to_hex(&self) -> String {
109        const_hex::encode_prefixed(self.inner.to_bytes())
110    }
111
112    /// Returns the corresponding public key.
113    pub fn public_key(&self) -> Bls12381PublicKey {
114        Bls12381PublicKey {
115            inner: self.inner.sk_to_pk(),
116        }
117    }
118
119    /// Signs a message and returns the signature.
120    pub fn sign(&self, message: &[u8]) -> Bls12381Signature {
121        let signature = self.inner.sign(message, DST, &[]);
122        Bls12381Signature { inner: signature }
123    }
124
125    /// Creates a proof of possession for this key pair.
126    ///
127    /// A proof of possession (`PoP`) proves ownership of the private key
128    /// and prevents rogue key attacks in aggregate signature schemes.
129    pub fn create_proof_of_possession(&self) -> Bls12381ProofOfPossession {
130        let pk = self.public_key();
131        let pk_bytes = pk.to_bytes();
132        let pop = self.inner.sign(&pk_bytes, DST_POP, &[]);
133        Bls12381ProofOfPossession { inner: pop }
134    }
135}
136
137impl Signer for Bls12381PrivateKey {
138    type Signature = Bls12381Signature;
139
140    fn sign(&self, message: &[u8]) -> Bls12381Signature {
141        Bls12381PrivateKey::sign(self, message)
142    }
143
144    fn public_key(&self) -> Bls12381PublicKey {
145        Bls12381PrivateKey::public_key(self)
146    }
147}
148
149impl fmt::Debug for Bls12381PrivateKey {
150    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151        write!(f, "Bls12381PrivateKey([REDACTED])")
152    }
153}
154
155/// A BLS12-381 public key.
156#[derive(Clone, PartialEq, Eq)]
157pub struct Bls12381PublicKey {
158    inner: BlstPublicKey,
159}
160
161impl Bls12381PublicKey {
162    /// Creates a public key from compressed bytes (48 bytes).
163    ///
164    /// # Errors
165    ///
166    /// Returns an error if the bytes length is not 48 bytes or if the key deserialization fails.
167    pub fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
168        if bytes.len() != BLS12381_PUBLIC_KEY_LENGTH {
169            return Err(AptosError::InvalidPublicKey(format!(
170                "expected {} bytes, got {}",
171                BLS12381_PUBLIC_KEY_LENGTH,
172                bytes.len()
173            )));
174        }
175        let public_key = BlstPublicKey::from_bytes(bytes)
176            .map_err(|e| AptosError::InvalidPublicKey(format!("{e:?}")))?;
177        Ok(Self { inner: public_key })
178    }
179
180    /// Creates a public key from a hex string.
181    ///
182    /// # Errors
183    ///
184    /// Returns an error if hex decoding fails or if the resulting bytes are invalid.
185    pub fn from_hex(hex_str: &str) -> AptosResult<Self> {
186        let bytes = const_hex::decode(hex_str)?;
187        Self::from_bytes(&bytes)
188    }
189
190    /// Returns the public key as compressed bytes (48 bytes).
191    pub fn to_bytes(&self) -> Vec<u8> {
192        self.inner.compress().to_vec()
193    }
194
195    /// Returns the public key as a hex string.
196    pub fn to_hex(&self) -> String {
197        const_hex::encode_prefixed(self.inner.compress())
198    }
199
200    /// Verifies a signature against a message.
201    ///
202    /// # Errors
203    ///
204    /// Returns an error if signature verification fails.
205    pub fn verify(&self, message: &[u8], signature: &Bls12381Signature) -> AptosResult<()> {
206        let result = signature
207            .inner
208            .verify(true, message, DST, &[], &self.inner, true);
209        if result == BLST_ERROR::BLST_SUCCESS {
210            Ok(())
211        } else {
212            Err(AptosError::SignatureVerificationFailed)
213        }
214    }
215}
216
217impl Bls12381PublicKey {
218    /// Aggregates multiple public keys into a single aggregated public key.
219    ///
220    /// The aggregated public key can be used to verify an aggregated signature.
221    ///
222    /// WARNING: This assumes all public keys have had their proofs-of-possession verified.
223    ///
224    /// # Errors
225    ///
226    /// Returns an error if the list of public keys is empty or if aggregation fails.
227    pub fn aggregate(public_keys: &[&Bls12381PublicKey]) -> AptosResult<Bls12381PublicKey> {
228        if public_keys.is_empty() {
229            return Err(AptosError::InvalidPublicKey(
230                "cannot aggregate empty list of public keys".to_string(),
231            ));
232        }
233        let blst_pks: Vec<&BlstPublicKey> = public_keys.iter().map(|pk| &pk.inner).collect();
234        let agg_pk = blst::min_pk::AggregatePublicKey::aggregate(&blst_pks, false)
235            .map_err(|e| AptosError::InvalidPublicKey(format!("{e:?}")))?;
236        Ok(Bls12381PublicKey {
237            inner: agg_pk.to_public_key(),
238        })
239    }
240}
241
242impl PublicKey for Bls12381PublicKey {
243    const LENGTH: usize = BLS12381_PUBLIC_KEY_LENGTH;
244
245    /// Creates a public key from compressed bytes (48 bytes).
246    ///
247    /// # Errors
248    ///
249    /// Returns an error if the bytes length is not 48 bytes or if the key deserialization fails.
250    fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
251        Bls12381PublicKey::from_bytes(bytes)
252    }
253
254    fn to_bytes(&self) -> Vec<u8> {
255        Bls12381PublicKey::to_bytes(self)
256    }
257}
258
259impl Verifier for Bls12381PublicKey {
260    type Signature = Bls12381Signature;
261
262    /// Verifies a signature against a message.
263    ///
264    /// # Errors
265    ///
266    /// Returns an error if signature verification fails.
267    fn verify(&self, message: &[u8], signature: &Bls12381Signature) -> AptosResult<()> {
268        Bls12381PublicKey::verify(self, message, signature)
269    }
270}
271
272impl fmt::Debug for Bls12381PublicKey {
273    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274        write!(f, "Bls12381PublicKey({})", self.to_hex())
275    }
276}
277
278impl fmt::Display for Bls12381PublicKey {
279    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280        write!(f, "{}", self.to_hex())
281    }
282}
283
284impl Serialize for Bls12381PublicKey {
285    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
286    where
287        S: serde::Serializer,
288    {
289        if serializer.is_human_readable() {
290            serializer.serialize_str(&self.to_hex())
291        } else {
292            serializer.serialize_bytes(&self.to_bytes())
293        }
294    }
295}
296
297impl<'de> Deserialize<'de> for Bls12381PublicKey {
298    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
299    where
300        D: serde::Deserializer<'de>,
301    {
302        if deserializer.is_human_readable() {
303            let s = String::deserialize(deserializer)?;
304            Self::from_hex(&s).map_err(serde::de::Error::custom)
305        } else {
306            let bytes = Vec::<u8>::deserialize(deserializer)?;
307            Self::from_bytes(&bytes).map_err(serde::de::Error::custom)
308        }
309    }
310}
311
312/// A BLS12-381 signature.
313#[derive(Clone, PartialEq, Eq)]
314pub struct Bls12381Signature {
315    inner: BlstSignature,
316}
317
318impl Bls12381Signature {
319    /// Creates a signature from compressed bytes (96 bytes).
320    ///
321    /// # Errors
322    ///
323    /// Returns an error if the bytes length is not 96 bytes or if the signature deserialization fails.
324    pub fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
325        if bytes.len() != BLS12381_SIGNATURE_LENGTH {
326            return Err(AptosError::InvalidSignature(format!(
327                "expected {} bytes, got {}",
328                BLS12381_SIGNATURE_LENGTH,
329                bytes.len()
330            )));
331        }
332        let signature = BlstSignature::from_bytes(bytes)
333            .map_err(|e| AptosError::InvalidSignature(format!("{e:?}")))?;
334        Ok(Self { inner: signature })
335    }
336
337    /// Creates a signature from a hex string.
338    ///
339    /// # Errors
340    ///
341    /// Returns an error if hex decoding fails or if the resulting bytes are invalid.
342    pub fn from_hex(hex_str: &str) -> AptosResult<Self> {
343        let bytes = const_hex::decode(hex_str)?;
344        Self::from_bytes(&bytes)
345    }
346
347    /// Returns the signature as compressed bytes (96 bytes).
348    pub fn to_bytes(&self) -> Vec<u8> {
349        self.inner.compress().to_vec()
350    }
351
352    /// Returns the signature as a hex string.
353    pub fn to_hex(&self) -> String {
354        const_hex::encode_prefixed(self.inner.compress())
355    }
356}
357
358impl Bls12381Signature {
359    /// Aggregates multiple signatures into a single aggregated signature.
360    ///
361    /// The aggregated signature can be verified against an aggregated public key
362    /// for the same message, or against individual public keys for different messages.
363    ///
364    /// # Errors
365    ///
366    /// Returns an error if the list of signatures is empty or if aggregation fails.
367    pub fn aggregate(signatures: &[&Bls12381Signature]) -> AptosResult<Bls12381Signature> {
368        if signatures.is_empty() {
369            return Err(AptosError::InvalidSignature(
370                "cannot aggregate empty list of signatures".to_string(),
371            ));
372        }
373        let blst_sigs: Vec<&BlstSignature> = signatures.iter().map(|s| &s.inner).collect();
374        let agg_sig = blst::min_pk::AggregateSignature::aggregate(&blst_sigs, false)
375            .map_err(|e| AptosError::InvalidSignature(format!("{e:?}")))?;
376        Ok(Bls12381Signature {
377            inner: agg_sig.to_signature(),
378        })
379    }
380}
381
382impl Signature for Bls12381Signature {
383    type PublicKey = Bls12381PublicKey;
384    const LENGTH: usize = BLS12381_SIGNATURE_LENGTH;
385
386    /// Creates a signature from compressed bytes (96 bytes).
387    ///
388    /// # Errors
389    ///
390    /// Returns an error if the bytes length is not 96 bytes or if the signature deserialization fails.
391    fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
392        Bls12381Signature::from_bytes(bytes)
393    }
394
395    fn to_bytes(&self) -> Vec<u8> {
396        Bls12381Signature::to_bytes(self)
397    }
398}
399
400impl fmt::Debug for Bls12381Signature {
401    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
402        write!(f, "Bls12381Signature({})", self.to_hex())
403    }
404}
405
406impl fmt::Display for Bls12381Signature {
407    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
408        write!(f, "{}", self.to_hex())
409    }
410}
411
412impl Serialize for Bls12381Signature {
413    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
414    where
415        S: serde::Serializer,
416    {
417        if serializer.is_human_readable() {
418            serializer.serialize_str(&self.to_hex())
419        } else {
420            serializer.serialize_bytes(&self.to_bytes())
421        }
422    }
423}
424
425impl<'de> Deserialize<'de> for Bls12381Signature {
426    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
427    where
428        D: serde::Deserializer<'de>,
429    {
430        if deserializer.is_human_readable() {
431            let s = String::deserialize(deserializer)?;
432            Self::from_hex(&s).map_err(serde::de::Error::custom)
433        } else {
434            let bytes = Vec::<u8>::deserialize(deserializer)?;
435            Self::from_bytes(&bytes).map_err(serde::de::Error::custom)
436        }
437    }
438}
439
440/// A BLS12-381 proof of possession.
441///
442/// A proof of possession (`PoP`) proves ownership of the private key corresponding
443/// to a public key. This prevents rogue key attacks in aggregate signature schemes.
444#[derive(Clone, PartialEq, Eq)]
445pub struct Bls12381ProofOfPossession {
446    inner: BlstSignature,
447}
448
449impl Bls12381ProofOfPossession {
450    /// Creates a proof of possession from compressed bytes (96 bytes).
451    ///
452    /// # Errors
453    ///
454    /// Returns an error if the bytes length is not 96 bytes or if the proof of possession deserialization fails.
455    pub fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
456        if bytes.len() != BLS12381_POP_LENGTH {
457            return Err(AptosError::InvalidSignature(format!(
458                "expected {} bytes, got {}",
459                BLS12381_POP_LENGTH,
460                bytes.len()
461            )));
462        }
463        let pop = BlstSignature::from_bytes(bytes)
464            .map_err(|e| AptosError::InvalidSignature(format!("{e:?}")))?;
465        Ok(Self { inner: pop })
466    }
467
468    /// Creates a proof of possession from a hex string.
469    ///
470    /// # Errors
471    ///
472    /// Returns an error if hex decoding fails or if the resulting bytes are invalid.
473    pub fn from_hex(hex_str: &str) -> AptosResult<Self> {
474        let bytes = const_hex::decode(hex_str)?;
475        Self::from_bytes(&bytes)
476    }
477
478    /// Returns the proof of possession as compressed bytes (96 bytes).
479    pub fn to_bytes(&self) -> Vec<u8> {
480        self.inner.compress().to_vec()
481    }
482
483    /// Returns the proof of possession as a hex string.
484    pub fn to_hex(&self) -> String {
485        const_hex::encode_prefixed(self.inner.compress())
486    }
487
488    /// Verifies this proof of possession against a public key.
489    ///
490    /// Returns Ok(()) if the `PoP` is valid, or an error if invalid.
491    ///
492    /// # Errors
493    ///
494    /// Returns an error if proof of possession verification fails.
495    pub fn verify(&self, public_key: &Bls12381PublicKey) -> AptosResult<()> {
496        let pk_bytes = public_key.to_bytes();
497        let result = self
498            .inner
499            .verify(true, &pk_bytes, DST_POP, &[], &public_key.inner, true);
500        if result == BLST_ERROR::BLST_SUCCESS {
501            Ok(())
502        } else {
503            Err(AptosError::SignatureVerificationFailed)
504        }
505    }
506}
507
508impl fmt::Debug for Bls12381ProofOfPossession {
509    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
510        write!(f, "Bls12381ProofOfPossession({})", self.to_hex())
511    }
512}
513
514impl fmt::Display for Bls12381ProofOfPossession {
515    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
516        write!(f, "{}", self.to_hex())
517    }
518}
519
520#[cfg(test)]
521mod tests {
522    use super::*;
523
524    #[test]
525    fn test_generate_and_sign() {
526        let private_key = Bls12381PrivateKey::generate();
527        let message = b"hello world";
528        let signature = private_key.sign(message);
529
530        let public_key = private_key.public_key();
531        assert!(public_key.verify(message, &signature).is_ok());
532    }
533
534    #[test]
535    fn test_wrong_message_fails() {
536        let private_key = Bls12381PrivateKey::generate();
537        let message = b"hello world";
538        let wrong_message = b"hello world!";
539        let signature = private_key.sign(message);
540
541        let public_key = private_key.public_key();
542        assert!(public_key.verify(wrong_message, &signature).is_err());
543    }
544
545    #[test]
546    fn test_from_bytes_roundtrip() {
547        let private_key = Bls12381PrivateKey::generate();
548        let bytes = private_key.to_bytes();
549        let restored = Bls12381PrivateKey::from_bytes(&bytes).unwrap();
550        assert_eq!(private_key.to_bytes(), restored.to_bytes());
551    }
552
553    #[test]
554    fn test_public_key_from_bytes_roundtrip() {
555        let private_key = Bls12381PrivateKey::generate();
556        let public_key = private_key.public_key();
557        let bytes = public_key.to_bytes();
558        let restored = Bls12381PublicKey::from_bytes(&bytes).unwrap();
559        assert_eq!(public_key.to_bytes(), restored.to_bytes());
560    }
561
562    #[test]
563    fn test_signature_from_bytes_roundtrip() {
564        let private_key = Bls12381PrivateKey::generate();
565        let signature = private_key.sign(b"test");
566        let bytes = signature.to_bytes();
567        let restored = Bls12381Signature::from_bytes(&bytes).unwrap();
568        assert_eq!(signature.to_bytes(), restored.to_bytes());
569    }
570
571    #[test]
572    fn test_hex_roundtrip() {
573        let private_key = Bls12381PrivateKey::generate();
574        let hex = private_key.to_hex();
575        let restored = Bls12381PrivateKey::from_hex(&hex).unwrap();
576        assert_eq!(private_key.to_bytes(), restored.to_bytes());
577    }
578
579    #[test]
580    fn test_public_key_hex_roundtrip() {
581        let private_key = Bls12381PrivateKey::generate();
582        let public_key = private_key.public_key();
583        let hex = public_key.to_hex();
584        let restored = Bls12381PublicKey::from_hex(&hex).unwrap();
585        assert_eq!(public_key.to_bytes(), restored.to_bytes());
586    }
587
588    #[test]
589    fn test_signature_hex_roundtrip() {
590        let private_key = Bls12381PrivateKey::generate();
591        let signature = private_key.sign(b"test");
592        let hex = signature.to_hex();
593        let restored = Bls12381Signature::from_hex(&hex).unwrap();
594        assert_eq!(signature.to_bytes(), restored.to_bytes());
595    }
596
597    #[test]
598    fn test_public_key_length() {
599        assert_eq!(Bls12381PublicKey::LENGTH, BLS12381_PUBLIC_KEY_LENGTH);
600    }
601
602    #[test]
603    fn test_signature_length() {
604        assert_eq!(Bls12381Signature::LENGTH, BLS12381_SIGNATURE_LENGTH);
605    }
606
607    #[test]
608    fn test_invalid_private_key_bytes() {
609        let bytes = vec![0u8; 16]; // Wrong length
610        let result = Bls12381PrivateKey::from_bytes(&bytes);
611        assert!(result.is_err());
612    }
613
614    #[test]
615    fn test_invalid_public_key_bytes() {
616        let bytes = vec![0u8; 16]; // Wrong length
617        let result = Bls12381PublicKey::from_bytes(&bytes);
618        assert!(result.is_err());
619    }
620
621    #[test]
622    fn test_invalid_signature_bytes() {
623        let bytes = vec![0u8; 16]; // Wrong length
624        let result = Bls12381Signature::from_bytes(&bytes);
625        assert!(result.is_err());
626    }
627
628    #[test]
629    fn test_json_serialization_public_key() {
630        let private_key = Bls12381PrivateKey::generate();
631        let public_key = private_key.public_key();
632        let json = serde_json::to_string(&public_key).unwrap();
633        let restored: Bls12381PublicKey = serde_json::from_str(&json).unwrap();
634        assert_eq!(public_key.to_bytes(), restored.to_bytes());
635    }
636
637    #[test]
638    fn test_json_serialization_signature() {
639        let private_key = Bls12381PrivateKey::generate();
640        let signature = private_key.sign(b"test");
641        let json = serde_json::to_string(&signature).unwrap();
642        let restored: Bls12381Signature = serde_json::from_str(&json).unwrap();
643        assert_eq!(signature.to_bytes(), restored.to_bytes());
644    }
645
646    #[test]
647    fn test_proof_of_possession() {
648        let private_key = Bls12381PrivateKey::generate();
649        let public_key = private_key.public_key();
650        let pop = private_key.create_proof_of_possession();
651
652        // PoP should verify against the public key
653        assert!(pop.verify(&public_key).is_ok());
654
655        // PoP should fail against a different public key
656        let other_key = Bls12381PrivateKey::generate().public_key();
657        assert!(pop.verify(&other_key).is_err());
658    }
659
660    #[test]
661    fn test_pop_bytes_roundtrip() {
662        let private_key = Bls12381PrivateKey::generate();
663        let pop = private_key.create_proof_of_possession();
664
665        let bytes = pop.to_bytes();
666        assert_eq!(bytes.len(), BLS12381_POP_LENGTH);
667
668        let restored = Bls12381ProofOfPossession::from_bytes(&bytes).unwrap();
669        assert_eq!(pop.to_bytes(), restored.to_bytes());
670    }
671
672    #[test]
673    fn test_pop_hex_roundtrip() {
674        let private_key = Bls12381PrivateKey::generate();
675        let pop = private_key.create_proof_of_possession();
676
677        let hex = pop.to_hex();
678        assert!(hex.starts_with("0x"));
679
680        let restored = Bls12381ProofOfPossession::from_hex(&hex).unwrap();
681        assert_eq!(pop.to_bytes(), restored.to_bytes());
682    }
683
684    #[test]
685    fn test_pop_invalid_bytes_length() {
686        let bytes = vec![0u8; 32]; // Wrong length
687        let result = Bls12381ProofOfPossession::from_bytes(&bytes);
688        assert!(result.is_err());
689    }
690
691    #[test]
692    fn test_aggregate_public_keys() {
693        let pk1 = Bls12381PrivateKey::generate().public_key();
694        let pk2 = Bls12381PrivateKey::generate().public_key();
695        let pk3 = Bls12381PrivateKey::generate().public_key();
696
697        let agg = Bls12381PublicKey::aggregate(&[&pk1, &pk2, &pk3]).unwrap();
698        assert!(!agg.to_bytes().is_empty());
699    }
700
701    #[test]
702    fn test_aggregate_public_keys_empty() {
703        let result = Bls12381PublicKey::aggregate(&[]);
704        assert!(result.is_err());
705    }
706
707    #[test]
708    fn test_aggregate_signatures() {
709        let pk1 = Bls12381PrivateKey::generate();
710        let pk2 = Bls12381PrivateKey::generate();
711
712        let message = b"aggregate test";
713        let sig1 = pk1.sign(message);
714        let sig2 = pk2.sign(message);
715
716        let agg_sig = Bls12381Signature::aggregate(&[&sig1, &sig2]).unwrap();
717        assert!(!agg_sig.to_bytes().is_empty());
718    }
719
720    #[test]
721    fn test_aggregate_signatures_empty() {
722        let result = Bls12381Signature::aggregate(&[]);
723        assert!(result.is_err());
724    }
725
726    #[test]
727    fn test_from_seed() {
728        let seed = [42u8; 32];
729        let pk1 = Bls12381PrivateKey::from_seed(&seed).unwrap();
730        let pk2 = Bls12381PrivateKey::from_seed(&seed).unwrap();
731
732        // Same seed should produce same key
733        assert_eq!(pk1.to_bytes(), pk2.to_bytes());
734    }
735
736    #[test]
737    fn test_from_seed_too_short() {
738        let seed = [42u8; 16]; // Too short
739        let result = Bls12381PrivateKey::from_seed(&seed);
740        assert!(result.is_err());
741    }
742
743    #[test]
744    fn test_private_key_debug() {
745        let private_key = Bls12381PrivateKey::generate();
746        let debug = format!("{private_key:?}");
747        assert!(debug.contains("REDACTED"));
748        assert!(!debug.contains(&private_key.to_hex()));
749    }
750
751    #[test]
752    fn test_public_key_debug() {
753        let private_key = Bls12381PrivateKey::generate();
754        let public_key = private_key.public_key();
755        let debug = format!("{public_key:?}");
756        assert!(debug.contains("Bls12381PublicKey"));
757    }
758
759    #[test]
760    fn test_public_key_display() {
761        let private_key = Bls12381PrivateKey::generate();
762        let public_key = private_key.public_key();
763        let display = format!("{public_key}");
764        assert!(display.starts_with("0x"));
765    }
766
767    #[test]
768    fn test_signature_debug() {
769        let private_key = Bls12381PrivateKey::generate();
770        let signature = private_key.sign(b"test");
771        let debug = format!("{signature:?}");
772        assert!(debug.contains("Bls12381Signature"));
773    }
774
775    #[test]
776    fn test_signature_display() {
777        let private_key = Bls12381PrivateKey::generate();
778        let signature = private_key.sign(b"test");
779        let display = format!("{signature}");
780        assert!(display.starts_with("0x"));
781    }
782
783    #[test]
784    fn test_pop_debug() {
785        let private_key = Bls12381PrivateKey::generate();
786        let pop = private_key.create_proof_of_possession();
787        let debug = format!("{pop:?}");
788        assert!(debug.contains("Bls12381ProofOfPossession"));
789    }
790
791    #[test]
792    fn test_pop_display() {
793        let private_key = Bls12381PrivateKey::generate();
794        let pop = private_key.create_proof_of_possession();
795        let display = format!("{pop}");
796        assert!(display.starts_with("0x"));
797    }
798
799    #[test]
800    fn test_signer_trait() {
801        use crate::crypto::traits::Signer;
802
803        let private_key = Bls12381PrivateKey::generate();
804        let message = b"trait test";
805
806        let signature = Signer::sign(&private_key, message);
807        let public_key = Signer::public_key(&private_key);
808
809        assert!(public_key.verify(message, &signature).is_ok());
810    }
811
812    #[test]
813    fn test_verifier_trait() {
814        use crate::crypto::traits::Verifier;
815
816        let private_key = Bls12381PrivateKey::generate();
817        let public_key = private_key.public_key();
818        let message = b"verifier test";
819        let signature = private_key.sign(message);
820
821        assert!(Verifier::verify(&public_key, message, &signature).is_ok());
822    }
823
824    #[test]
825    fn test_public_key_trait() {
826        use crate::crypto::traits::PublicKey;
827
828        let private_key = Bls12381PrivateKey::generate();
829        let public_key = private_key.public_key();
830        let bytes = PublicKey::to_bytes(&public_key);
831        let restored = Bls12381PublicKey::from_bytes(&bytes).unwrap();
832        assert_eq!(public_key, restored);
833    }
834
835    #[test]
836    fn test_signature_trait() {
837        use crate::crypto::traits::Signature;
838
839        let private_key = Bls12381PrivateKey::generate();
840        let signature = private_key.sign(b"test");
841        let bytes = Signature::to_bytes(&signature);
842        let restored = Bls12381Signature::from_bytes(&bytes).unwrap();
843        assert_eq!(signature, restored);
844    }
845}