aptos_sdk/account/
secp256k1.rs1use crate::account::account::{Account, AuthenticationKey};
4use crate::crypto::{
5 SINGLE_KEY_SCHEME, Secp256k1PrivateKey, Secp256k1PublicKey, derive_authentication_key,
6};
7use crate::error::AptosResult;
8use crate::types::AccountAddress;
9use std::fmt;
10
11#[derive(Clone)]
24pub struct Secp256k1Account {
25 private_key: Secp256k1PrivateKey,
26 public_key: Secp256k1PublicKey,
27 address: AccountAddress,
28}
29
30impl Secp256k1Account {
31 pub fn generate() -> Self {
33 let private_key = Secp256k1PrivateKey::generate();
34 Self::from_private_key(private_key)
35 }
36
37 pub fn from_private_key(private_key: Secp256k1PrivateKey) -> Self {
39 let public_key = private_key.public_key();
40 let address = public_key.to_address();
41 Self {
42 private_key,
43 public_key,
44 address,
45 }
46 }
47
48 pub fn from_private_key_bytes(bytes: &[u8]) -> AptosResult<Self> {
54 let private_key = Secp256k1PrivateKey::from_bytes(bytes)?;
55 Ok(Self::from_private_key(private_key))
56 }
57
58 pub fn from_private_key_hex(hex_str: &str) -> AptosResult<Self> {
66 let private_key = Secp256k1PrivateKey::from_hex(hex_str)?;
67 Ok(Self::from_private_key(private_key))
68 }
69
70 pub fn address(&self) -> AccountAddress {
72 self.address
73 }
74
75 pub fn public_key(&self) -> &Secp256k1PublicKey {
77 &self.public_key
78 }
79
80 pub fn private_key(&self) -> &Secp256k1PrivateKey {
82 &self.private_key
83 }
84
85 pub fn sign_message(&self, message: &[u8]) -> crate::crypto::Secp256k1Signature {
87 self.private_key.sign(message)
88 }
89}
90
91impl Account for Secp256k1Account {
92 fn address(&self) -> AccountAddress {
93 self.address
94 }
95
96 fn authentication_key(&self) -> AuthenticationKey {
97 let uncompressed = self.public_key.to_uncompressed_bytes();
103 let mut bcs_bytes = Vec::with_capacity(1 + 1 + uncompressed.len());
104 bcs_bytes.push(0x01); bcs_bytes.push(65); bcs_bytes.extend_from_slice(&uncompressed);
107 let key = derive_authentication_key(&bcs_bytes, SINGLE_KEY_SCHEME);
108 AuthenticationKey::new(key)
109 }
110
111 fn sign(&self, message: &[u8]) -> crate::error::AptosResult<Vec<u8>> {
112 let sig = self.private_key.sign(message).to_bytes().to_vec();
116 debug_assert_eq!(
117 sig.len(),
118 64,
119 "Secp256k1 signature must be exactly 64 bytes (R || S)"
120 );
121 let mut out = Vec::with_capacity(1 + 1 + sig.len());
122 out.push(0x01); out.push(64); out.extend_from_slice(&sig);
125 Ok(out)
126 }
127
128 fn public_key_bytes(&self) -> Vec<u8> {
129 let uncompressed = self.public_key.to_uncompressed_bytes();
134 let mut out = Vec::with_capacity(1 + 1 + uncompressed.len());
135 out.push(0x01); out.push(65); out.extend_from_slice(&uncompressed);
138 out
139 }
140
141 fn signature_scheme(&self) -> u8 {
142 SINGLE_KEY_SCHEME
143 }
144}
145
146impl fmt::Debug for Secp256k1Account {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 f.debug_struct("Secp256k1Account")
149 .field("address", &self.address)
150 .field("public_key", &self.public_key)
151 .finish_non_exhaustive()
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158 use crate::account::Account;
159
160 #[test]
161 fn test_generate() {
162 let account = Secp256k1Account::generate();
163 assert!(!account.address().is_zero());
164 }
165
166 #[test]
167 fn test_from_private_key_roundtrip() {
168 let account = Secp256k1Account::generate();
169 let bytes = account.private_key().to_bytes();
170
171 let restored = Secp256k1Account::from_private_key_bytes(&bytes).unwrap();
172 assert_eq!(account.address(), restored.address());
173 }
174
175 #[test]
176 fn test_sign_and_verify() {
177 let account = Secp256k1Account::generate();
178 let message = b"hello world";
179
180 let signature = account.sign_message(message);
181 assert!(account.public_key().verify(message, &signature).is_ok());
182 }
183
184 #[test]
185 fn test_from_private_key() {
186 let original = Secp256k1Account::generate();
187 let private_key = original.private_key().clone();
188 let restored = Secp256k1Account::from_private_key(private_key);
189 assert_eq!(original.address(), restored.address());
190 }
191
192 #[test]
193 fn test_from_private_key_hex() {
194 let original = Secp256k1Account::generate();
195 let hex = original.private_key().to_hex();
196 let restored = Secp256k1Account::from_private_key_hex(&hex).unwrap();
197 assert_eq!(original.address(), restored.address());
198 }
199
200 #[test]
201 fn test_authentication_key() {
202 let account = Secp256k1Account::generate();
203 let auth_key = account.authentication_key();
204 assert_eq!(auth_key.as_bytes().len(), 32);
205 }
206
207 #[test]
208 fn test_public_key_bytes() {
209 let account = Secp256k1Account::generate();
210 let bytes = account.public_key_bytes();
211 assert_eq!(bytes.len(), 67);
214 assert_eq!(bytes[0], 0x01, "AnyPublicKey::Secp256k1Ecdsa variant tag");
215 assert_eq!(bytes[1], 65, "ULEB128(65)");
216 assert_eq!(bytes[2], 0x04, "SEC1 uncompressed marker");
217 }
218
219 #[test]
220 fn test_signature_scheme() {
221 let account = Secp256k1Account::generate();
222 assert_eq!(account.signature_scheme(), SINGLE_KEY_SCHEME);
223 }
224
225 #[test]
226 fn test_sign_trait() {
227 let account = Secp256k1Account::generate();
228 let message = b"test message";
229 let sig_bytes = account.sign(message).unwrap();
230 assert_eq!(sig_bytes.len(), 66);
232 assert_eq!(sig_bytes[0], 0x01, "AnySignature::Secp256k1 variant tag");
233 assert_eq!(sig_bytes[1], 64, "ULEB128(64)");
234 }
235
236 #[test]
237 fn test_debug_output() {
238 let account = Secp256k1Account::generate();
239 let debug = format!("{account:?}");
240 assert!(debug.contains("Secp256k1Account"));
241 assert!(debug.contains("address"));
242 }
243
244 #[test]
245 fn test_invalid_private_key_bytes() {
246 let result = Secp256k1Account::from_private_key_bytes(&[0u8; 16]);
247 assert!(result.is_err());
248 }
249
250 #[test]
251 fn test_invalid_private_key_hex() {
252 let result = Secp256k1Account::from_private_key_hex("invalid");
253 assert!(result.is_err());
254 }
255}