Skip to main content

aptos_sdk/crypto/
secp256r1.rs

1//! Secp256r1 (P-256) ECDSA signature scheme implementation.
2//!
3//! Secp256r1, also known as P-256 or prime256v1, is commonly used in
4//! `WebAuthn` and passkey implementations.
5//!
6//! # Security: Signature Malleability
7//!
8//! This implementation uses the `p256` crate which produces normalized (low-S)
9//! ECDSA signatures by default. This prevents signature malleability attacks
10//! where an attacker could create an alternative valid signature `(r, -s mod n)`
11//! for the same message.
12//!
13//! When parsing external signatures via [`Secp256r1Signature::from_bytes`], the
14//! `p256` crate accepts both low-S and high-S signatures. If strict low-S
15//! enforcement is required, callers should normalize or reject high-S signatures.
16
17use crate::crypto::traits::{PublicKey, Signature, Signer, Verifier};
18use crate::error::{AptosError, AptosResult};
19use p256::ecdsa::{
20    Signature as P256Signature, SigningKey, VerifyingKey, signature::Signer as P256Signer,
21    signature::Verifier as P256Verifier,
22};
23use serde::{Deserialize, Serialize};
24use std::fmt;
25use zeroize::Zeroize;
26
27/// Secp256r1 private key length in bytes.
28pub const SECP256R1_PRIVATE_KEY_LENGTH: usize = 32;
29/// Secp256r1 public key length in bytes (compressed).
30pub const SECP256R1_PUBLIC_KEY_LENGTH: usize = 33;
31/// Secp256r1 signature length in bytes.
32pub const SECP256R1_SIGNATURE_LENGTH: usize = 64;
33
34/// A Secp256r1 (P-256) ECDSA private key.
35///
36/// The private key is zeroized when dropped.
37#[derive(Clone, Zeroize)]
38#[zeroize(drop)]
39pub struct Secp256r1PrivateKey {
40    #[zeroize(skip)]
41    #[allow(unused)] // Field is used; lint false positive from Zeroize derive
42    inner: SigningKey,
43}
44
45impl Secp256r1PrivateKey {
46    /// Generates a new random Secp256r1 private key.
47    pub fn generate() -> Self {
48        let signing_key = SigningKey::random(&mut rand::rngs::OsRng);
49        Self { inner: signing_key }
50    }
51
52    /// Creates a private key from raw bytes.
53    ///
54    /// # Errors
55    ///
56    /// Returns [`AptosError::InvalidPrivateKey`] if:
57    /// - The byte slice length is not exactly 32 bytes
58    /// - The bytes do not represent a valid Secp256r1 private key
59    pub fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
60        if bytes.len() != SECP256R1_PRIVATE_KEY_LENGTH {
61            return Err(AptosError::InvalidPrivateKey(format!(
62                "expected {} bytes, got {}",
63                SECP256R1_PRIVATE_KEY_LENGTH,
64                bytes.len()
65            )));
66        }
67        let signing_key = SigningKey::from_slice(bytes)
68            .map_err(|e| AptosError::InvalidPrivateKey(e.to_string()))?;
69        Ok(Self { inner: signing_key })
70    }
71
72    /// Creates a private key from a hex string.
73    ///
74    /// # Errors
75    ///
76    /// Returns [`AptosError::Hex`] if the hex string is invalid.
77    /// Returns [`AptosError::InvalidPrivateKey`] if the decoded bytes are not exactly 32 bytes or do not represent a valid Secp256r1 private key.
78    pub fn from_hex(hex_str: &str) -> AptosResult<Self> {
79        let hex_str = hex_str.strip_prefix("0x").unwrap_or(hex_str);
80        let bytes = hex::decode(hex_str)?;
81        Self::from_bytes(&bytes)
82    }
83
84    /// Creates a private key from AIP-80 format string.
85    ///
86    /// AIP-80 format: `secp256r1-priv-0x{hex_bytes}`
87    ///
88    /// # Errors
89    ///
90    /// Returns an error if the format is invalid or the key bytes are invalid.
91    pub fn from_aip80(s: &str) -> AptosResult<Self> {
92        const PREFIX: &str = "secp256r1-priv-";
93        if let Some(hex_part) = s.strip_prefix(PREFIX) {
94            Self::from_hex(hex_part)
95        } else {
96            Err(AptosError::InvalidPrivateKey(format!(
97                "invalid AIP-80 format: expected prefix '{PREFIX}'"
98            )))
99        }
100    }
101
102    /// Returns the private key as bytes.
103    pub fn to_bytes(&self) -> [u8; SECP256R1_PRIVATE_KEY_LENGTH] {
104        self.inner.to_bytes().into()
105    }
106
107    /// Returns the private key as a hex string.
108    pub fn to_hex(&self) -> String {
109        format!("0x{}", hex::encode(self.inner.to_bytes()))
110    }
111
112    /// Returns the private key in AIP-80 format.
113    ///
114    /// AIP-80 format: `secp256r1-priv-0x{hex_bytes}`
115    pub fn to_aip80(&self) -> String {
116        format!("secp256r1-priv-{}", self.to_hex())
117    }
118
119    /// Returns the corresponding public key.
120    pub fn public_key(&self) -> Secp256r1PublicKey {
121        Secp256r1PublicKey {
122            inner: *self.inner.verifying_key(),
123        }
124    }
125
126    /// Signs a message (pre-hashed with SHA256) and returns the signature.
127    pub fn sign(&self, message: &[u8]) -> Secp256r1Signature {
128        let hash = crate::crypto::sha2_256(message);
129        let signature: P256Signature = self.inner.sign(&hash);
130        Secp256r1Signature { inner: signature }
131    }
132
133    /// Signs a pre-hashed message directly.
134    pub fn sign_prehashed(&self, hash: &[u8; 32]) -> Secp256r1Signature {
135        let signature: P256Signature = self.inner.sign(hash);
136        Secp256r1Signature { inner: signature }
137    }
138}
139
140impl Signer for Secp256r1PrivateKey {
141    type Signature = Secp256r1Signature;
142
143    fn sign(&self, message: &[u8]) -> Secp256r1Signature {
144        Secp256r1PrivateKey::sign(self, message)
145    }
146
147    fn public_key(&self) -> Secp256r1PublicKey {
148        Secp256r1PrivateKey::public_key(self)
149    }
150}
151
152impl fmt::Debug for Secp256r1PrivateKey {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        write!(f, "Secp256r1PrivateKey([REDACTED])")
155    }
156}
157
158/// A Secp256r1 (P-256) ECDSA public key.
159#[derive(Clone, Copy, PartialEq, Eq)]
160pub struct Secp256r1PublicKey {
161    inner: VerifyingKey,
162}
163
164impl Secp256r1PublicKey {
165    /// Creates a public key from compressed bytes (33 bytes).
166    ///
167    /// # Errors
168    ///
169    /// Returns [`AptosError::InvalidPublicKey`] if the bytes do not represent a valid Secp256r1 compressed public key.
170    pub fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
171        let verifying_key = VerifyingKey::from_sec1_bytes(bytes)
172            .map_err(|e| AptosError::InvalidPublicKey(e.to_string()))?;
173        Ok(Self {
174            inner: verifying_key,
175        })
176    }
177
178    /// Creates a public key from a hex string.
179    ///
180    /// # Errors
181    ///
182    /// Returns [`AptosError::Hex`] if the hex string is invalid.
183    /// Returns [`AptosError::InvalidPublicKey`] if the decoded bytes do not represent a valid Secp256r1 compressed public key.
184    pub fn from_hex(hex_str: &str) -> AptosResult<Self> {
185        let hex_str = hex_str.strip_prefix("0x").unwrap_or(hex_str);
186        let bytes = hex::decode(hex_str)?;
187        Self::from_bytes(&bytes)
188    }
189
190    /// Creates a public key from AIP-80 format string.
191    ///
192    /// AIP-80 format: `secp256r1-pub-0x{hex_bytes}`
193    ///
194    /// # Errors
195    ///
196    /// Returns an error if the format is invalid or the key bytes are invalid.
197    pub fn from_aip80(s: &str) -> AptosResult<Self> {
198        const PREFIX: &str = "secp256r1-pub-";
199        if let Some(hex_part) = s.strip_prefix(PREFIX) {
200            Self::from_hex(hex_part)
201        } else {
202            Err(AptosError::InvalidPublicKey(format!(
203                "invalid AIP-80 format: expected prefix '{PREFIX}'"
204            )))
205        }
206    }
207
208    /// Returns the public key as compressed bytes (33 bytes).
209    pub fn to_bytes(&self) -> Vec<u8> {
210        #[allow(unused_imports)]
211        use p256::elliptic_curve::sec1::ToEncodedPoint;
212        self.inner.to_encoded_point(true).as_bytes().to_vec()
213    }
214
215    /// Returns the public key as uncompressed bytes (65 bytes).
216    pub fn to_uncompressed_bytes(&self) -> Vec<u8> {
217        #[allow(unused_imports)]
218        use p256::elliptic_curve::sec1::ToEncodedPoint;
219        self.inner.to_encoded_point(false).as_bytes().to_vec()
220    }
221
222    /// Returns the public key as a hex string (compressed format).
223    pub fn to_hex(&self) -> String {
224        format!("0x{}", hex::encode(self.to_bytes()))
225    }
226
227    /// Returns the public key in AIP-80 format (compressed).
228    ///
229    /// AIP-80 format: `secp256r1-pub-0x{hex_bytes}`
230    pub fn to_aip80(&self) -> String {
231        format!("secp256r1-pub-{}", self.to_hex())
232    }
233
234    /// Verifies a signature against a message.
235    ///
236    /// # Errors
237    ///
238    /// Returns [`AptosError::SignatureVerificationFailed`] if the signature is invalid or does not match the message.
239    pub fn verify(&self, message: &[u8], signature: &Secp256r1Signature) -> AptosResult<()> {
240        let hash = crate::crypto::sha2_256(message);
241        self.inner
242            .verify(&hash, &signature.inner)
243            .map_err(|_| AptosError::SignatureVerificationFailed)
244    }
245
246    /// Verifies a signature against a pre-hashed message.
247    ///
248    /// # Errors
249    ///
250    /// Returns [`AptosError::SignatureVerificationFailed`] if the signature is invalid or does not match the hash.
251    pub fn verify_prehashed(
252        &self,
253        hash: &[u8; 32],
254        signature: &Secp256r1Signature,
255    ) -> AptosResult<()> {
256        self.inner
257            .verify(hash, &signature.inner)
258            .map_err(|_| AptosError::SignatureVerificationFailed)
259    }
260
261    /// Derives the account address for this public key.
262    ///
263    /// Uses the `SingleKey` authentication scheme (`scheme_id` = 2):
264    /// `auth_key = SHA3-256(BCS(AnyPublicKey::Secp256r1) || 0x02)`
265    ///
266    /// Where `BCS(AnyPublicKey::Secp256r1)` = `0x02 || ULEB128(65) || uncompressed_public_key`
267    pub fn to_address(&self) -> crate::types::AccountAddress {
268        // BCS format: variant_byte || ULEB128(length) || uncompressed_public_key
269        let uncompressed = self.to_uncompressed_bytes();
270        let mut bcs_bytes = Vec::with_capacity(1 + 1 + uncompressed.len());
271        bcs_bytes.push(0x02); // Secp256r1 variant
272        bcs_bytes.push(65); // ULEB128(65) = 65 (since 65 < 128)
273        bcs_bytes.extend_from_slice(&uncompressed);
274        crate::crypto::derive_address(&bcs_bytes, crate::crypto::SINGLE_KEY_SCHEME)
275    }
276}
277
278impl PublicKey for Secp256r1PublicKey {
279    const LENGTH: usize = SECP256R1_PUBLIC_KEY_LENGTH;
280
281    fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
282        Secp256r1PublicKey::from_bytes(bytes)
283    }
284
285    fn to_bytes(&self) -> Vec<u8> {
286        Secp256r1PublicKey::to_bytes(self)
287    }
288}
289
290impl Verifier for Secp256r1PublicKey {
291    type Signature = Secp256r1Signature;
292
293    fn verify(&self, message: &[u8], signature: &Secp256r1Signature) -> AptosResult<()> {
294        Secp256r1PublicKey::verify(self, message, signature)
295    }
296}
297
298impl fmt::Debug for Secp256r1PublicKey {
299    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300        write!(f, "Secp256r1PublicKey({})", self.to_hex())
301    }
302}
303
304impl fmt::Display for Secp256r1PublicKey {
305    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306        write!(f, "{}", self.to_hex())
307    }
308}
309
310impl Serialize for Secp256r1PublicKey {
311    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
312    where
313        S: serde::Serializer,
314    {
315        if serializer.is_human_readable() {
316            serializer.serialize_str(&self.to_hex())
317        } else {
318            serializer.serialize_bytes(&self.to_bytes())
319        }
320    }
321}
322
323impl<'de> Deserialize<'de> for Secp256r1PublicKey {
324    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
325    where
326        D: serde::Deserializer<'de>,
327    {
328        if deserializer.is_human_readable() {
329            let s = String::deserialize(deserializer)?;
330            Self::from_hex(&s).map_err(serde::de::Error::custom)
331        } else {
332            let bytes = Vec::<u8>::deserialize(deserializer)?;
333            Self::from_bytes(&bytes).map_err(serde::de::Error::custom)
334        }
335    }
336}
337
338/// A Secp256r1 (P-256) ECDSA signature.
339#[derive(Clone, Copy, PartialEq, Eq)]
340pub struct Secp256r1Signature {
341    inner: P256Signature,
342}
343
344impl Secp256r1Signature {
345    /// Creates a signature from raw bytes (64 bytes, r || s).
346    ///
347    /// # Errors
348    ///
349    /// Returns [`AptosError::InvalidSignature`] if:
350    /// - The byte slice length is not exactly 64 bytes
351    /// - The bytes do not represent a valid Secp256r1 signature
352    pub fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
353        if bytes.len() != SECP256R1_SIGNATURE_LENGTH {
354            return Err(AptosError::InvalidSignature(format!(
355                "expected {} bytes, got {}",
356                SECP256R1_SIGNATURE_LENGTH,
357                bytes.len()
358            )));
359        }
360        let signature = P256Signature::from_slice(bytes)
361            .map_err(|e| AptosError::InvalidSignature(e.to_string()))?;
362        Ok(Self { inner: signature })
363    }
364
365    /// Creates a signature from a hex string.
366    ///
367    /// # Errors
368    ///
369    /// Returns [`AptosError::Hex`] if the hex string is invalid.
370    /// Returns [`AptosError::InvalidSignature`] if the decoded bytes are not exactly 64 bytes or do not represent a valid Secp256r1 signature.
371    pub fn from_hex(hex_str: &str) -> AptosResult<Self> {
372        let hex_str = hex_str.strip_prefix("0x").unwrap_or(hex_str);
373        let bytes = hex::decode(hex_str)?;
374        Self::from_bytes(&bytes)
375    }
376
377    /// Returns the signature as bytes (64 bytes, r || s).
378    pub fn to_bytes(&self) -> [u8; SECP256R1_SIGNATURE_LENGTH] {
379        self.inner.to_bytes().into()
380    }
381
382    /// Returns the signature as a hex string.
383    pub fn to_hex(&self) -> String {
384        format!("0x{}", hex::encode(self.to_bytes()))
385    }
386}
387
388impl Signature for Secp256r1Signature {
389    type PublicKey = Secp256r1PublicKey;
390    const LENGTH: usize = SECP256R1_SIGNATURE_LENGTH;
391
392    fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
393        Secp256r1Signature::from_bytes(bytes)
394    }
395
396    fn to_bytes(&self) -> Vec<u8> {
397        self.inner.to_bytes().to_vec()
398    }
399}
400
401impl fmt::Debug for Secp256r1Signature {
402    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
403        write!(f, "Secp256r1Signature({})", self.to_hex())
404    }
405}
406
407impl fmt::Display for Secp256r1Signature {
408    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
409        write!(f, "{}", self.to_hex())
410    }
411}
412
413impl Serialize for Secp256r1Signature {
414    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
415    where
416        S: serde::Serializer,
417    {
418        if serializer.is_human_readable() {
419            serializer.serialize_str(&self.to_hex())
420        } else {
421            serializer.serialize_bytes(&self.to_bytes())
422        }
423    }
424}
425
426impl<'de> Deserialize<'de> for Secp256r1Signature {
427    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
428    where
429        D: serde::Deserializer<'de>,
430    {
431        if deserializer.is_human_readable() {
432            let s = String::deserialize(deserializer)?;
433            Self::from_hex(&s).map_err(serde::de::Error::custom)
434        } else {
435            let bytes = Vec::<u8>::deserialize(deserializer)?;
436            Self::from_bytes(&bytes).map_err(serde::de::Error::custom)
437        }
438    }
439}
440
441#[cfg(test)]
442mod tests {
443    use super::*;
444
445    #[test]
446    fn test_generate_and_sign() {
447        let private_key = Secp256r1PrivateKey::generate();
448        let message = b"hello world";
449        let signature = private_key.sign(message);
450
451        let public_key = private_key.public_key();
452        assert!(public_key.verify(message, &signature).is_ok());
453    }
454
455    #[test]
456    fn test_wrong_message_fails() {
457        let private_key = Secp256r1PrivateKey::generate();
458        let message = b"hello world";
459        let wrong_message = b"hello world!";
460        let signature = private_key.sign(message);
461
462        let public_key = private_key.public_key();
463        assert!(public_key.verify(wrong_message, &signature).is_err());
464    }
465
466    #[test]
467    fn test_from_bytes_roundtrip() {
468        let private_key = Secp256r1PrivateKey::generate();
469        let bytes = private_key.to_bytes();
470        let restored = Secp256r1PrivateKey::from_bytes(&bytes).unwrap();
471        assert_eq!(private_key.to_bytes(), restored.to_bytes());
472    }
473
474    #[test]
475    fn test_public_key_from_bytes_roundtrip() {
476        let private_key = Secp256r1PrivateKey::generate();
477        let public_key = private_key.public_key();
478        let bytes = public_key.to_bytes();
479        let restored = Secp256r1PublicKey::from_bytes(&bytes).unwrap();
480        assert_eq!(public_key.to_bytes(), restored.to_bytes());
481    }
482
483    #[test]
484    fn test_signature_from_bytes_roundtrip() {
485        let private_key = Secp256r1PrivateKey::generate();
486        let signature = private_key.sign(b"test");
487        let bytes = signature.to_bytes();
488        let restored = Secp256r1Signature::from_bytes(&bytes).unwrap();
489        assert_eq!(signature.to_bytes(), restored.to_bytes());
490    }
491
492    #[test]
493    fn test_hex_roundtrip() {
494        let private_key = Secp256r1PrivateKey::generate();
495        let hex = private_key.to_hex();
496        let restored = Secp256r1PrivateKey::from_hex(&hex).unwrap();
497        assert_eq!(private_key.to_bytes(), restored.to_bytes());
498    }
499
500    #[test]
501    fn test_public_key_hex_roundtrip() {
502        let private_key = Secp256r1PrivateKey::generate();
503        let public_key = private_key.public_key();
504        let hex = public_key.to_hex();
505        let restored = Secp256r1PublicKey::from_hex(&hex).unwrap();
506        assert_eq!(public_key.to_bytes(), restored.to_bytes());
507    }
508
509    #[test]
510    fn test_signature_hex_roundtrip() {
511        let private_key = Secp256r1PrivateKey::generate();
512        let signature = private_key.sign(b"test");
513        let hex = signature.to_hex();
514        let restored = Secp256r1Signature::from_hex(&hex).unwrap();
515        assert_eq!(signature.to_bytes(), restored.to_bytes());
516    }
517
518    #[test]
519    fn test_invalid_private_key_bytes() {
520        let bytes = vec![0u8; 16]; // Wrong length
521        let result = Secp256r1PrivateKey::from_bytes(&bytes);
522        assert!(result.is_err());
523    }
524
525    #[test]
526    fn test_invalid_public_key_bytes() {
527        let bytes = vec![0u8; 16]; // Wrong length
528        let result = Secp256r1PublicKey::from_bytes(&bytes);
529        assert!(result.is_err());
530    }
531
532    #[test]
533    fn test_invalid_signature_bytes() {
534        let bytes = vec![0u8; 16]; // Wrong length
535        let result = Secp256r1Signature::from_bytes(&bytes);
536        assert!(result.is_err());
537    }
538
539    #[test]
540    fn test_json_serialization_public_key() {
541        let private_key = Secp256r1PrivateKey::generate();
542        let public_key = private_key.public_key();
543        let json = serde_json::to_string(&public_key).unwrap();
544        let restored: Secp256r1PublicKey = serde_json::from_str(&json).unwrap();
545        assert_eq!(public_key.to_bytes(), restored.to_bytes());
546    }
547
548    #[test]
549    fn test_json_serialization_signature() {
550        let private_key = Secp256r1PrivateKey::generate();
551        let signature = private_key.sign(b"test");
552        let json = serde_json::to_string(&signature).unwrap();
553        let restored: Secp256r1Signature = serde_json::from_str(&json).unwrap();
554        assert_eq!(signature.to_bytes(), restored.to_bytes());
555    }
556
557    #[test]
558    fn test_key_lengths() {
559        assert_eq!(Secp256r1PublicKey::LENGTH, SECP256R1_PUBLIC_KEY_LENGTH);
560        assert_eq!(Secp256r1Signature::LENGTH, SECP256R1_SIGNATURE_LENGTH);
561    }
562
563    #[test]
564    fn test_display_debug() {
565        let private_key = Secp256r1PrivateKey::generate();
566        let public_key = private_key.public_key();
567        let signature = private_key.sign(b"test");
568
569        // Debug should contain type name
570        assert!(format!("{public_key:?}").contains("Secp256r1PublicKey"));
571        assert!(format!("{signature:?}").contains("Secp256r1Signature"));
572
573        // Display should show hex
574        assert!(format!("{public_key}").starts_with("0x"));
575        assert!(format!("{signature}").starts_with("0x"));
576    }
577
578    #[test]
579    fn test_compressed_public_key_length() {
580        let private_key = Secp256r1PrivateKey::generate();
581        let public_key = private_key.public_key();
582        // Compressed public key should be 33 bytes
583        assert_eq!(public_key.to_bytes().len(), 33);
584    }
585
586    #[test]
587    fn test_private_key_aip80_roundtrip() {
588        let private_key = Secp256r1PrivateKey::generate();
589        let aip80 = private_key.to_aip80();
590
591        // Should have correct prefix
592        assert!(aip80.starts_with("secp256r1-priv-0x"));
593
594        // Should roundtrip correctly
595        let restored = Secp256r1PrivateKey::from_aip80(&aip80).unwrap();
596        assert_eq!(private_key.to_bytes(), restored.to_bytes());
597    }
598
599    #[test]
600    fn test_private_key_aip80_format() {
601        let bytes = [0x01; 32];
602        let private_key = Secp256r1PrivateKey::from_bytes(&bytes).unwrap();
603        let aip80 = private_key.to_aip80();
604
605        // Expected format: secp256r1-priv-0x0101...01
606        let expected = format!("secp256r1-priv-0x{}", "01".repeat(32));
607        assert_eq!(aip80, expected);
608    }
609
610    #[test]
611    fn test_private_key_aip80_invalid_prefix() {
612        let result = Secp256r1PrivateKey::from_aip80("ed25519-priv-0x01");
613        assert!(result.is_err());
614    }
615
616    #[test]
617    fn test_public_key_aip80_roundtrip() {
618        let private_key = Secp256r1PrivateKey::generate();
619        let public_key = private_key.public_key();
620        let aip80 = public_key.to_aip80();
621
622        // Should have correct prefix
623        assert!(aip80.starts_with("secp256r1-pub-0x"));
624
625        // Should roundtrip correctly
626        let restored = Secp256r1PublicKey::from_aip80(&aip80).unwrap();
627        assert_eq!(public_key.to_bytes(), restored.to_bytes());
628    }
629
630    #[test]
631    fn test_public_key_aip80_invalid_prefix() {
632        let result = Secp256r1PublicKey::from_aip80("ed25519-pub-0x01");
633        assert!(result.is_err());
634    }
635
636    #[test]
637    fn test_signer_trait() {
638        use crate::crypto::traits::Signer;
639
640        let private_key = Secp256r1PrivateKey::generate();
641        let message = b"trait test";
642
643        let signature = Signer::sign(&private_key, message);
644        let public_key = Signer::public_key(&private_key);
645
646        assert!(public_key.verify(message, &signature).is_ok());
647    }
648
649    #[test]
650    fn test_verifier_trait() {
651        use crate::crypto::traits::Verifier;
652
653        let private_key = Secp256r1PrivateKey::generate();
654        let public_key = private_key.public_key();
655        let message = b"verifier test";
656        let signature = private_key.sign(message);
657
658        assert!(Verifier::verify(&public_key, message, &signature).is_ok());
659    }
660
661    #[test]
662    fn test_public_key_trait() {
663        use crate::crypto::traits::PublicKey;
664
665        let private_key = Secp256r1PrivateKey::generate();
666        let public_key = private_key.public_key();
667        let bytes = PublicKey::to_bytes(&public_key);
668        let restored = Secp256r1PublicKey::from_bytes(&bytes).unwrap();
669        assert_eq!(public_key.to_bytes(), restored.to_bytes());
670    }
671
672    #[test]
673    fn test_signature_trait() {
674        use crate::crypto::traits::Signature;
675
676        let private_key = Secp256r1PrivateKey::generate();
677        let signature = private_key.sign(b"test");
678        let bytes = Signature::to_bytes(&signature);
679        let restored = Secp256r1Signature::from_bytes(&bytes).unwrap();
680        assert_eq!(signature.to_bytes(), restored.to_bytes());
681    }
682
683    #[test]
684    fn test_private_key_debug() {
685        let private_key = Secp256r1PrivateKey::generate();
686        let debug = format!("{private_key:?}");
687        assert!(debug.contains("REDACTED"));
688        assert!(!debug.contains(&private_key.to_hex()));
689    }
690
691    #[test]
692    fn test_address_derivation() {
693        let private_key = Secp256r1PrivateKey::generate();
694        let public_key = private_key.public_key();
695        let address = public_key.to_address();
696
697        // Address should not be zero
698        assert!(!address.is_zero());
699
700        // Same public key should derive same address
701        let address2 = public_key.to_address();
702        assert_eq!(address, address2);
703    }
704
705    #[test]
706    fn test_uncompressed_bytes() {
707        let private_key = Secp256r1PrivateKey::generate();
708        let public_key = private_key.public_key();
709
710        // Uncompressed should be 65 bytes (0x04 prefix + 64 bytes)
711        let uncompressed = public_key.to_uncompressed_bytes();
712        assert_eq!(uncompressed.len(), 65);
713        assert_eq!(uncompressed[0], 0x04); // Uncompressed point prefix
714    }
715
716    #[test]
717    fn test_private_key_clone() {
718        let private_key = Secp256r1PrivateKey::generate();
719        let cloned = private_key.clone();
720        assert_eq!(private_key.to_bytes(), cloned.to_bytes());
721    }
722
723    #[test]
724    fn test_public_key_equality() {
725        let private_key = Secp256r1PrivateKey::generate();
726        let pk1 = private_key.public_key();
727        let pk2 = private_key.public_key();
728        assert_eq!(pk1, pk2);
729
730        let different = Secp256r1PrivateKey::generate().public_key();
731        assert_ne!(pk1, different);
732    }
733
734    #[test]
735    fn test_signature_verification() {
736        let private_key = Secp256r1PrivateKey::generate();
737        let sig1 = private_key.sign(b"test");
738        let sig2 = private_key.sign(b"test");
739        // Note: ECDSA signatures may have randomness, so they might not be equal
740        // But they should both verify
741        let public_key = private_key.public_key();
742        assert!(public_key.verify(b"test", &sig1).is_ok());
743        assert!(public_key.verify(b"test", &sig2).is_ok());
744    }
745}