aptos_sdk/account/
account.rs1use crate::error::AptosResult;
4use crate::types::AccountAddress;
5use serde::{Deserialize, Serialize};
6use std::fmt;
7
8#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13pub struct AuthenticationKey([u8; 32]);
14
15impl AuthenticationKey {
16 pub fn new(bytes: [u8; 32]) -> Self {
18 Self(bytes)
19 }
20
21 pub fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
27 if bytes.len() != 32 {
28 return Err(crate::error::AptosError::InvalidAddress(format!(
29 "authentication key must be 32 bytes, got {}",
30 bytes.len()
31 )));
32 }
33 let mut key = [0u8; 32];
34 key.copy_from_slice(bytes);
35 Ok(Self(key))
36 }
37
38 pub fn from_hex(hex_str: &str) -> AptosResult<Self> {
46 let hex_str = hex_str.strip_prefix("0x").unwrap_or(hex_str);
47 let bytes = hex::decode(hex_str)?;
48 Self::from_bytes(&bytes)
49 }
50
51 pub fn as_bytes(&self) -> &[u8; 32] {
53 &self.0
54 }
55
56 pub fn to_bytes(&self) -> [u8; 32] {
58 self.0
59 }
60
61 pub fn to_hex(&self) -> String {
63 format!("0x{}", hex::encode(self.0))
64 }
65
66 pub fn to_address(&self) -> AccountAddress {
70 AccountAddress::new(self.0)
71 }
72}
73
74impl fmt::Debug for AuthenticationKey {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 write!(f, "AuthenticationKey({})", self.to_hex())
77 }
78}
79
80impl fmt::Display for AuthenticationKey {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 write!(f, "{}", self.to_hex())
83 }
84}
85
86impl From<[u8; 32]> for AuthenticationKey {
87 fn from(bytes: [u8; 32]) -> Self {
88 Self(bytes)
89 }
90}
91
92impl From<AuthenticationKey> for [u8; 32] {
93 fn from(key: AuthenticationKey) -> Self {
94 key.0
95 }
96}
97
98impl From<AuthenticationKey> for AccountAddress {
99 fn from(key: AuthenticationKey) -> Self {
100 key.to_address()
101 }
102}
103
104pub trait Account: Send + Sync {
109 fn address(&self) -> AccountAddress;
111
112 fn authentication_key(&self) -> AuthenticationKey;
114
115 fn sign(&self, message: &[u8]) -> AptosResult<Vec<u8>>;
122
123 fn public_key_bytes(&self) -> Vec<u8>;
125
126 fn signature_scheme(&self) -> u8;
128}
129
130#[derive(Debug)]
135#[allow(clippy::large_enum_variant)] pub enum AnyAccount {
137 #[cfg(feature = "ed25519")]
139 Ed25519(super::Ed25519Account),
140 #[cfg(feature = "ed25519")]
142 MultiEd25519(super::MultiEd25519Account),
143 MultiKey(super::MultiKeyAccount),
145 #[cfg(feature = "keyless")]
147 Keyless(super::KeylessAccount),
148 #[cfg(feature = "secp256k1")]
150 Secp256k1(super::Secp256k1Account),
151}
152
153impl Account for AnyAccount {
154 fn address(&self) -> AccountAddress {
155 match self {
156 #[cfg(feature = "ed25519")]
157 AnyAccount::Ed25519(account) => account.address(),
158 #[cfg(feature = "ed25519")]
159 AnyAccount::MultiEd25519(account) => account.address(),
160 AnyAccount::MultiKey(account) => account.address(),
161 #[cfg(feature = "keyless")]
162 AnyAccount::Keyless(account) => account.address(),
163 #[cfg(feature = "secp256k1")]
164 AnyAccount::Secp256k1(account) => account.address(),
165 }
166 }
167
168 fn authentication_key(&self) -> AuthenticationKey {
169 match self {
170 #[cfg(feature = "ed25519")]
171 AnyAccount::Ed25519(account) => account.authentication_key(),
172 #[cfg(feature = "ed25519")]
173 AnyAccount::MultiEd25519(account) => account.authentication_key(),
174 AnyAccount::MultiKey(account) => account.authentication_key(),
175 #[cfg(feature = "keyless")]
176 AnyAccount::Keyless(account) => account.authentication_key(),
177 #[cfg(feature = "secp256k1")]
178 AnyAccount::Secp256k1(account) => account.authentication_key(),
179 }
180 }
181
182 fn sign(&self, message: &[u8]) -> AptosResult<Vec<u8>> {
183 match self {
184 #[cfg(feature = "ed25519")]
185 AnyAccount::Ed25519(account) => Account::sign(account, message),
186 #[cfg(feature = "ed25519")]
187 AnyAccount::MultiEd25519(account) => Account::sign(account, message),
188 AnyAccount::MultiKey(account) => Account::sign(account, message),
189 #[cfg(feature = "keyless")]
190 AnyAccount::Keyless(account) => Account::sign(account, message),
191 #[cfg(feature = "secp256k1")]
192 AnyAccount::Secp256k1(account) => Account::sign(account, message),
193 }
194 }
195
196 fn public_key_bytes(&self) -> Vec<u8> {
197 match self {
198 #[cfg(feature = "ed25519")]
199 AnyAccount::Ed25519(account) => account.public_key_bytes(),
200 #[cfg(feature = "ed25519")]
201 AnyAccount::MultiEd25519(account) => account.public_key_bytes(),
202 AnyAccount::MultiKey(account) => account.public_key_bytes(),
203 #[cfg(feature = "keyless")]
204 AnyAccount::Keyless(account) => account.public_key_bytes(),
205 #[cfg(feature = "secp256k1")]
206 AnyAccount::Secp256k1(account) => account.public_key_bytes(),
207 }
208 }
209
210 fn signature_scheme(&self) -> u8 {
211 match self {
212 #[cfg(feature = "ed25519")]
213 AnyAccount::Ed25519(account) => account.signature_scheme(),
214 #[cfg(feature = "ed25519")]
215 AnyAccount::MultiEd25519(account) => account.signature_scheme(),
216 AnyAccount::MultiKey(account) => account.signature_scheme(),
217 #[cfg(feature = "keyless")]
218 AnyAccount::Keyless(account) => account.signature_scheme(),
219 #[cfg(feature = "secp256k1")]
220 AnyAccount::Secp256k1(account) => account.signature_scheme(),
221 }
222 }
223}
224
225#[cfg(feature = "ed25519")]
226impl From<super::Ed25519Account> for AnyAccount {
227 fn from(account: super::Ed25519Account) -> Self {
228 AnyAccount::Ed25519(account)
229 }
230}
231
232#[cfg(feature = "ed25519")]
233impl From<super::MultiEd25519Account> for AnyAccount {
234 fn from(account: super::MultiEd25519Account) -> Self {
235 AnyAccount::MultiEd25519(account)
236 }
237}
238
239#[cfg(feature = "keyless")]
240impl From<super::KeylessAccount> for AnyAccount {
241 fn from(account: super::KeylessAccount) -> Self {
242 AnyAccount::Keyless(account)
243 }
244}
245
246#[cfg(feature = "secp256k1")]
247impl From<super::Secp256k1Account> for AnyAccount {
248 fn from(account: super::Secp256k1Account) -> Self {
249 AnyAccount::Secp256k1(account)
250 }
251}
252
253impl From<super::MultiKeyAccount> for AnyAccount {
254 fn from(account: super::MultiKeyAccount) -> Self {
255 AnyAccount::MultiKey(account)
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262
263 #[test]
264 fn test_authentication_key() {
265 let key = AuthenticationKey::new([1u8; 32]);
266 assert_eq!(key.as_bytes(), &[1u8; 32]);
267
268 let hex = key.to_hex();
269 let restored = AuthenticationKey::from_hex(&hex).unwrap();
270 assert_eq!(key, restored);
271 }
272
273 #[test]
274 fn test_auth_key_to_address() {
275 let key = AuthenticationKey::new([42u8; 32]);
276 let address = key.to_address();
277 assert_eq!(address.as_bytes(), &[42u8; 32]);
278 }
279
280 #[test]
281 fn test_auth_key_from_bytes() {
282 let bytes = [5u8; 32];
283 let key = AuthenticationKey::from_bytes(&bytes).unwrap();
284 assert_eq!(key.to_bytes(), bytes);
285 }
286
287 #[test]
288 fn test_auth_key_from_bytes_invalid_length() {
289 let bytes = [5u8; 16];
290 let result = AuthenticationKey::from_bytes(&bytes);
291 assert!(result.is_err());
292 }
293
294 #[test]
295 fn test_auth_key_from_hex_with_prefix() {
296 let key = AuthenticationKey::new([0xab; 32]);
297 let hex = key.to_hex();
298 assert!(hex.starts_with("0x"));
299 let restored = AuthenticationKey::from_hex(&hex).unwrap();
300 assert_eq!(key, restored);
301 }
302
303 #[test]
304 fn test_auth_key_from_hex_without_prefix() {
305 let key = AuthenticationKey::new([0xcd; 32]);
306 let hex = key.to_hex();
307 let hex_without_prefix = hex.trim_start_matches("0x");
308 let restored = AuthenticationKey::from_hex(hex_without_prefix).unwrap();
309 assert_eq!(key, restored);
310 }
311
312 #[test]
313 fn test_auth_key_display() {
314 let key = AuthenticationKey::new([0xff; 32]);
315 let display = format!("{key}");
316 assert!(display.starts_with("0x"));
317 assert_eq!(display.len(), 66); }
319
320 #[test]
321 fn test_auth_key_debug() {
322 let key = AuthenticationKey::new([0xaa; 32]);
323 let debug = format!("{key:?}");
324 assert!(debug.contains("AuthenticationKey"));
325 }
326
327 #[test]
328 fn test_auth_key_from_array() {
329 let bytes = [7u8; 32];
330 let key: AuthenticationKey = bytes.into();
331 assert_eq!(key.to_bytes(), bytes);
332 }
333
334 #[test]
335 fn test_auth_key_to_array() {
336 let key = AuthenticationKey::new([8u8; 32]);
337 let bytes: [u8; 32] = key.into();
338 assert_eq!(bytes, [8u8; 32]);
339 }
340
341 #[test]
342 fn test_auth_key_to_account_address() {
343 let key = AuthenticationKey::new([9u8; 32]);
344 let address: AccountAddress = key.into();
345 assert_eq!(address.as_bytes(), &[9u8; 32]);
346 }
347
348 #[cfg(feature = "ed25519")]
349 #[test]
350 fn test_any_account_from_ed25519() {
351 let ed25519 = super::super::Ed25519Account::generate();
352 let any_account: AnyAccount = ed25519.into();
353 if let AnyAccount::Ed25519(account) = any_account {
354 assert!(!account.address().is_zero());
355 } else {
356 panic!("Expected Ed25519 account");
357 }
358 }
359
360 #[cfg(feature = "ed25519")]
361 #[test]
362 fn test_any_account_ed25519_trait_methods() {
363 let ed25519 = super::super::Ed25519Account::generate();
364 let address = ed25519.address();
365 let auth_key = ed25519.authentication_key();
366 let any_account: AnyAccount = ed25519.into();
367
368 assert_eq!(any_account.address(), address);
369 assert_eq!(any_account.authentication_key(), auth_key);
370 assert!(!any_account.public_key_bytes().is_empty());
371
372 let sig = any_account.sign(b"test message").unwrap();
373 assert!(!sig.is_empty());
374 }
375
376 #[cfg(feature = "secp256k1")]
377 #[test]
378 fn test_any_account_from_secp256k1() {
379 let secp = super::super::Secp256k1Account::generate();
380 let any_account: AnyAccount = secp.into();
381 if let AnyAccount::Secp256k1(account) = any_account {
382 assert!(!account.address().is_zero());
383 } else {
384 panic!("Expected Secp256k1 account");
385 }
386 }
387
388 #[cfg(feature = "secp256k1")]
389 #[test]
390 fn test_any_account_secp256k1_trait_methods() {
391 let secp = super::super::Secp256k1Account::generate();
392 let address = secp.address();
393 let auth_key = secp.authentication_key();
394 let any_account: AnyAccount = secp.into();
395
396 assert_eq!(any_account.address(), address);
397 assert_eq!(any_account.authentication_key(), auth_key);
398 assert!(!any_account.public_key_bytes().is_empty());
399
400 let sig = any_account.sign(b"test message").unwrap();
401 assert!(!sig.is_empty());
402 }
403
404 #[cfg(feature = "ed25519")]
405 #[test]
406 fn test_any_account_from_multi_ed25519() {
407 use crate::crypto::Ed25519PrivateKey;
408
409 let keys: Vec<_> = (0..2).map(|_| Ed25519PrivateKey::generate()).collect();
410 let account = super::super::MultiEd25519Account::new(keys, 2).unwrap();
411 let any_account: AnyAccount = account.into();
412
413 if let AnyAccount::MultiEd25519(_) = any_account {
414 } else {
416 panic!("Expected MultiEd25519 account");
417 }
418 }
419
420 #[cfg(feature = "ed25519")]
421 #[test]
422 fn test_any_account_multi_ed25519_trait_methods() {
423 use crate::crypto::Ed25519PrivateKey;
424
425 let keys: Vec<_> = (0..2).map(|_| Ed25519PrivateKey::generate()).collect();
426 let account = super::super::MultiEd25519Account::new(keys, 2).unwrap();
427 let address = account.address();
428 let auth_key = account.authentication_key();
429 let any_account: AnyAccount = account.into();
430
431 assert_eq!(any_account.address(), address);
432 assert_eq!(any_account.authentication_key(), auth_key);
433 assert!(!any_account.public_key_bytes().is_empty());
434 assert!(any_account.signature_scheme() > 0);
435
436 let sig = any_account.sign(b"test").unwrap();
437 assert!(!sig.is_empty());
438 }
439
440 #[cfg(feature = "ed25519")]
441 #[test]
442 fn test_any_account_from_multi_key() {
443 use crate::account::AnyPrivateKey;
444 use crate::crypto::Ed25519PrivateKey;
445
446 let keys: Vec<_> = (0..2)
447 .map(|_| AnyPrivateKey::ed25519(Ed25519PrivateKey::generate()))
448 .collect();
449 let account = super::super::MultiKeyAccount::new(keys, 2).unwrap();
450 let any_account: AnyAccount = account.into();
451
452 if let AnyAccount::MultiKey(_) = any_account {
453 } else {
455 panic!("Expected MultiKey account");
456 }
457 }
458
459 #[cfg(feature = "ed25519")]
460 #[test]
461 fn test_any_account_multi_key_trait_methods() {
462 use crate::account::AnyPrivateKey;
463 use crate::crypto::Ed25519PrivateKey;
464
465 let keys: Vec<_> = (0..2)
466 .map(|_| AnyPrivateKey::ed25519(Ed25519PrivateKey::generate()))
467 .collect();
468 let account = super::super::MultiKeyAccount::new(keys, 2).unwrap();
469 let address = account.address();
470 let auth_key = account.authentication_key();
471 let any_account: AnyAccount = account.into();
472
473 assert_eq!(any_account.address(), address);
474 assert_eq!(any_account.authentication_key(), auth_key);
475 assert!(!any_account.public_key_bytes().is_empty());
476
477 let sig = any_account.sign(b"test").unwrap();
478 assert!(!sig.is_empty());
479 }
480
481 #[test]
482 fn test_auth_key_json_serialization() {
483 let key = AuthenticationKey::new([0xab; 32]);
484 let json = serde_json::to_string(&key).unwrap();
485 let restored: AuthenticationKey = serde_json::from_str(&json).unwrap();
486 assert_eq!(key, restored);
487 }
488
489 #[test]
490 fn test_auth_key_hash() {
491 use std::collections::HashSet;
492 let key1 = AuthenticationKey::new([1u8; 32]);
493 let key2 = AuthenticationKey::new([2u8; 32]);
494
495 let mut set = HashSet::new();
496 set.insert(key1);
497 set.insert(key2);
498 assert_eq!(set.len(), 2);
499 assert!(set.contains(&key1));
500 }
501
502 #[test]
503 fn test_auth_key_clone() {
504 let key = AuthenticationKey::new([42u8; 32]);
505 let cloned = key;
506 assert_eq!(key, cloned);
507 }
508
509 #[test]
510 fn test_any_account_debug() {
511 #[cfg(feature = "ed25519")]
512 {
513 let ed25519 = super::super::Ed25519Account::generate();
514 let any_account: AnyAccount = ed25519.into();
515 let debug = format!("{any_account:?}");
516 assert!(debug.contains("Ed25519"));
517 }
518 }
519}