aptos_sdk/account/
secp256r1.rs1#![allow(clippy::doc_markdown)]
5
6use crate::account::account::{Account, AuthenticationKey};
34use crate::crypto::{
35 SINGLE_KEY_SCHEME, Secp256r1PrivateKey, Secp256r1PublicKey, derive_authentication_key,
36};
37use crate::error::AptosResult;
38use crate::types::AccountAddress;
39use std::fmt;
40
41#[deprecated(
69 since = "0.5.0",
70 note = "Use `WebAuthnAccount` for on-chain transaction signing. Bare \
71 secp256r1 signatures are not accepted by Aptos validators (the \
72 on-chain AnySignature variant 2 is WebAuthn, not Secp256r1Ecdsa). \
73 This type is retained for off-chain use only."
74)]
75#[derive(Clone)]
76pub struct Secp256r1Account {
77 private_key: Secp256r1PrivateKey,
78 public_key: Secp256r1PublicKey,
79 address: AccountAddress,
80}
81
82#[allow(deprecated)]
83impl Secp256r1Account {
84 pub fn generate() -> Self {
86 let private_key = Secp256r1PrivateKey::generate();
87 Self::from_private_key(private_key)
88 }
89
90 pub fn from_private_key(private_key: Secp256r1PrivateKey) -> Self {
92 let public_key = private_key.public_key();
93 let address = public_key.to_address();
94 Self {
95 private_key,
96 public_key,
97 address,
98 }
99 }
100
101 pub fn from_private_key_bytes(bytes: &[u8]) -> AptosResult<Self> {
107 let private_key = Secp256r1PrivateKey::from_bytes(bytes)?;
108 Ok(Self::from_private_key(private_key))
109 }
110
111 pub fn from_private_key_hex(hex_str: &str) -> AptosResult<Self> {
119 let private_key = Secp256r1PrivateKey::from_hex(hex_str)?;
120 Ok(Self::from_private_key(private_key))
121 }
122
123 pub fn address(&self) -> AccountAddress {
125 self.address
126 }
127
128 pub fn public_key(&self) -> &Secp256r1PublicKey {
130 &self.public_key
131 }
132
133 pub fn private_key(&self) -> &Secp256r1PrivateKey {
135 &self.private_key
136 }
137
138 pub fn sign_message(&self, message: &[u8]) -> crate::crypto::Secp256r1Signature {
140 self.private_key.sign(message)
141 }
142}
143
144#[allow(deprecated)]
145impl Account for Secp256r1Account {
146 fn address(&self) -> AccountAddress {
147 self.address
148 }
149
150 fn authentication_key(&self) -> AuthenticationKey {
151 let uncompressed = self.public_key.to_uncompressed_bytes();
152 let mut bcs_bytes = Vec::with_capacity(1 + 1 + uncompressed.len());
153 bcs_bytes.push(0x02); bcs_bytes.push(65); bcs_bytes.extend_from_slice(&uncompressed);
156 let key = derive_authentication_key(&bcs_bytes, SINGLE_KEY_SCHEME);
157 AuthenticationKey::new(key)
158 }
159
160 fn sign(&self, message: &[u8]) -> crate::error::AptosResult<Vec<u8>> {
161 let sig = self.private_key.sign(message).to_bytes().to_vec();
175 debug_assert_eq!(
176 sig.len(),
177 64,
178 "Secp256r1 signature must be exactly 64 bytes (R || S)"
179 );
180 let mut out = Vec::with_capacity(1 + 1 + sig.len());
181 out.push(0x02); out.push(64); out.extend_from_slice(&sig);
184 Ok(out)
185 }
186
187 fn public_key_bytes(&self) -> Vec<u8> {
188 let uncompressed = self.public_key.to_uncompressed_bytes();
191 let mut out = Vec::with_capacity(1 + 1 + uncompressed.len());
192 out.push(0x02); out.push(65); out.extend_from_slice(&uncompressed);
195 out
196 }
197
198 fn signature_scheme(&self) -> u8 {
199 SINGLE_KEY_SCHEME
200 }
201}
202
203#[allow(deprecated)]
204impl fmt::Debug for Secp256r1Account {
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 f.debug_struct("Secp256r1Account")
207 .field("address", &self.address)
208 .field("public_key", &self.public_key)
209 .finish_non_exhaustive()
210 }
211}
212
213#[cfg(test)]
214#[allow(deprecated)] mod tests {
216 use super::*;
217 use crate::account::Account;
218
219 #[test]
220 fn test_generate() {
221 let account = Secp256r1Account::generate();
222 assert!(!account.address().is_zero());
223 }
224
225 #[test]
226 fn test_from_private_key_roundtrip() {
227 let account = Secp256r1Account::generate();
228 let bytes = account.private_key().to_bytes();
229
230 let restored = Secp256r1Account::from_private_key_bytes(&bytes).unwrap();
231 assert_eq!(account.address(), restored.address());
232 }
233
234 #[test]
235 fn test_sign_and_verify() {
236 let account = Secp256r1Account::generate();
237 let message = b"hello world";
238
239 let signature = account.sign_message(message);
240 assert!(account.public_key().verify(message, &signature).is_ok());
241 }
242
243 #[test]
244 fn test_account_trait() {
245 let account = Secp256r1Account::generate();
246 let message = b"test message";
247
248 let sig_bytes = account.sign(message).unwrap();
250 assert_eq!(sig_bytes.len(), 66);
251 assert_eq!(sig_bytes[0], 0x02, "AnySignature::Secp256r1 variant tag");
252 assert_eq!(sig_bytes[1], 64, "ULEB128(64)");
253
254 let pub_key_bytes = account.public_key_bytes();
257 assert_eq!(pub_key_bytes.len(), 67);
258 assert_eq!(
259 pub_key_bytes[0], 0x02,
260 "AnyPublicKey::Secp256r1Ecdsa variant tag"
261 );
262 assert_eq!(pub_key_bytes[1], 65, "ULEB128(65)");
263 assert_eq!(pub_key_bytes[2], 0x04, "SEC1 uncompressed marker");
264
265 assert!(!account.authentication_key().as_bytes().is_empty());
266 }
267
268 #[test]
269 fn test_from_private_key() {
270 let original = Secp256r1Account::generate();
271 let private_key = original.private_key().clone();
272 let restored = Secp256r1Account::from_private_key(private_key);
273 assert_eq!(original.address(), restored.address());
274 }
275
276 #[test]
277 fn test_from_private_key_hex() {
278 let original = Secp256r1Account::generate();
279 let hex = original.private_key().to_hex();
280 let restored = Secp256r1Account::from_private_key_hex(&hex).unwrap();
281 assert_eq!(original.address(), restored.address());
282 }
283
284 #[test]
285 fn test_signature_scheme() {
286 let account = Secp256r1Account::generate();
287 assert_eq!(account.signature_scheme(), SINGLE_KEY_SCHEME);
288 }
289
290 #[test]
291 fn test_debug_output() {
292 let account = Secp256r1Account::generate();
293 let debug = format!("{account:?}");
294 assert!(debug.contains("Secp256r1Account"));
295 assert!(debug.contains("address"));
296 }
297
298 #[test]
299 fn test_invalid_private_key_bytes() {
300 let result = Secp256r1Account::from_private_key_bytes(&[0u8; 16]);
301 assert!(result.is_err());
302 }
303
304 #[test]
305 fn test_invalid_private_key_hex() {
306 let result = Secp256r1Account::from_private_key_hex("invalid");
307 assert!(result.is_err());
308 }
309}