Skip to main content

aptos_sdk/transaction/
authenticator.rs

1//! Transaction authenticators.
2
3use crate::types::AccountAddress;
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5
6/// Ed25519 public key (32 bytes).
7/// Serializes WITH a length prefix as required by Aptos BCS format.
8#[derive(Clone, Debug, PartialEq, Eq)]
9pub struct Ed25519PublicKey(pub [u8; 32]);
10
11impl Serialize for Ed25519PublicKey {
12    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
13        // Aptos BCS format requires a length prefix for public keys
14        // Use serde_bytes to serialize with ULEB128 length prefix
15        serde_bytes::Bytes::new(&self.0).serialize(serializer)
16    }
17}
18
19impl<'de> Deserialize<'de> for Ed25519PublicKey {
20    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
21        // Deserialize with length prefix
22        let bytes: Vec<u8> = serde_bytes::deserialize(deserializer)?;
23        if bytes.len() != 32 {
24            return Err(serde::de::Error::invalid_length(bytes.len(), &"32 bytes"));
25        }
26        let mut arr = [0u8; 32];
27        arr.copy_from_slice(&bytes);
28        Ok(Ed25519PublicKey(arr))
29    }
30}
31
32impl From<Vec<u8>> for Ed25519PublicKey {
33    /// Converts a `Vec<u8>` to `Ed25519PublicKey`.
34    ///
35    /// # Panics
36    ///
37    /// Panics if the input is not exactly 32 bytes. Use `Ed25519PublicKey::try_from_bytes`
38    /// for fallible conversion.
39    fn from(bytes: Vec<u8>) -> Self {
40        assert!(
41            bytes.len() == 32,
42            "Ed25519PublicKey requires exactly 32 bytes, got {}",
43            bytes.len()
44        );
45        let mut arr = [0u8; 32];
46        arr.copy_from_slice(&bytes);
47        Ed25519PublicKey(arr)
48    }
49}
50
51impl Ed25519PublicKey {
52    /// Attempts to create an `Ed25519PublicKey` from a byte slice.
53    ///
54    /// Returns an error if the input is not exactly 32 bytes.
55    ///
56    /// # Errors
57    ///
58    /// Returns an error if the input slice is not exactly 32 bytes.
59    pub fn try_from_bytes(bytes: &[u8]) -> crate::error::AptosResult<Self> {
60        if bytes.len() != 32 {
61            return Err(crate::error::AptosError::InvalidPublicKey(format!(
62                "Ed25519PublicKey requires exactly 32 bytes, got {}",
63                bytes.len()
64            )));
65        }
66        let mut arr = [0u8; 32];
67        arr.copy_from_slice(bytes);
68        Ok(Ed25519PublicKey(arr))
69    }
70}
71
72/// Ed25519 signature (64 bytes).
73/// Serializes WITH a length prefix as required by Aptos BCS format.
74#[derive(Clone, Debug, PartialEq, Eq)]
75pub struct Ed25519Signature(pub [u8; 64]);
76
77impl Serialize for Ed25519Signature {
78    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
79        // Aptos BCS format requires a length prefix for signatures
80        // Use serde_bytes to serialize with ULEB128 length prefix
81        serde_bytes::Bytes::new(&self.0).serialize(serializer)
82    }
83}
84
85impl<'de> Deserialize<'de> for Ed25519Signature {
86    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
87        // Deserialize with length prefix
88        let bytes: Vec<u8> = serde_bytes::deserialize(deserializer)?;
89        if bytes.len() != 64 {
90            return Err(serde::de::Error::invalid_length(bytes.len(), &"64 bytes"));
91        }
92        let mut arr = [0u8; 64];
93        arr.copy_from_slice(&bytes);
94        Ok(Ed25519Signature(arr))
95    }
96}
97
98impl From<Vec<u8>> for Ed25519Signature {
99    /// Converts a `Vec<u8>` to `Ed25519Signature`.
100    ///
101    /// # Panics
102    ///
103    /// Panics if the input is not exactly 64 bytes. Use `Ed25519Signature::try_from_bytes`
104    /// for fallible conversion.
105    fn from(bytes: Vec<u8>) -> Self {
106        assert!(
107            bytes.len() == 64,
108            "Ed25519Signature requires exactly 64 bytes, got {}",
109            bytes.len()
110        );
111        let mut arr = [0u8; 64];
112        arr.copy_from_slice(&bytes);
113        Ed25519Signature(arr)
114    }
115}
116
117impl Ed25519Signature {
118    /// Attempts to create an `Ed25519Signature` from a byte slice.
119    ///
120    /// # Errors
121    ///
122    /// Returns an error if the input is not exactly 64 bytes.
123    pub fn try_from_bytes(bytes: &[u8]) -> crate::error::AptosResult<Self> {
124        if bytes.len() != 64 {
125            return Err(crate::error::AptosError::InvalidSignature(format!(
126                "Ed25519Signature requires exactly 64 bytes, got {}",
127                bytes.len()
128            )));
129        }
130        let mut arr = [0u8; 64];
131        arr.copy_from_slice(bytes);
132        Ok(Ed25519Signature(arr))
133    }
134}
135
136/// An authenticator for a transaction.
137///
138/// This contains the signature(s) and public key(s) that prove
139/// the transaction was authorized by the sender.
140///
141/// Note: Variant indices must match Aptos core for BCS compatibility:
142/// - 0: Ed25519
143/// - 1: `MultiEd25519`
144/// - 2: `MultiAgent`
145/// - 3: `FeePayer`
146/// - 4: `SingleSender` (for unified key support)
147#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
148pub enum TransactionAuthenticator {
149    /// Ed25519 single-key authentication (variant 0).
150    Ed25519 {
151        /// The Ed25519 public key (32 bytes).
152        public_key: Ed25519PublicKey,
153        /// The Ed25519 signature (64 bytes).
154        signature: Ed25519Signature,
155    },
156    /// Multi-Ed25519 authentication (variant 1).
157    MultiEd25519 {
158        /// The multi-Ed25519 public key.
159        public_key: Vec<u8>,
160        /// The multi-Ed25519 signature.
161        signature: Vec<u8>,
162    },
163    /// Multi-agent transaction authentication (variant 2).
164    MultiAgent {
165        /// The sender's authenticator.
166        sender: AccountAuthenticator,
167        /// Secondary signer addresses.
168        secondary_signer_addresses: Vec<AccountAddress>,
169        /// Secondary signers' authenticators.
170        secondary_signers: Vec<AccountAuthenticator>,
171    },
172    /// Fee payer transaction authentication (variant 3).
173    FeePayer {
174        /// The sender's authenticator.
175        sender: AccountAuthenticator,
176        /// Secondary signer addresses.
177        secondary_signer_addresses: Vec<AccountAddress>,
178        /// Secondary signers' authenticators.
179        secondary_signers: Vec<AccountAuthenticator>,
180        /// The fee payer's address.
181        fee_payer_address: AccountAddress,
182        /// The fee payer's authenticator.
183        fee_payer_signer: AccountAuthenticator,
184    },
185    /// Single sender authentication with account authenticator (variant 4).
186    /// Used for newer single-key and multi-key accounts.
187    SingleSender {
188        /// The account authenticator.
189        sender: AccountAuthenticator,
190    },
191}
192
193/// An authenticator for a single account (not the full transaction).
194#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
195pub enum AccountAuthenticator {
196    /// Ed25519 authentication (variant 0).
197    Ed25519 {
198        /// The public key (32 bytes).
199        public_key: Ed25519PublicKey,
200        /// The signature (64 bytes).
201        signature: Ed25519Signature,
202    },
203    /// Multi-Ed25519 authentication (variant 1).
204    MultiEd25519 {
205        /// The public key.
206        public_key: Vec<u8>,
207        /// The signature.
208        signature: Vec<u8>,
209    },
210    /// Single-key authentication (ed25519, secp256k1 and secp256r1) (variant 2).
211    SingleKey {
212        /// The public key (BCS-serialized `AnyPublicKey`).
213        public_key: Vec<u8>,
214        /// The signature (BCS-serialized `AnySignature`).
215        signature: Vec<u8>,
216    },
217    /// Multi-key authentication (mixed signature types) (variant 3).
218    MultiKey {
219        /// The public key.
220        public_key: Vec<u8>,
221        /// The signature.
222        signature: Vec<u8>,
223    },
224    /// No account authenticator used for simulation only (variant 4).
225    NoAccountAuthenticator,
226    /// Keyless (OIDC-based) authentication (variant 5).
227    /// Uses ephemeral keys and ZK proofs for authentication.
228    #[cfg(feature = "keyless")]
229    Keyless {
230        /// The ephemeral public key bytes.
231        public_key: Vec<u8>,
232        /// The BCS-serialized `KeylessSignature` containing ephemeral signature and ZK proof.
233        signature: Vec<u8>,
234    },
235}
236
237/// Ed25519 authenticator helper.
238#[derive(Clone, Debug, PartialEq, Eq)]
239pub struct Ed25519Authenticator {
240    /// The public key.
241    pub public_key: Vec<u8>,
242    /// The signature.
243    pub signature: Vec<u8>,
244}
245
246impl Ed25519Authenticator {
247    /// Creates a new Ed25519 authenticator.
248    pub fn new(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
249        Self {
250            public_key,
251            signature,
252        }
253    }
254}
255
256impl From<Ed25519Authenticator> for TransactionAuthenticator {
257    fn from(auth: Ed25519Authenticator) -> Self {
258        TransactionAuthenticator::Ed25519 {
259            public_key: auth.public_key.into(),
260            signature: auth.signature.into(),
261        }
262    }
263}
264
265impl From<Ed25519Authenticator> for AccountAuthenticator {
266    fn from(auth: Ed25519Authenticator) -> Self {
267        AccountAuthenticator::Ed25519 {
268            public_key: auth.public_key.into(),
269            signature: auth.signature.into(),
270        }
271    }
272}
273
274impl TransactionAuthenticator {
275    /// Creates an Ed25519 authenticator.
276    pub fn ed25519(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
277        Self::Ed25519 {
278            public_key: public_key.into(),
279            signature: signature.into(),
280        }
281    }
282
283    /// Creates a multi-Ed25519 authenticator.
284    pub fn multi_ed25519(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
285        Self::MultiEd25519 {
286            public_key,
287            signature,
288        }
289    }
290
291    /// Creates a multi-agent authenticator.
292    pub fn multi_agent(
293        sender: AccountAuthenticator,
294        secondary_signer_addresses: Vec<AccountAddress>,
295        secondary_signers: Vec<AccountAuthenticator>,
296    ) -> Self {
297        Self::MultiAgent {
298            sender,
299            secondary_signer_addresses,
300            secondary_signers,
301        }
302    }
303
304    /// Creates a fee payer authenticator.
305    pub fn fee_payer(
306        sender: AccountAuthenticator,
307        secondary_signer_addresses: Vec<AccountAddress>,
308        secondary_signers: Vec<AccountAuthenticator>,
309        fee_payer_address: AccountAddress,
310        fee_payer_signer: AccountAuthenticator,
311    ) -> Self {
312        Self::FeePayer {
313            sender,
314            secondary_signer_addresses,
315            secondary_signers,
316            fee_payer_address,
317            fee_payer_signer,
318        }
319    }
320
321    /// Creates a single sender authenticator.
322    /// This is used for accounts with the unified key model (including multi-key accounts).
323    pub fn single_sender(sender: AccountAuthenticator) -> Self {
324        Self::SingleSender { sender }
325    }
326}
327
328impl AccountAuthenticator {
329    /// Creates an Ed25519 account authenticator.
330    pub fn ed25519(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
331        Self::Ed25519 {
332            public_key: public_key.into(),
333            signature: signature.into(),
334        }
335    }
336    /// Creates a single-key account authenticator.
337    pub fn single_key(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
338        Self::SingleKey {
339            public_key,
340            signature,
341        }
342    }
343
344    /// Creates a multi-key account authenticator.
345    pub fn multi_key(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
346        Self::MultiKey {
347            public_key,
348            signature,
349        }
350    }
351
352    /// Creates a no account authenticator.
353    pub fn no_account_authenticator() -> Self {
354        Self::NoAccountAuthenticator
355    }
356
357    /// Creates a keyless account authenticator.
358    ///
359    /// # Arguments
360    ///
361    /// * `public_key` - The ephemeral public key bytes
362    /// * `signature` - The BCS-serialized `KeylessSignature`
363    #[cfg(feature = "keyless")]
364    pub fn keyless(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
365        Self::Keyless {
366            public_key,
367            signature,
368        }
369    }
370}
371
372#[cfg(test)]
373mod tests {
374    use super::*;
375
376    #[test]
377    fn test_ed25519_authenticator() {
378        let mut pk = [0u8; 32];
379        pk[0..3].copy_from_slice(&[1, 2, 3]);
380        let mut sig = [0u8; 64];
381        sig[0..3].copy_from_slice(&[4, 5, 6]);
382
383        let auth = Ed25519Authenticator::new(pk.to_vec(), sig.to_vec());
384        let txn_auth: TransactionAuthenticator = auth.into();
385
386        match txn_auth {
387            TransactionAuthenticator::Ed25519 {
388                public_key,
389                signature,
390            } => {
391                assert_eq!(public_key.0[0..3], [1, 2, 3]);
392                assert_eq!(signature.0[0..3], [4, 5, 6]);
393            }
394            _ => panic!("wrong authenticator type"),
395        }
396    }
397
398    #[test]
399    fn test_multi_agent_authenticator() {
400        let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
401        let auth = TransactionAuthenticator::multi_agent(sender, vec![], vec![]);
402
403        match auth {
404            TransactionAuthenticator::MultiAgent { .. } => {}
405            _ => panic!("wrong authenticator type"),
406        }
407    }
408
409    #[test]
410    fn test_ed25519_bcs_format() {
411        // Test that Ed25519 serializes WITH length prefixes (Aptos BCS format)
412        let auth = TransactionAuthenticator::Ed25519 {
413            public_key: Ed25519PublicKey([0xab; 32]),
414            signature: Ed25519Signature([0xcd; 64]),
415        };
416        let bcs = aptos_bcs::to_bytes(&auth).unwrap();
417
418        // Ed25519 variant should be index 0
419        assert_eq!(bcs[0], 0, "Ed25519 variant index should be 0");
420        // Next byte is length prefix for pubkey (32 = 0x20)
421        assert_eq!(bcs[1], 32, "Pubkey length prefix should be 32");
422        // Next 32 bytes should be the pubkey
423        assert_eq!(bcs[2], 0xab, "First pubkey byte should be 0xab");
424        // After pubkey (1 + 1 + 32 = 34), length prefix for signature (64 = 0x40)
425        assert_eq!(bcs[34], 64, "Signature length prefix should be 64");
426        // Signature starts at offset 35
427        assert_eq!(bcs[35], 0xcd, "First signature byte should be 0xcd");
428        // Total: 1 (variant) + 1 (pubkey len) + 32 (pubkey) + 1 (sig len) + 64 (sig) = 99
429        assert_eq!(bcs.len(), 99, "BCS length should be 99");
430    }
431
432    #[test]
433    fn test_ed25519_authenticator_into_account_authenticator() {
434        let auth = Ed25519Authenticator::new(vec![0xaa; 32], vec![0xbb; 64]);
435        let account_auth: AccountAuthenticator = auth.into();
436
437        match account_auth {
438            AccountAuthenticator::Ed25519 {
439                public_key,
440                signature,
441            } => {
442                assert_eq!(public_key.0[0], 0xaa);
443                assert_eq!(signature.0[0], 0xbb);
444            }
445            _ => panic!("Expected Ed25519 variant"),
446        }
447    }
448
449    #[test]
450    fn test_transaction_authenticator_ed25519() {
451        let auth = TransactionAuthenticator::ed25519(vec![0x11; 32], vec![0x22; 64]);
452        match auth {
453            TransactionAuthenticator::Ed25519 {
454                public_key,
455                signature,
456            } => {
457                assert_eq!(public_key.0[0], 0x11);
458                assert_eq!(signature.0[0], 0x22);
459            }
460            _ => panic!("Expected Ed25519 variant"),
461        }
462    }
463
464    #[test]
465    fn test_transaction_authenticator_multi_ed25519() {
466        let auth = TransactionAuthenticator::multi_ed25519(vec![0x33; 64], vec![0x44; 128]);
467        match auth {
468            TransactionAuthenticator::MultiEd25519 {
469                public_key,
470                signature,
471            } => {
472                assert_eq!(public_key.len(), 64);
473                assert_eq!(signature.len(), 128);
474            }
475            _ => panic!("Expected MultiEd25519 variant"),
476        }
477    }
478
479    #[test]
480    fn test_fee_payer_authenticator() {
481        let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
482        let fee_payer = AccountAuthenticator::ed25519(vec![1; 32], vec![1; 64]);
483        let fee_payer_address = AccountAddress::from_hex("0x123").unwrap();
484
485        let auth = TransactionAuthenticator::fee_payer(
486            sender,
487            vec![],
488            vec![],
489            fee_payer_address,
490            fee_payer,
491        );
492
493        match auth {
494            TransactionAuthenticator::FeePayer {
495                fee_payer_address: addr,
496                ..
497            } => {
498                assert_eq!(addr, fee_payer_address);
499            }
500            _ => panic!("Expected FeePayer variant"),
501        }
502    }
503
504    #[test]
505    fn test_single_sender_authenticator() {
506        let sender = AccountAuthenticator::ed25519(vec![0x55; 32], vec![0x66; 64]);
507        let auth = TransactionAuthenticator::single_sender(sender);
508
509        match auth {
510            TransactionAuthenticator::SingleSender { sender } => match sender {
511                AccountAuthenticator::Ed25519 { public_key, .. } => {
512                    assert_eq!(public_key.0[0], 0x55);
513                }
514                _ => panic!("Expected Ed25519 sender"),
515            },
516            _ => panic!("Expected SingleSender variant"),
517        }
518    }
519
520    #[test]
521    fn test_account_authenticator_multi_key() {
522        let auth = AccountAuthenticator::multi_key(vec![0x77; 100], vec![0x88; 200]);
523        match auth {
524            AccountAuthenticator::MultiKey {
525                public_key,
526                signature,
527            } => {
528                assert_eq!(public_key.len(), 100);
529                assert_eq!(signature.len(), 200);
530            }
531            _ => panic!("Expected MultiKey variant"),
532        }
533    }
534
535    #[test]
536    fn test_ed25519_public_key_from_vec() {
537        let pk: Ed25519PublicKey = vec![0x12; 32].into();
538        assert_eq!(pk.0[0], 0x12);
539        assert_eq!(pk.0.len(), 32);
540    }
541
542    #[test]
543    fn test_ed25519_signature_from_vec() {
544        let sig: Ed25519Signature = vec![0x34; 64].into();
545        assert_eq!(sig.0[0], 0x34);
546        assert_eq!(sig.0.len(), 64);
547    }
548
549    #[test]
550    fn test_ed25519_public_key_bcs_roundtrip() {
551        let pk = Ed25519PublicKey([0xef; 32]);
552        let serialized = aptos_bcs::to_bytes(&pk).unwrap();
553        // Aptos BCS format: 1 byte length prefix (32) + 32 bytes = 33 bytes
554        assert_eq!(serialized.len(), 33);
555        assert_eq!(serialized[0], 32); // Length prefix
556        let deserialized: Ed25519PublicKey = aptos_bcs::from_bytes(&serialized).unwrap();
557        assert_eq!(pk, deserialized);
558    }
559
560    #[test]
561    fn test_ed25519_signature_bcs_roundtrip() {
562        let sig = Ed25519Signature([0x99; 64]);
563        let serialized = aptos_bcs::to_bytes(&sig).unwrap();
564        let deserialized: Ed25519Signature = aptos_bcs::from_bytes(&serialized).unwrap();
565        assert_eq!(sig, deserialized);
566    }
567
568    #[test]
569    fn test_multi_agent_with_secondary_signers() {
570        let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
571        let secondary_signer1 = AccountAuthenticator::ed25519(vec![1; 32], vec![1; 64]);
572        let secondary_signer2 = AccountAuthenticator::ed25519(vec![2; 32], vec![2; 64]);
573        let addr1 = AccountAddress::from_hex("0x111").unwrap();
574        let addr2 = AccountAddress::from_hex("0x222").unwrap();
575
576        let auth = TransactionAuthenticator::multi_agent(
577            sender,
578            vec![addr1, addr2],
579            vec![secondary_signer1, secondary_signer2],
580        );
581
582        match auth {
583            TransactionAuthenticator::MultiAgent {
584                secondary_signer_addresses,
585                secondary_signers,
586                ..
587            } => {
588                assert_eq!(secondary_signer_addresses.len(), 2);
589                assert_eq!(secondary_signers.len(), 2);
590            }
591            _ => panic!("Expected MultiAgent variant"),
592        }
593    }
594
595    #[test]
596    fn test_transaction_authenticator_bcs_roundtrip() {
597        let auth = TransactionAuthenticator::Ed25519 {
598            public_key: Ed25519PublicKey([0x11; 32]),
599            signature: Ed25519Signature([0x22; 64]),
600        };
601
602        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
603        let deserialized: TransactionAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
604
605        assert_eq!(auth, deserialized);
606    }
607
608    #[test]
609    fn test_account_authenticator_bcs_roundtrip() {
610        let auth = AccountAuthenticator::Ed25519 {
611            public_key: Ed25519PublicKey([0x33; 32]),
612            signature: Ed25519Signature([0x44; 64]),
613        };
614
615        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
616        let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
617
618        assert_eq!(auth, deserialized);
619    }
620
621    #[test]
622    fn test_account_authenticator_single_key() {
623        let auth = AccountAuthenticator::single_key(vec![0x55; 33], vec![0x66; 65]);
624        match auth {
625            AccountAuthenticator::SingleKey {
626                public_key,
627                signature,
628            } => {
629                assert_eq!(public_key.len(), 33);
630                assert_eq!(signature.len(), 65);
631            }
632            _ => panic!("Expected SingleKey variant"),
633        }
634    }
635
636    #[test]
637    fn test_account_authenticator_single_key_bcs_roundtrip() {
638        let auth = AccountAuthenticator::SingleKey {
639            public_key: vec![0x77; 33],
640            signature: vec![0x88; 65],
641        };
642
643        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
644        // SingleKey should be variant index 2
645        assert_eq!(serialized[0], 2, "SingleKey variant index should be 2");
646        let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
647        assert_eq!(auth, deserialized);
648    }
649
650    #[test]
651    fn test_no_account_authenticator() {
652        let auth = AccountAuthenticator::no_account_authenticator();
653        match auth {
654            AccountAuthenticator::NoAccountAuthenticator => {}
655            _ => panic!("Expected NoAccountAuthenticator variant"),
656        }
657    }
658
659    #[test]
660    fn test_no_account_authenticator_bcs_roundtrip() {
661        let auth = AccountAuthenticator::NoAccountAuthenticator;
662
663        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
664        // NoAccountAuthenticator should be variant index 4
665        assert_eq!(
666            serialized[0], 4,
667            "NoAccountAuthenticator variant index should be 4"
668        );
669        // It should be just the variant index, no payload
670        assert_eq!(
671            serialized.len(),
672            1,
673            "NoAccountAuthenticator should be 1 byte"
674        );
675        let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
676        assert_eq!(auth, deserialized);
677    }
678
679    #[test]
680    fn test_single_sender_with_single_key() {
681        let sender = AccountAuthenticator::single_key(vec![0x99; 33], vec![0xaa; 65]);
682        let auth = TransactionAuthenticator::single_sender(sender);
683
684        match auth {
685            TransactionAuthenticator::SingleSender { sender } => match sender {
686                AccountAuthenticator::SingleKey { public_key, .. } => {
687                    assert_eq!(public_key.len(), 33);
688                }
689                _ => panic!("Expected SingleKey sender"),
690            },
691            _ => panic!("Expected SingleSender variant"),
692        }
693    }
694
695    #[test]
696    fn test_account_authenticator_variant_indices() {
697        // Verify all variant indices match Aptos core
698        let ed25519 = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
699        let multi_ed25519 = AccountAuthenticator::MultiEd25519 {
700            public_key: vec![0; 64],
701            signature: vec![0; 128],
702        };
703        let single_key = AccountAuthenticator::single_key(vec![0; 33], vec![0; 65]);
704        let multi_key = AccountAuthenticator::multi_key(vec![0; 100], vec![0; 200]);
705        let no_account = AccountAuthenticator::no_account_authenticator();
706
707        assert_eq!(aptos_bcs::to_bytes(&ed25519).unwrap()[0], 0, "Ed25519 = 0");
708        assert_eq!(
709            aptos_bcs::to_bytes(&multi_ed25519).unwrap()[0],
710            1,
711            "MultiEd25519 = 1"
712        );
713        assert_eq!(
714            aptos_bcs::to_bytes(&single_key).unwrap()[0],
715            2,
716            "SingleKey = 2"
717        );
718        assert_eq!(
719            aptos_bcs::to_bytes(&multi_key).unwrap()[0],
720            3,
721            "MultiKey = 3"
722        );
723        assert_eq!(
724            aptos_bcs::to_bytes(&no_account).unwrap()[0],
725            4,
726            "NoAccountAuthenticator = 4"
727        );
728    }
729
730    #[test]
731    fn test_ed25519_public_key_try_from_bytes_valid() {
732        let bytes = vec![0x12; 32];
733        let pk = Ed25519PublicKey::try_from_bytes(&bytes).unwrap();
734        assert_eq!(pk.0[0], 0x12);
735    }
736
737    #[test]
738    fn test_ed25519_public_key_try_from_bytes_invalid_length() {
739        let bytes = vec![0x12; 16]; // Wrong length
740        let result = Ed25519PublicKey::try_from_bytes(&bytes);
741        assert!(result.is_err());
742    }
743
744    #[test]
745    fn test_ed25519_signature_try_from_bytes_valid() {
746        let bytes = vec![0x34; 64];
747        let sig = Ed25519Signature::try_from_bytes(&bytes).unwrap();
748        assert_eq!(sig.0[0], 0x34);
749    }
750
751    #[test]
752    fn test_ed25519_signature_try_from_bytes_invalid_length() {
753        let bytes = vec![0x34; 32]; // Wrong length
754        let result = Ed25519Signature::try_from_bytes(&bytes);
755        assert!(result.is_err());
756    }
757
758    #[test]
759    fn test_transaction_authenticator_variant_indices() {
760        // Verify transaction authenticator variant indices
761        let ed25519 = TransactionAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
762        let multi_ed25519 = TransactionAuthenticator::multi_ed25519(vec![0; 64], vec![0; 128]);
763        let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
764        let multi_agent = TransactionAuthenticator::multi_agent(sender.clone(), vec![], vec![]);
765        let fee_payer = TransactionAuthenticator::fee_payer(
766            sender.clone(),
767            vec![],
768            vec![],
769            AccountAddress::ONE,
770            sender.clone(),
771        );
772        let single_sender = TransactionAuthenticator::single_sender(sender);
773
774        assert_eq!(aptos_bcs::to_bytes(&ed25519).unwrap()[0], 0, "Ed25519 = 0");
775        assert_eq!(
776            aptos_bcs::to_bytes(&multi_ed25519).unwrap()[0],
777            1,
778            "MultiEd25519 = 1"
779        );
780        assert_eq!(
781            aptos_bcs::to_bytes(&multi_agent).unwrap()[0],
782            2,
783            "MultiAgent = 2"
784        );
785        assert_eq!(
786            aptos_bcs::to_bytes(&fee_payer).unwrap()[0],
787            3,
788            "FeePayer = 3"
789        );
790        assert_eq!(
791            aptos_bcs::to_bytes(&single_sender).unwrap()[0],
792            4,
793            "SingleSender = 4"
794        );
795    }
796
797    #[test]
798    fn test_multi_key_authenticator_bcs_roundtrip() {
799        let auth = AccountAuthenticator::multi_key(vec![0xaa; 100], vec![0xbb; 200]);
800
801        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
802        // MultiKey should be variant index 3
803        assert_eq!(serialized[0], 3, "MultiKey variant index should be 3");
804        let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
805        assert_eq!(auth, deserialized);
806    }
807
808    #[test]
809    fn test_multi_ed25519_authenticator_bcs_roundtrip() {
810        let auth = AccountAuthenticator::MultiEd25519 {
811            public_key: vec![0xcc; 64],
812            signature: vec![0xdd; 128],
813        };
814
815        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
816        // MultiEd25519 should be variant index 1
817        assert_eq!(serialized[0], 1, "MultiEd25519 variant index should be 1");
818        let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
819        assert_eq!(auth, deserialized);
820    }
821
822    #[test]
823    fn test_ed25519_public_key_deserialize_invalid_length() {
824        // Serialize with wrong length (use 16 bytes instead of 32)
825        let mut bytes = vec![16u8]; // Length prefix
826        bytes.extend_from_slice(&[0xab; 16]); // Only 16 bytes
827        let result: Result<Ed25519PublicKey, _> = aptos_bcs::from_bytes(&bytes);
828        assert!(result.is_err());
829    }
830
831    #[test]
832    fn test_ed25519_signature_deserialize_invalid_length() {
833        // Serialize with wrong length (use 32 bytes instead of 64)
834        let mut bytes = vec![32u8]; // Length prefix
835        bytes.extend_from_slice(&[0xab; 32]); // Only 32 bytes
836        let result: Result<Ed25519Signature, _> = aptos_bcs::from_bytes(&bytes);
837        assert!(result.is_err());
838    }
839}