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