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