Skip to main content

aptos_sdk/crypto/
secp256k1.rs

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