aptos_sdk/account/
ed25519.rs1#[cfg(feature = "mnemonic")]
15use crate::account::Mnemonic;
16use crate::account::account::{Account, AuthenticationKey};
17use crate::crypto::{
18 ED25519_SCHEME, Ed25519PrivateKey, Ed25519PublicKey, SINGLE_KEY_SCHEME,
19 derive_authentication_key,
20};
21use crate::error::AptosResult;
22use crate::types::AccountAddress;
23use std::fmt;
24
25#[derive(Clone)]
39pub struct Ed25519Account {
40 private_key: Ed25519PrivateKey,
41 public_key: Ed25519PublicKey,
42 address: AccountAddress,
43}
44
45impl Ed25519Account {
46 pub fn generate() -> Self {
48 let private_key = Ed25519PrivateKey::generate();
49 Self::from_private_key(private_key)
50 }
51
52 pub fn from_private_key(private_key: Ed25519PrivateKey) -> Self {
54 let public_key = private_key.public_key();
55 let address = public_key.to_address();
56 Self {
57 private_key,
58 public_key,
59 address,
60 }
61 }
62
63 pub fn from_private_key_bytes(bytes: &[u8]) -> AptosResult<Self> {
69 let private_key = Ed25519PrivateKey::from_bytes(bytes)?;
70 Ok(Self::from_private_key(private_key))
71 }
72
73 pub fn from_private_key_hex(hex_str: &str) -> AptosResult<Self> {
81 let private_key = Ed25519PrivateKey::from_hex(hex_str)?;
82 Ok(Self::from_private_key(private_key))
83 }
84
85 #[cfg(feature = "mnemonic")]
107 pub fn from_mnemonic(mnemonic: &str, index: u32) -> AptosResult<Self> {
108 let mnemonic = Mnemonic::from_phrase(mnemonic)?;
109 let private_key = mnemonic.derive_ed25519_key(index)?;
110 Ok(Self::from_private_key(private_key))
111 }
112
113 #[cfg(feature = "mnemonic")]
121 pub fn generate_with_mnemonic() -> AptosResult<(Self, String)> {
122 let mnemonic = Mnemonic::generate(24)?;
123 let phrase = mnemonic.phrase().to_string();
124 let private_key = mnemonic.derive_ed25519_key(0)?;
125 let account = Self::from_private_key(private_key);
126 Ok((account, phrase))
127 }
128
129 #[must_use]
138 pub fn with_address(mut self, address: AccountAddress) -> Self {
139 self.address = address;
140 self
141 }
142
143 pub fn address(&self) -> AccountAddress {
145 self.address
146 }
147
148 pub fn public_key(&self) -> &Ed25519PublicKey {
150 &self.public_key
151 }
152
153 pub fn private_key(&self) -> &Ed25519PrivateKey {
157 &self.private_key
158 }
159
160 pub fn sign_message(&self, message: &[u8]) -> crate::crypto::Ed25519Signature {
162 self.private_key.sign(message)
163 }
164}
165
166impl Account for Ed25519Account {
167 fn address(&self) -> AccountAddress {
168 self.address
169 }
170
171 fn authentication_key(&self) -> AuthenticationKey {
172 AuthenticationKey::new(self.public_key.to_authentication_key())
173 }
174
175 fn sign(&self, message: &[u8]) -> AptosResult<Vec<u8>> {
176 Ok(self.private_key.sign(message).to_bytes().to_vec())
177 }
178
179 fn public_key_bytes(&self) -> Vec<u8> {
180 self.public_key.to_bytes().to_vec()
181 }
182
183 fn signature_scheme(&self) -> u8 {
184 ED25519_SCHEME
185 }
186}
187
188impl fmt::Debug for Ed25519Account {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 f.debug_struct("Ed25519Account")
191 .field("address", &self.address)
192 .field("public_key", &self.public_key)
193 .finish_non_exhaustive()
194 }
195}
196
197#[derive(Clone)]
225pub struct Ed25519SingleKeyAccount {
226 private_key: Ed25519PrivateKey,
227 public_key: Ed25519PublicKey,
228 address: AccountAddress,
229}
230
231impl Ed25519SingleKeyAccount {
232 pub fn generate() -> Self {
234 let private_key = Ed25519PrivateKey::generate();
235 Self::from_private_key(private_key)
236 }
237
238 pub fn from_private_key(private_key: Ed25519PrivateKey) -> Self {
240 let public_key = private_key.public_key();
241 let address = Self::derive_address(&public_key);
242 Self {
243 private_key,
244 public_key,
245 address,
246 }
247 }
248
249 pub fn from_private_key_bytes(bytes: &[u8]) -> AptosResult<Self> {
255 let private_key = Ed25519PrivateKey::from_bytes(bytes)?;
256 Ok(Self::from_private_key(private_key))
257 }
258
259 pub fn from_private_key_hex(hex_str: &str) -> AptosResult<Self> {
267 let private_key = Ed25519PrivateKey::from_hex(hex_str)?;
268 Ok(Self::from_private_key(private_key))
269 }
270
271 #[cfg(feature = "mnemonic")]
279 pub fn from_mnemonic(mnemonic: &str, index: u32) -> AptosResult<Self> {
280 let mnemonic = Mnemonic::from_phrase(mnemonic)?;
281 let private_key = mnemonic.derive_ed25519_key(index)?;
282 Ok(Self::from_private_key(private_key))
283 }
284
285 pub fn address(&self) -> AccountAddress {
287 self.address
288 }
289
290 pub fn public_key(&self) -> &Ed25519PublicKey {
292 &self.public_key
293 }
294
295 pub fn private_key(&self) -> &Ed25519PrivateKey {
297 &self.private_key
298 }
299
300 pub fn sign_message(&self, message: &[u8]) -> crate::crypto::Ed25519Signature {
302 self.private_key.sign(message)
303 }
304
305 fn derive_address(public_key: &Ed25519PublicKey) -> AccountAddress {
307 let pk_bytes = public_key.to_bytes();
309 let mut bcs_bytes = Vec::with_capacity(1 + 1 + pk_bytes.len());
310 bcs_bytes.push(0x00); bcs_bytes.push(32); bcs_bytes.extend_from_slice(&pk_bytes);
313 let auth_key = derive_authentication_key(&bcs_bytes, SINGLE_KEY_SCHEME);
314 AccountAddress::new(auth_key)
315 }
316
317 fn bcs_public_key_bytes(&self) -> Vec<u8> {
321 let pk_bytes = self.public_key.to_bytes();
322 let mut bcs_bytes = Vec::with_capacity(1 + 1 + pk_bytes.len());
323 bcs_bytes.push(0x00); bcs_bytes.push(32); bcs_bytes.extend_from_slice(&pk_bytes);
326 bcs_bytes
327 }
328
329 fn bcs_signature_bytes(sig: &crate::crypto::Ed25519Signature) -> Vec<u8> {
333 let sig_bytes = sig.to_bytes();
334 let mut out = Vec::with_capacity(1 + 1 + sig_bytes.len());
335 out.push(0x00); out.push(64); out.extend_from_slice(&sig_bytes);
338 out
339 }
340}
341
342impl Account for Ed25519SingleKeyAccount {
343 fn address(&self) -> AccountAddress {
344 self.address
345 }
346
347 fn authentication_key(&self) -> AuthenticationKey {
348 let bcs_bytes = self.bcs_public_key_bytes();
349 let key = derive_authentication_key(&bcs_bytes, SINGLE_KEY_SCHEME);
350 AuthenticationKey::new(key)
351 }
352
353 fn sign(&self, message: &[u8]) -> AptosResult<Vec<u8>> {
354 let sig = self.private_key.sign(message);
358 Ok(Self::bcs_signature_bytes(&sig))
359 }
360
361 fn public_key_bytes(&self) -> Vec<u8> {
362 self.bcs_public_key_bytes()
364 }
365
366 fn signature_scheme(&self) -> u8 {
367 SINGLE_KEY_SCHEME
368 }
369}
370
371impl fmt::Debug for Ed25519SingleKeyAccount {
372 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
373 f.debug_struct("Ed25519SingleKeyAccount")
374 .field("address", &self.address)
375 .field("public_key", &self.public_key)
376 .finish_non_exhaustive()
377 }
378}
379
380#[cfg(test)]
381mod tests {
382 use super::*;
383
384 #[test]
385 fn test_generate() {
386 let account = Ed25519Account::generate();
387 assert!(!account.address().is_zero());
388 }
389
390 #[test]
391 #[cfg(feature = "mnemonic")]
392 fn test_from_mnemonic() {
393 let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
395 let account = Ed25519Account::from_mnemonic(mnemonic, 0).unwrap();
396
397 let account2 = Ed25519Account::from_mnemonic(mnemonic, 0).unwrap();
399 assert_eq!(account.address(), account2.address());
400
401 let account3 = Ed25519Account::from_mnemonic(mnemonic, 1).unwrap();
403 assert_ne!(account.address(), account3.address());
404 }
405
406 #[test]
407 fn test_sign_and_verify() {
408 let account = Ed25519Account::generate();
409 let message = b"hello world";
410
411 let signature = account.sign_message(message);
412 assert!(account.public_key().verify(message, &signature).is_ok());
413 }
414
415 #[test]
416 #[cfg(feature = "mnemonic")]
417 fn test_generate_with_mnemonic() {
418 let (account, mnemonic) = Ed25519Account::generate_with_mnemonic().unwrap();
419
420 let restored = Ed25519Account::from_mnemonic(&mnemonic, 0).unwrap();
422 assert_eq!(account.address(), restored.address());
423 }
424
425 #[test]
426 fn test_from_private_key() {
427 let original = Ed25519Account::generate();
428 let private_key = original.private_key().clone();
429 let restored = Ed25519Account::from_private_key(private_key);
430 assert_eq!(original.address(), restored.address());
431 }
432
433 #[test]
434 fn test_from_private_key_bytes() {
435 let original = Ed25519Account::generate();
436 let bytes = original.private_key().to_bytes();
437 let restored = Ed25519Account::from_private_key_bytes(&bytes).unwrap();
438 assert_eq!(original.address(), restored.address());
439 }
440
441 #[test]
442 fn test_from_private_key_hex() {
443 let original = Ed25519Account::generate();
444 let hex = original.private_key().to_hex();
445 let restored = Ed25519Account::from_private_key_hex(&hex).unwrap();
446 assert_eq!(original.address(), restored.address());
447 }
448
449 #[test]
450 fn test_authentication_key() {
451 let account = Ed25519Account::generate();
452 let auth_key = account.authentication_key();
453 assert_eq!(auth_key.as_bytes().len(), 32);
454 }
455
456 #[test]
457 fn test_public_key_bytes() {
458 let account = Ed25519Account::generate();
459 let bytes = account.public_key_bytes();
460 assert_eq!(bytes.len(), 32);
461 }
462
463 #[test]
464 fn test_signature_scheme() {
465 let account = Ed25519Account::generate();
466 assert_eq!(account.signature_scheme(), ED25519_SCHEME);
467 }
468
469 #[test]
470 fn test_sign_trait() {
471 let account = Ed25519Account::generate();
472 let message = b"test message";
473 let sig_bytes = account.sign(message).unwrap();
474 assert_eq!(sig_bytes.len(), 64);
475 }
476
477 #[test]
478 fn test_debug_output() {
479 let account = Ed25519Account::generate();
480 let debug = format!("{account:?}");
481 assert!(debug.contains("Ed25519Account"));
482 assert!(debug.contains("address"));
483 }
484
485 #[test]
486 fn test_invalid_private_key_bytes() {
487 let result = Ed25519Account::from_private_key_bytes(&[0u8; 16]);
488 assert!(result.is_err());
489 }
490
491 #[test]
492 fn test_invalid_private_key_hex() {
493 let result = Ed25519Account::from_private_key_hex("invalid");
494 assert!(result.is_err());
495 }
496
497 #[test]
498 #[cfg(feature = "mnemonic")]
499 fn test_invalid_mnemonic() {
500 let result = Ed25519Account::from_mnemonic("invalid mnemonic phrase", 0);
501 assert!(result.is_err());
502 }
503
504 #[test]
507 fn test_single_key_generate() {
508 let account = Ed25519SingleKeyAccount::generate();
509 assert!(!account.address().is_zero());
510 }
511
512 #[test]
513 fn test_single_key_different_address() {
514 let legacy_account = Ed25519Account::generate();
516 let private_key = legacy_account.private_key().clone();
517
518 let single_key_account = Ed25519SingleKeyAccount::from_private_key(private_key);
519
520 assert_ne!(legacy_account.address(), single_key_account.address());
522 }
523
524 #[test]
525 fn test_single_key_sign_and_verify() {
526 let account = Ed25519SingleKeyAccount::generate();
527 let message = b"hello world";
528
529 let signature = account.sign_message(message);
530 assert!(account.public_key().verify(message, &signature).is_ok());
531 }
532
533 #[test]
534 fn test_single_key_from_private_key() {
535 let original = Ed25519SingleKeyAccount::generate();
536 let private_key = original.private_key().clone();
537 let restored = Ed25519SingleKeyAccount::from_private_key(private_key);
538 assert_eq!(original.address(), restored.address());
539 }
540
541 #[test]
542 fn test_single_key_from_private_key_bytes() {
543 let original = Ed25519SingleKeyAccount::generate();
544 let bytes = original.private_key().to_bytes();
545 let restored = Ed25519SingleKeyAccount::from_private_key_bytes(&bytes).unwrap();
546 assert_eq!(original.address(), restored.address());
547 }
548
549 #[test]
550 fn test_single_key_from_private_key_hex() {
551 let original = Ed25519SingleKeyAccount::generate();
552 let hex = original.private_key().to_hex();
553 let restored = Ed25519SingleKeyAccount::from_private_key_hex(&hex).unwrap();
554 assert_eq!(original.address(), restored.address());
555 }
556
557 #[test]
558 fn test_single_key_authentication_key() {
559 let account = Ed25519SingleKeyAccount::generate();
560 let auth_key = account.authentication_key();
561 assert_eq!(auth_key.as_bytes().len(), 32);
562 }
563
564 #[test]
565 fn test_single_key_public_key_bytes() {
566 let account = Ed25519SingleKeyAccount::generate();
567 let bytes = account.public_key_bytes();
568 assert_eq!(bytes.len(), 34);
570 assert_eq!(bytes[0], 0x00); assert_eq!(bytes[1], 32); }
573
574 #[test]
575 fn test_single_key_signature_scheme() {
576 let account = Ed25519SingleKeyAccount::generate();
577 assert_eq!(account.signature_scheme(), SINGLE_KEY_SCHEME);
578 }
579
580 #[test]
581 fn test_single_key_sign_trait() {
582 let account = Ed25519SingleKeyAccount::generate();
583 let message = b"test message";
584 let sig_bytes = account.sign(message).unwrap();
585 assert_eq!(sig_bytes.len(), 66);
587 assert_eq!(sig_bytes[0], 0x00, "AnySignature::Ed25519 variant tag");
588 assert_eq!(sig_bytes[1], 64, "ULEB128(64)");
589 }
590
591 #[test]
592 fn test_single_key_debug_output() {
593 let account = Ed25519SingleKeyAccount::generate();
594 let debug = format!("{account:?}");
595 assert!(debug.contains("Ed25519SingleKeyAccount"));
596 assert!(debug.contains("address"));
597 }
598
599 #[test]
600 #[cfg(feature = "mnemonic")]
601 fn test_single_key_from_mnemonic() {
602 let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
603 let account = Ed25519SingleKeyAccount::from_mnemonic(mnemonic, 0).unwrap();
604
605 let account2 = Ed25519SingleKeyAccount::from_mnemonic(mnemonic, 0).unwrap();
607 assert_eq!(account.address(), account2.address());
608
609 let account3 = Ed25519SingleKeyAccount::from_mnemonic(mnemonic, 1).unwrap();
611 assert_ne!(account.address(), account3.address());
612 }
613
614 #[test]
615 #[cfg(feature = "mnemonic")]
616 fn test_single_key_vs_legacy_mnemonic() {
617 let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
618
619 let legacy = Ed25519Account::from_mnemonic(mnemonic, 0).unwrap();
620 let single_key = Ed25519SingleKeyAccount::from_mnemonic(mnemonic, 0).unwrap();
621
622 assert_eq!(
624 legacy.private_key().to_bytes(),
625 single_key.private_key().to_bytes()
626 );
627 assert_ne!(legacy.address(), single_key.address());
628 }
629}