use crate::error::AptosResult;
use crate::types::AccountAddress;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AuthenticationKey([u8; 32]);
impl AuthenticationKey {
pub fn new(bytes: [u8; 32]) -> Self {
Self(bytes)
}
pub fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
if bytes.len() != 32 {
return Err(crate::error::AptosError::InvalidAddress(format!(
"authentication key must be 32 bytes, got {}",
bytes.len()
)));
}
let mut key = [0u8; 32];
key.copy_from_slice(bytes);
Ok(Self(key))
}
pub fn from_hex(hex_str: &str) -> AptosResult<Self> {
let bytes = const_hex::decode(hex_str)?;
Self::from_bytes(&bytes)
}
pub fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0
}
pub fn to_hex(&self) -> String {
const_hex::encode_prefixed(self.0)
}
pub fn to_address(&self) -> AccountAddress {
AccountAddress::new(self.0)
}
}
impl fmt::Debug for AuthenticationKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "AuthenticationKey({})", self.to_hex())
}
}
impl fmt::Display for AuthenticationKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl From<[u8; 32]> for AuthenticationKey {
fn from(bytes: [u8; 32]) -> Self {
Self(bytes)
}
}
impl From<AuthenticationKey> for [u8; 32] {
fn from(key: AuthenticationKey) -> Self {
key.0
}
}
impl From<AuthenticationKey> for AccountAddress {
fn from(key: AuthenticationKey) -> Self {
key.to_address()
}
}
pub trait Account: Send + Sync {
fn address(&self) -> AccountAddress;
fn authentication_key(&self) -> AuthenticationKey;
fn sign(&self, message: &[u8]) -> AptosResult<Vec<u8>>;
fn public_key_bytes(&self) -> Vec<u8>;
fn signature_scheme(&self) -> u8;
}
#[derive(Debug)]
#[allow(clippy::large_enum_variant)] pub enum AnyAccount {
#[cfg(feature = "ed25519")]
Ed25519(super::Ed25519Account),
#[cfg(feature = "ed25519")]
MultiEd25519(super::MultiEd25519Account),
MultiKey(super::MultiKeyAccount),
#[cfg(feature = "keyless")]
Keyless(super::KeylessAccount),
#[cfg(feature = "secp256k1")]
Secp256k1(super::Secp256k1Account),
}
impl Account for AnyAccount {
fn address(&self) -> AccountAddress {
match self {
#[cfg(feature = "ed25519")]
AnyAccount::Ed25519(account) => account.address(),
#[cfg(feature = "ed25519")]
AnyAccount::MultiEd25519(account) => account.address(),
AnyAccount::MultiKey(account) => account.address(),
#[cfg(feature = "keyless")]
AnyAccount::Keyless(account) => account.address(),
#[cfg(feature = "secp256k1")]
AnyAccount::Secp256k1(account) => account.address(),
}
}
fn authentication_key(&self) -> AuthenticationKey {
match self {
#[cfg(feature = "ed25519")]
AnyAccount::Ed25519(account) => account.authentication_key(),
#[cfg(feature = "ed25519")]
AnyAccount::MultiEd25519(account) => account.authentication_key(),
AnyAccount::MultiKey(account) => account.authentication_key(),
#[cfg(feature = "keyless")]
AnyAccount::Keyless(account) => account.authentication_key(),
#[cfg(feature = "secp256k1")]
AnyAccount::Secp256k1(account) => account.authentication_key(),
}
}
fn sign(&self, message: &[u8]) -> AptosResult<Vec<u8>> {
match self {
#[cfg(feature = "ed25519")]
AnyAccount::Ed25519(account) => Account::sign(account, message),
#[cfg(feature = "ed25519")]
AnyAccount::MultiEd25519(account) => Account::sign(account, message),
AnyAccount::MultiKey(account) => Account::sign(account, message),
#[cfg(feature = "keyless")]
AnyAccount::Keyless(account) => Account::sign(account, message),
#[cfg(feature = "secp256k1")]
AnyAccount::Secp256k1(account) => Account::sign(account, message),
}
}
fn public_key_bytes(&self) -> Vec<u8> {
match self {
#[cfg(feature = "ed25519")]
AnyAccount::Ed25519(account) => account.public_key_bytes(),
#[cfg(feature = "ed25519")]
AnyAccount::MultiEd25519(account) => account.public_key_bytes(),
AnyAccount::MultiKey(account) => account.public_key_bytes(),
#[cfg(feature = "keyless")]
AnyAccount::Keyless(account) => account.public_key_bytes(),
#[cfg(feature = "secp256k1")]
AnyAccount::Secp256k1(account) => account.public_key_bytes(),
}
}
fn signature_scheme(&self) -> u8 {
match self {
#[cfg(feature = "ed25519")]
AnyAccount::Ed25519(account) => account.signature_scheme(),
#[cfg(feature = "ed25519")]
AnyAccount::MultiEd25519(account) => account.signature_scheme(),
AnyAccount::MultiKey(account) => account.signature_scheme(),
#[cfg(feature = "keyless")]
AnyAccount::Keyless(account) => account.signature_scheme(),
#[cfg(feature = "secp256k1")]
AnyAccount::Secp256k1(account) => account.signature_scheme(),
}
}
}
#[cfg(feature = "ed25519")]
impl From<super::Ed25519Account> for AnyAccount {
fn from(account: super::Ed25519Account) -> Self {
AnyAccount::Ed25519(account)
}
}
#[cfg(feature = "ed25519")]
impl From<super::MultiEd25519Account> for AnyAccount {
fn from(account: super::MultiEd25519Account) -> Self {
AnyAccount::MultiEd25519(account)
}
}
#[cfg(feature = "keyless")]
impl From<super::KeylessAccount> for AnyAccount {
fn from(account: super::KeylessAccount) -> Self {
AnyAccount::Keyless(account)
}
}
#[cfg(feature = "secp256k1")]
impl From<super::Secp256k1Account> for AnyAccount {
fn from(account: super::Secp256k1Account) -> Self {
AnyAccount::Secp256k1(account)
}
}
impl From<super::MultiKeyAccount> for AnyAccount {
fn from(account: super::MultiKeyAccount) -> Self {
AnyAccount::MultiKey(account)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_authentication_key() {
let key = AuthenticationKey::new([1u8; 32]);
assert_eq!(key.as_bytes(), &[1u8; 32]);
let hex = key.to_hex();
let restored = AuthenticationKey::from_hex(&hex).unwrap();
assert_eq!(key, restored);
}
#[test]
fn test_auth_key_to_address() {
let key = AuthenticationKey::new([42u8; 32]);
let address = key.to_address();
assert_eq!(address.as_bytes(), &[42u8; 32]);
}
#[test]
fn test_auth_key_from_bytes() {
let bytes = [5u8; 32];
let key = AuthenticationKey::from_bytes(&bytes).unwrap();
assert_eq!(key.to_bytes(), bytes);
}
#[test]
fn test_auth_key_from_bytes_invalid_length() {
let bytes = [5u8; 16];
let result = AuthenticationKey::from_bytes(&bytes);
assert!(result.is_err());
}
#[test]
fn test_auth_key_from_hex_with_prefix() {
let key = AuthenticationKey::new([0xab; 32]);
let hex = key.to_hex();
assert!(hex.starts_with("0x"));
let restored = AuthenticationKey::from_hex(&hex).unwrap();
assert_eq!(key, restored);
}
#[test]
fn test_auth_key_from_hex_without_prefix() {
let key = AuthenticationKey::new([0xcd; 32]);
let hex = key.to_hex();
let hex_without_prefix = hex.trim_start_matches("0x");
let restored = AuthenticationKey::from_hex(hex_without_prefix).unwrap();
assert_eq!(key, restored);
}
#[test]
fn test_auth_key_display() {
let key = AuthenticationKey::new([0xff; 32]);
let display = format!("{key}");
assert!(display.starts_with("0x"));
assert_eq!(display.len(), 66); }
#[test]
fn test_auth_key_debug() {
let key = AuthenticationKey::new([0xaa; 32]);
let debug = format!("{key:?}");
assert!(debug.contains("AuthenticationKey"));
}
#[test]
fn test_auth_key_from_array() {
let bytes = [7u8; 32];
let key: AuthenticationKey = bytes.into();
assert_eq!(key.to_bytes(), bytes);
}
#[test]
fn test_auth_key_to_array() {
let key = AuthenticationKey::new([8u8; 32]);
let bytes: [u8; 32] = key.into();
assert_eq!(bytes, [8u8; 32]);
}
#[test]
fn test_auth_key_to_account_address() {
let key = AuthenticationKey::new([9u8; 32]);
let address: AccountAddress = key.into();
assert_eq!(address.as_bytes(), &[9u8; 32]);
}
#[cfg(feature = "ed25519")]
#[test]
fn test_any_account_from_ed25519() {
let ed25519 = super::super::Ed25519Account::generate();
let any_account: AnyAccount = ed25519.into();
if let AnyAccount::Ed25519(account) = any_account {
assert!(!account.address().is_zero());
} else {
panic!("Expected Ed25519 account");
}
}
#[cfg(feature = "ed25519")]
#[test]
fn test_any_account_ed25519_trait_methods() {
let ed25519 = super::super::Ed25519Account::generate();
let address = ed25519.address();
let auth_key = ed25519.authentication_key();
let any_account: AnyAccount = ed25519.into();
assert_eq!(any_account.address(), address);
assert_eq!(any_account.authentication_key(), auth_key);
assert!(!any_account.public_key_bytes().is_empty());
let sig = any_account.sign(b"test message").unwrap();
assert!(!sig.is_empty());
}
#[cfg(feature = "secp256k1")]
#[test]
fn test_any_account_from_secp256k1() {
let secp = super::super::Secp256k1Account::generate();
let any_account: AnyAccount = secp.into();
if let AnyAccount::Secp256k1(account) = any_account {
assert!(!account.address().is_zero());
} else {
panic!("Expected Secp256k1 account");
}
}
#[cfg(feature = "secp256k1")]
#[test]
fn test_any_account_secp256k1_trait_methods() {
let secp = super::super::Secp256k1Account::generate();
let address = secp.address();
let auth_key = secp.authentication_key();
let any_account: AnyAccount = secp.into();
assert_eq!(any_account.address(), address);
assert_eq!(any_account.authentication_key(), auth_key);
assert!(!any_account.public_key_bytes().is_empty());
let sig = any_account.sign(b"test message").unwrap();
assert!(!sig.is_empty());
}
#[cfg(feature = "ed25519")]
#[test]
fn test_any_account_from_multi_ed25519() {
use crate::crypto::Ed25519PrivateKey;
let keys: Vec<_> = (0..2).map(|_| Ed25519PrivateKey::generate()).collect();
let account = super::super::MultiEd25519Account::new(keys, 2).unwrap();
let any_account: AnyAccount = account.into();
if let AnyAccount::MultiEd25519(_) = any_account {
} else {
panic!("Expected MultiEd25519 account");
}
}
#[cfg(feature = "ed25519")]
#[test]
fn test_any_account_multi_ed25519_trait_methods() {
use crate::crypto::Ed25519PrivateKey;
let keys: Vec<_> = (0..2).map(|_| Ed25519PrivateKey::generate()).collect();
let account = super::super::MultiEd25519Account::new(keys, 2).unwrap();
let address = account.address();
let auth_key = account.authentication_key();
let any_account: AnyAccount = account.into();
assert_eq!(any_account.address(), address);
assert_eq!(any_account.authentication_key(), auth_key);
assert!(!any_account.public_key_bytes().is_empty());
assert!(any_account.signature_scheme() > 0);
let sig = any_account.sign(b"test").unwrap();
assert!(!sig.is_empty());
}
#[cfg(feature = "ed25519")]
#[test]
fn test_any_account_from_multi_key() {
use crate::account::AnyPrivateKey;
use crate::crypto::Ed25519PrivateKey;
let keys: Vec<_> = (0..2)
.map(|_| AnyPrivateKey::ed25519(Ed25519PrivateKey::generate()))
.collect();
let account = super::super::MultiKeyAccount::new(keys, 2).unwrap();
let any_account: AnyAccount = account.into();
if let AnyAccount::MultiKey(_) = any_account {
} else {
panic!("Expected MultiKey account");
}
}
#[cfg(feature = "ed25519")]
#[test]
fn test_any_account_multi_key_trait_methods() {
use crate::account::AnyPrivateKey;
use crate::crypto::Ed25519PrivateKey;
let keys: Vec<_> = (0..2)
.map(|_| AnyPrivateKey::ed25519(Ed25519PrivateKey::generate()))
.collect();
let account = super::super::MultiKeyAccount::new(keys, 2).unwrap();
let address = account.address();
let auth_key = account.authentication_key();
let any_account: AnyAccount = account.into();
assert_eq!(any_account.address(), address);
assert_eq!(any_account.authentication_key(), auth_key);
assert!(!any_account.public_key_bytes().is_empty());
let sig = any_account.sign(b"test").unwrap();
assert!(!sig.is_empty());
}
#[test]
fn test_auth_key_json_serialization() {
let key = AuthenticationKey::new([0xab; 32]);
let json = serde_json::to_string(&key).unwrap();
let restored: AuthenticationKey = serde_json::from_str(&json).unwrap();
assert_eq!(key, restored);
}
#[test]
fn test_auth_key_hash() {
use std::collections::HashSet;
let key1 = AuthenticationKey::new([1u8; 32]);
let key2 = AuthenticationKey::new([2u8; 32]);
let mut set = HashSet::new();
set.insert(key1);
set.insert(key2);
assert_eq!(set.len(), 2);
assert!(set.contains(&key1));
}
#[test]
fn test_auth_key_clone() {
let key = AuthenticationKey::new([42u8; 32]);
let cloned = key;
assert_eq!(key, cloned);
}
#[test]
fn test_any_account_debug() {
#[cfg(feature = "ed25519")]
{
let ed25519 = super::super::Ed25519Account::generate();
let any_account: AnyAccount = ed25519.into();
let debug = format!("{any_account:?}");
assert!(debug.contains("Ed25519"));
}
}
}