use crate::types::AccountAddress;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Ed25519PublicKey(pub [u8; 32]);
impl Serialize for Ed25519PublicKey {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serde_bytes::Bytes::new(&self.0).serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Ed25519PublicKey {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let bytes: Vec<u8> = serde_bytes::deserialize(deserializer)?;
if bytes.len() != 32 {
return Err(serde::de::Error::invalid_length(bytes.len(), &"32 bytes"));
}
let mut arr = [0u8; 32];
arr.copy_from_slice(&bytes);
Ok(Ed25519PublicKey(arr))
}
}
impl From<Vec<u8>> for Ed25519PublicKey {
fn from(bytes: Vec<u8>) -> Self {
assert!(
bytes.len() == 32,
"Ed25519PublicKey requires exactly 32 bytes, got {}",
bytes.len()
);
let mut arr = [0u8; 32];
arr.copy_from_slice(&bytes);
Ed25519PublicKey(arr)
}
}
impl Ed25519PublicKey {
pub fn try_from_bytes(bytes: &[u8]) -> crate::error::AptosResult<Self> {
if bytes.len() != 32 {
return Err(crate::error::AptosError::InvalidPublicKey(format!(
"Ed25519PublicKey requires exactly 32 bytes, got {}",
bytes.len()
)));
}
let mut arr = [0u8; 32];
arr.copy_from_slice(bytes);
Ok(Ed25519PublicKey(arr))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Ed25519Signature(pub [u8; 64]);
impl Serialize for Ed25519Signature {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serde_bytes::Bytes::new(&self.0).serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Ed25519Signature {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let bytes: Vec<u8> = serde_bytes::deserialize(deserializer)?;
if bytes.len() != 64 {
return Err(serde::de::Error::invalid_length(bytes.len(), &"64 bytes"));
}
let mut arr = [0u8; 64];
arr.copy_from_slice(&bytes);
Ok(Ed25519Signature(arr))
}
}
impl From<Vec<u8>> for Ed25519Signature {
fn from(bytes: Vec<u8>) -> Self {
assert!(
bytes.len() == 64,
"Ed25519Signature requires exactly 64 bytes, got {}",
bytes.len()
);
let mut arr = [0u8; 64];
arr.copy_from_slice(&bytes);
Ed25519Signature(arr)
}
}
impl Ed25519Signature {
pub fn try_from_bytes(bytes: &[u8]) -> crate::error::AptosResult<Self> {
if bytes.len() != 64 {
return Err(crate::error::AptosError::InvalidSignature(format!(
"Ed25519Signature requires exactly 64 bytes, got {}",
bytes.len()
)));
}
let mut arr = [0u8; 64];
arr.copy_from_slice(bytes);
Ok(Ed25519Signature(arr))
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum TransactionAuthenticator {
Ed25519 {
public_key: Ed25519PublicKey,
signature: Ed25519Signature,
},
MultiEd25519 {
public_key: Vec<u8>,
signature: Vec<u8>,
},
MultiAgent {
sender: AccountAuthenticator,
secondary_signer_addresses: Vec<AccountAddress>,
secondary_signers: Vec<AccountAuthenticator>,
},
FeePayer {
sender: AccountAuthenticator,
secondary_signer_addresses: Vec<AccountAddress>,
secondary_signers: Vec<AccountAuthenticator>,
fee_payer_address: AccountAddress,
fee_payer_signer: AccountAuthenticator,
},
SingleSender {
sender: AccountAuthenticator,
},
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum AccountAuthenticator {
Ed25519 {
public_key: Ed25519PublicKey,
signature: Ed25519Signature,
},
MultiEd25519 {
public_key: Vec<u8>,
signature: Vec<u8>,
},
SingleKey {
public_key: Vec<u8>,
signature: Vec<u8>,
},
MultiKey {
public_key: Vec<u8>,
signature: Vec<u8>,
},
NoAccountAuthenticator,
#[cfg(feature = "keyless")]
Keyless {
public_key: Vec<u8>,
signature: Vec<u8>,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Ed25519Authenticator {
pub public_key: Vec<u8>,
pub signature: Vec<u8>,
}
impl Ed25519Authenticator {
pub fn new(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
Self {
public_key,
signature,
}
}
}
impl From<Ed25519Authenticator> for TransactionAuthenticator {
fn from(auth: Ed25519Authenticator) -> Self {
TransactionAuthenticator::Ed25519 {
public_key: auth.public_key.into(),
signature: auth.signature.into(),
}
}
}
impl From<Ed25519Authenticator> for AccountAuthenticator {
fn from(auth: Ed25519Authenticator) -> Self {
AccountAuthenticator::Ed25519 {
public_key: auth.public_key.into(),
signature: auth.signature.into(),
}
}
}
impl TransactionAuthenticator {
pub fn ed25519(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
Self::Ed25519 {
public_key: public_key.into(),
signature: signature.into(),
}
}
pub fn multi_ed25519(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
Self::MultiEd25519 {
public_key,
signature,
}
}
pub fn multi_agent(
sender: AccountAuthenticator,
secondary_signer_addresses: Vec<AccountAddress>,
secondary_signers: Vec<AccountAuthenticator>,
) -> Self {
Self::MultiAgent {
sender,
secondary_signer_addresses,
secondary_signers,
}
}
pub fn fee_payer(
sender: AccountAuthenticator,
secondary_signer_addresses: Vec<AccountAddress>,
secondary_signers: Vec<AccountAuthenticator>,
fee_payer_address: AccountAddress,
fee_payer_signer: AccountAuthenticator,
) -> Self {
Self::FeePayer {
sender,
secondary_signer_addresses,
secondary_signers,
fee_payer_address,
fee_payer_signer,
}
}
pub fn single_sender(sender: AccountAuthenticator) -> Self {
Self::SingleSender { sender }
}
}
impl AccountAuthenticator {
pub fn ed25519(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
Self::Ed25519 {
public_key: public_key.into(),
signature: signature.into(),
}
}
pub fn single_key(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
Self::SingleKey {
public_key,
signature,
}
}
pub fn multi_key(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
Self::MultiKey {
public_key,
signature,
}
}
pub fn no_account_authenticator() -> Self {
Self::NoAccountAuthenticator
}
#[cfg(feature = "keyless")]
pub fn keyless(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
Self::Keyless {
public_key,
signature,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ed25519_authenticator() {
let mut pk = [0u8; 32];
pk[0..3].copy_from_slice(&[1, 2, 3]);
let mut sig = [0u8; 64];
sig[0..3].copy_from_slice(&[4, 5, 6]);
let auth = Ed25519Authenticator::new(pk.to_vec(), sig.to_vec());
let txn_auth: TransactionAuthenticator = auth.into();
match txn_auth {
TransactionAuthenticator::Ed25519 {
public_key,
signature,
} => {
assert_eq!(public_key.0[0..3], [1, 2, 3]);
assert_eq!(signature.0[0..3], [4, 5, 6]);
}
_ => panic!("wrong authenticator type"),
}
}
#[test]
fn test_multi_agent_authenticator() {
let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
let auth = TransactionAuthenticator::multi_agent(sender, vec![], vec![]);
match auth {
TransactionAuthenticator::MultiAgent { .. } => {}
_ => panic!("wrong authenticator type"),
}
}
#[test]
fn test_ed25519_bcs_format() {
let auth = TransactionAuthenticator::Ed25519 {
public_key: Ed25519PublicKey([0xab; 32]),
signature: Ed25519Signature([0xcd; 64]),
};
let bcs = aptos_bcs::to_bytes(&auth).unwrap();
assert_eq!(bcs[0], 0, "Ed25519 variant index should be 0");
assert_eq!(bcs[1], 32, "Pubkey length prefix should be 32");
assert_eq!(bcs[2], 0xab, "First pubkey byte should be 0xab");
assert_eq!(bcs[34], 64, "Signature length prefix should be 64");
assert_eq!(bcs[35], 0xcd, "First signature byte should be 0xcd");
assert_eq!(bcs.len(), 99, "BCS length should be 99");
}
#[test]
fn test_ed25519_authenticator_into_account_authenticator() {
let auth = Ed25519Authenticator::new(vec![0xaa; 32], vec![0xbb; 64]);
let account_auth: AccountAuthenticator = auth.into();
match account_auth {
AccountAuthenticator::Ed25519 {
public_key,
signature,
} => {
assert_eq!(public_key.0[0], 0xaa);
assert_eq!(signature.0[0], 0xbb);
}
_ => panic!("Expected Ed25519 variant"),
}
}
#[test]
fn test_transaction_authenticator_ed25519() {
let auth = TransactionAuthenticator::ed25519(vec![0x11; 32], vec![0x22; 64]);
match auth {
TransactionAuthenticator::Ed25519 {
public_key,
signature,
} => {
assert_eq!(public_key.0[0], 0x11);
assert_eq!(signature.0[0], 0x22);
}
_ => panic!("Expected Ed25519 variant"),
}
}
#[test]
fn test_transaction_authenticator_multi_ed25519() {
let auth = TransactionAuthenticator::multi_ed25519(vec![0x33; 64], vec![0x44; 128]);
match auth {
TransactionAuthenticator::MultiEd25519 {
public_key,
signature,
} => {
assert_eq!(public_key.len(), 64);
assert_eq!(signature.len(), 128);
}
_ => panic!("Expected MultiEd25519 variant"),
}
}
#[test]
fn test_fee_payer_authenticator() {
let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
let fee_payer = AccountAuthenticator::ed25519(vec![1; 32], vec![1; 64]);
let fee_payer_address = AccountAddress::from_hex("0x123").unwrap();
let auth = TransactionAuthenticator::fee_payer(
sender,
vec![],
vec![],
fee_payer_address,
fee_payer,
);
match auth {
TransactionAuthenticator::FeePayer {
fee_payer_address: addr,
..
} => {
assert_eq!(addr, fee_payer_address);
}
_ => panic!("Expected FeePayer variant"),
}
}
#[test]
fn test_single_sender_authenticator() {
let sender = AccountAuthenticator::ed25519(vec![0x55; 32], vec![0x66; 64]);
let auth = TransactionAuthenticator::single_sender(sender);
match auth {
TransactionAuthenticator::SingleSender { sender } => match sender {
AccountAuthenticator::Ed25519 { public_key, .. } => {
assert_eq!(public_key.0[0], 0x55);
}
_ => panic!("Expected Ed25519 sender"),
},
_ => panic!("Expected SingleSender variant"),
}
}
#[test]
fn test_account_authenticator_multi_key() {
let auth = AccountAuthenticator::multi_key(vec![0x77; 100], vec![0x88; 200]);
match auth {
AccountAuthenticator::MultiKey {
public_key,
signature,
} => {
assert_eq!(public_key.len(), 100);
assert_eq!(signature.len(), 200);
}
_ => panic!("Expected MultiKey variant"),
}
}
#[test]
fn test_ed25519_public_key_from_vec() {
let pk: Ed25519PublicKey = vec![0x12; 32].into();
assert_eq!(pk.0[0], 0x12);
assert_eq!(pk.0.len(), 32);
}
#[test]
fn test_ed25519_signature_from_vec() {
let sig: Ed25519Signature = vec![0x34; 64].into();
assert_eq!(sig.0[0], 0x34);
assert_eq!(sig.0.len(), 64);
}
#[test]
fn test_ed25519_public_key_bcs_roundtrip() {
let pk = Ed25519PublicKey([0xef; 32]);
let serialized = aptos_bcs::to_bytes(&pk).unwrap();
assert_eq!(serialized.len(), 33);
assert_eq!(serialized[0], 32); let deserialized: Ed25519PublicKey = aptos_bcs::from_bytes(&serialized).unwrap();
assert_eq!(pk, deserialized);
}
#[test]
fn test_ed25519_signature_bcs_roundtrip() {
let sig = Ed25519Signature([0x99; 64]);
let serialized = aptos_bcs::to_bytes(&sig).unwrap();
let deserialized: Ed25519Signature = aptos_bcs::from_bytes(&serialized).unwrap();
assert_eq!(sig, deserialized);
}
#[test]
fn test_multi_agent_with_secondary_signers() {
let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
let secondary_signer1 = AccountAuthenticator::ed25519(vec![1; 32], vec![1; 64]);
let secondary_signer2 = AccountAuthenticator::ed25519(vec![2; 32], vec![2; 64]);
let addr1 = AccountAddress::from_hex("0x111").unwrap();
let addr2 = AccountAddress::from_hex("0x222").unwrap();
let auth = TransactionAuthenticator::multi_agent(
sender,
vec![addr1, addr2],
vec![secondary_signer1, secondary_signer2],
);
match auth {
TransactionAuthenticator::MultiAgent {
secondary_signer_addresses,
secondary_signers,
..
} => {
assert_eq!(secondary_signer_addresses.len(), 2);
assert_eq!(secondary_signers.len(), 2);
}
_ => panic!("Expected MultiAgent variant"),
}
}
#[test]
fn test_transaction_authenticator_bcs_roundtrip() {
let auth = TransactionAuthenticator::Ed25519 {
public_key: Ed25519PublicKey([0x11; 32]),
signature: Ed25519Signature([0x22; 64]),
};
let serialized = aptos_bcs::to_bytes(&auth).unwrap();
let deserialized: TransactionAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
assert_eq!(auth, deserialized);
}
#[test]
fn test_account_authenticator_bcs_roundtrip() {
let auth = AccountAuthenticator::Ed25519 {
public_key: Ed25519PublicKey([0x33; 32]),
signature: Ed25519Signature([0x44; 64]),
};
let serialized = aptos_bcs::to_bytes(&auth).unwrap();
let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
assert_eq!(auth, deserialized);
}
#[test]
fn test_account_authenticator_single_key() {
let auth = AccountAuthenticator::single_key(vec![0x55; 33], vec![0x66; 65]);
match auth {
AccountAuthenticator::SingleKey {
public_key,
signature,
} => {
assert_eq!(public_key.len(), 33);
assert_eq!(signature.len(), 65);
}
_ => panic!("Expected SingleKey variant"),
}
}
#[test]
fn test_account_authenticator_single_key_bcs_roundtrip() {
let auth = AccountAuthenticator::SingleKey {
public_key: vec![0x77; 33],
signature: vec![0x88; 65],
};
let serialized = aptos_bcs::to_bytes(&auth).unwrap();
assert_eq!(serialized[0], 2, "SingleKey variant index should be 2");
let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
assert_eq!(auth, deserialized);
}
#[test]
fn test_no_account_authenticator() {
let auth = AccountAuthenticator::no_account_authenticator();
match auth {
AccountAuthenticator::NoAccountAuthenticator => {}
_ => panic!("Expected NoAccountAuthenticator variant"),
}
}
#[test]
fn test_no_account_authenticator_bcs_roundtrip() {
let auth = AccountAuthenticator::NoAccountAuthenticator;
let serialized = aptos_bcs::to_bytes(&auth).unwrap();
assert_eq!(
serialized[0], 4,
"NoAccountAuthenticator variant index should be 4"
);
assert_eq!(
serialized.len(),
1,
"NoAccountAuthenticator should be 1 byte"
);
let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
assert_eq!(auth, deserialized);
}
#[test]
fn test_single_sender_with_single_key() {
let sender = AccountAuthenticator::single_key(vec![0x99; 33], vec![0xaa; 65]);
let auth = TransactionAuthenticator::single_sender(sender);
match auth {
TransactionAuthenticator::SingleSender { sender } => match sender {
AccountAuthenticator::SingleKey { public_key, .. } => {
assert_eq!(public_key.len(), 33);
}
_ => panic!("Expected SingleKey sender"),
},
_ => panic!("Expected SingleSender variant"),
}
}
#[test]
fn test_account_authenticator_variant_indices() {
let ed25519 = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
let multi_ed25519 = AccountAuthenticator::MultiEd25519 {
public_key: vec![0; 64],
signature: vec![0; 128],
};
let single_key = AccountAuthenticator::single_key(vec![0; 33], vec![0; 65]);
let multi_key = AccountAuthenticator::multi_key(vec![0; 100], vec![0; 200]);
let no_account = AccountAuthenticator::no_account_authenticator();
assert_eq!(aptos_bcs::to_bytes(&ed25519).unwrap()[0], 0, "Ed25519 = 0");
assert_eq!(
aptos_bcs::to_bytes(&multi_ed25519).unwrap()[0],
1,
"MultiEd25519 = 1"
);
assert_eq!(
aptos_bcs::to_bytes(&single_key).unwrap()[0],
2,
"SingleKey = 2"
);
assert_eq!(
aptos_bcs::to_bytes(&multi_key).unwrap()[0],
3,
"MultiKey = 3"
);
assert_eq!(
aptos_bcs::to_bytes(&no_account).unwrap()[0],
4,
"NoAccountAuthenticator = 4"
);
}
#[test]
fn test_ed25519_public_key_try_from_bytes_valid() {
let bytes = vec![0x12; 32];
let pk = Ed25519PublicKey::try_from_bytes(&bytes).unwrap();
assert_eq!(pk.0[0], 0x12);
}
#[test]
fn test_ed25519_public_key_try_from_bytes_invalid_length() {
let bytes = vec![0x12; 16]; let result = Ed25519PublicKey::try_from_bytes(&bytes);
assert!(result.is_err());
}
#[test]
fn test_ed25519_signature_try_from_bytes_valid() {
let bytes = vec![0x34; 64];
let sig = Ed25519Signature::try_from_bytes(&bytes).unwrap();
assert_eq!(sig.0[0], 0x34);
}
#[test]
fn test_ed25519_signature_try_from_bytes_invalid_length() {
let bytes = vec![0x34; 32]; let result = Ed25519Signature::try_from_bytes(&bytes);
assert!(result.is_err());
}
#[test]
fn test_transaction_authenticator_variant_indices() {
let ed25519 = TransactionAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
let multi_ed25519 = TransactionAuthenticator::multi_ed25519(vec![0; 64], vec![0; 128]);
let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
let multi_agent = TransactionAuthenticator::multi_agent(sender.clone(), vec![], vec![]);
let fee_payer = TransactionAuthenticator::fee_payer(
sender.clone(),
vec![],
vec![],
AccountAddress::ONE,
sender.clone(),
);
let single_sender = TransactionAuthenticator::single_sender(sender);
assert_eq!(aptos_bcs::to_bytes(&ed25519).unwrap()[0], 0, "Ed25519 = 0");
assert_eq!(
aptos_bcs::to_bytes(&multi_ed25519).unwrap()[0],
1,
"MultiEd25519 = 1"
);
assert_eq!(
aptos_bcs::to_bytes(&multi_agent).unwrap()[0],
2,
"MultiAgent = 2"
);
assert_eq!(
aptos_bcs::to_bytes(&fee_payer).unwrap()[0],
3,
"FeePayer = 3"
);
assert_eq!(
aptos_bcs::to_bytes(&single_sender).unwrap()[0],
4,
"SingleSender = 4"
);
}
#[test]
fn test_multi_key_authenticator_bcs_roundtrip() {
let auth = AccountAuthenticator::multi_key(vec![0xaa; 100], vec![0xbb; 200]);
let serialized = aptos_bcs::to_bytes(&auth).unwrap();
assert_eq!(serialized[0], 3, "MultiKey variant index should be 3");
let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
assert_eq!(auth, deserialized);
}
#[test]
fn test_multi_ed25519_authenticator_bcs_roundtrip() {
let auth = AccountAuthenticator::MultiEd25519 {
public_key: vec![0xcc; 64],
signature: vec![0xdd; 128],
};
let serialized = aptos_bcs::to_bytes(&auth).unwrap();
assert_eq!(serialized[0], 1, "MultiEd25519 variant index should be 1");
let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
assert_eq!(auth, deserialized);
}
#[test]
fn test_ed25519_public_key_deserialize_invalid_length() {
let mut bytes = vec![16u8]; bytes.extend_from_slice(&[0xab; 16]); let result: Result<Ed25519PublicKey, _> = aptos_bcs::from_bytes(&bytes);
assert!(result.is_err());
}
#[test]
fn test_ed25519_signature_deserialize_invalid_length() {
let mut bytes = vec![32u8]; bytes.extend_from_slice(&[0xab; 32]); let result: Result<Ed25519Signature, _> = aptos_bcs::from_bytes(&bytes);
assert!(result.is_err());
}
}