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    #[cfg_attr(docsrs, doc(cfg(feature = "keyless")))]
230    Keyless {
231        /// The ephemeral public key bytes.
232        public_key: Vec<u8>,
233        /// The BCS-serialized `KeylessSignature` containing ephemeral signature and ZK proof.
234        signature: Vec<u8>,
235    },
236}
237
238/// Ed25519 authenticator helper.
239#[derive(Clone, Debug, PartialEq, Eq)]
240pub struct Ed25519Authenticator {
241    /// The public key.
242    pub public_key: Vec<u8>,
243    /// The signature.
244    pub signature: Vec<u8>,
245}
246
247impl Ed25519Authenticator {
248    /// Creates a new Ed25519 authenticator.
249    pub fn new(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
250        Self {
251            public_key,
252            signature,
253        }
254    }
255}
256
257impl From<Ed25519Authenticator> for TransactionAuthenticator {
258    fn from(auth: Ed25519Authenticator) -> Self {
259        TransactionAuthenticator::Ed25519 {
260            public_key: auth.public_key.into(),
261            signature: auth.signature.into(),
262        }
263    }
264}
265
266impl From<Ed25519Authenticator> for AccountAuthenticator {
267    fn from(auth: Ed25519Authenticator) -> Self {
268        AccountAuthenticator::Ed25519 {
269            public_key: auth.public_key.into(),
270            signature: auth.signature.into(),
271        }
272    }
273}
274
275impl TransactionAuthenticator {
276    /// Creates an Ed25519 authenticator.
277    pub fn ed25519(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
278        Self::Ed25519 {
279            public_key: public_key.into(),
280            signature: signature.into(),
281        }
282    }
283
284    /// Creates a multi-Ed25519 authenticator.
285    pub fn multi_ed25519(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
286        Self::MultiEd25519 {
287            public_key,
288            signature,
289        }
290    }
291
292    /// Creates a multi-agent authenticator.
293    pub fn multi_agent(
294        sender: AccountAuthenticator,
295        secondary_signer_addresses: Vec<AccountAddress>,
296        secondary_signers: Vec<AccountAuthenticator>,
297    ) -> Self {
298        Self::MultiAgent {
299            sender,
300            secondary_signer_addresses,
301            secondary_signers,
302        }
303    }
304
305    /// Creates a fee payer authenticator.
306    pub fn fee_payer(
307        sender: AccountAuthenticator,
308        secondary_signer_addresses: Vec<AccountAddress>,
309        secondary_signers: Vec<AccountAuthenticator>,
310        fee_payer_address: AccountAddress,
311        fee_payer_signer: AccountAuthenticator,
312    ) -> Self {
313        Self::FeePayer {
314            sender,
315            secondary_signer_addresses,
316            secondary_signers,
317            fee_payer_address,
318            fee_payer_signer,
319        }
320    }
321
322    /// Creates a single sender authenticator.
323    /// This is used for accounts with the unified key model (including multi-key accounts).
324    pub fn single_sender(sender: AccountAuthenticator) -> Self {
325        Self::SingleSender { sender }
326    }
327}
328
329impl AccountAuthenticator {
330    /// Creates an Ed25519 account authenticator.
331    pub fn ed25519(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
332        Self::Ed25519 {
333            public_key: public_key.into(),
334            signature: signature.into(),
335        }
336    }
337    /// Creates a single-key account authenticator.
338    pub fn single_key(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
339        Self::SingleKey {
340            public_key,
341            signature,
342        }
343    }
344
345    /// Creates a multi-key account authenticator.
346    pub fn multi_key(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
347        Self::MultiKey {
348            public_key,
349            signature,
350        }
351    }
352
353    /// Creates a no account authenticator.
354    pub fn no_account_authenticator() -> Self {
355        Self::NoAccountAuthenticator
356    }
357
358    /// Creates a keyless account authenticator.
359    ///
360    /// # Arguments
361    ///
362    /// * `public_key` - The ephemeral public key bytes
363    /// * `signature` - The BCS-serialized `KeylessSignature`
364    #[cfg(feature = "keyless")]
365    #[cfg_attr(docsrs, doc(cfg(feature = "keyless")))]
366    pub fn keyless(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
367        Self::Keyless {
368            public_key,
369            signature,
370        }
371    }
372}
373
374#[cfg(test)]
375mod tests {
376    use super::*;
377
378    #[test]
379    fn test_ed25519_authenticator() {
380        let mut pk = [0u8; 32];
381        pk[0..3].copy_from_slice(&[1, 2, 3]);
382        let mut sig = [0u8; 64];
383        sig[0..3].copy_from_slice(&[4, 5, 6]);
384
385        let auth = Ed25519Authenticator::new(pk.to_vec(), sig.to_vec());
386        let txn_auth: TransactionAuthenticator = auth.into();
387
388        match txn_auth {
389            TransactionAuthenticator::Ed25519 {
390                public_key,
391                signature,
392            } => {
393                assert_eq!(public_key.0[0..3], [1, 2, 3]);
394                assert_eq!(signature.0[0..3], [4, 5, 6]);
395            }
396            _ => panic!("wrong authenticator type"),
397        }
398    }
399
400    #[test]
401    fn test_multi_agent_authenticator() {
402        let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
403        let auth = TransactionAuthenticator::multi_agent(sender, vec![], vec![]);
404
405        match auth {
406            TransactionAuthenticator::MultiAgent { .. } => {}
407            _ => panic!("wrong authenticator type"),
408        }
409    }
410
411    #[test]
412    fn test_ed25519_bcs_format() {
413        // Test that Ed25519 serializes WITH length prefixes (Aptos BCS format)
414        let auth = TransactionAuthenticator::Ed25519 {
415            public_key: Ed25519PublicKey([0xab; 32]),
416            signature: Ed25519Signature([0xcd; 64]),
417        };
418        let bcs = aptos_bcs::to_bytes(&auth).unwrap();
419
420        // Ed25519 variant should be index 0
421        assert_eq!(bcs[0], 0, "Ed25519 variant index should be 0");
422        // Next byte is length prefix for pubkey (32 = 0x20)
423        assert_eq!(bcs[1], 32, "Pubkey length prefix should be 32");
424        // Next 32 bytes should be the pubkey
425        assert_eq!(bcs[2], 0xab, "First pubkey byte should be 0xab");
426        // After pubkey (1 + 1 + 32 = 34), length prefix for signature (64 = 0x40)
427        assert_eq!(bcs[34], 64, "Signature length prefix should be 64");
428        // Signature starts at offset 35
429        assert_eq!(bcs[35], 0xcd, "First signature byte should be 0xcd");
430        // Total: 1 (variant) + 1 (pubkey len) + 32 (pubkey) + 1 (sig len) + 64 (sig) = 99
431        assert_eq!(bcs.len(), 99, "BCS length should be 99");
432    }
433
434    #[test]
435    fn test_ed25519_authenticator_into_account_authenticator() {
436        let auth = Ed25519Authenticator::new(vec![0xaa; 32], vec![0xbb; 64]);
437        let account_auth: AccountAuthenticator = auth.into();
438
439        match account_auth {
440            AccountAuthenticator::Ed25519 {
441                public_key,
442                signature,
443            } => {
444                assert_eq!(public_key.0[0], 0xaa);
445                assert_eq!(signature.0[0], 0xbb);
446            }
447            _ => panic!("Expected Ed25519 variant"),
448        }
449    }
450
451    #[test]
452    fn test_transaction_authenticator_ed25519() {
453        let auth = TransactionAuthenticator::ed25519(vec![0x11; 32], vec![0x22; 64]);
454        match auth {
455            TransactionAuthenticator::Ed25519 {
456                public_key,
457                signature,
458            } => {
459                assert_eq!(public_key.0[0], 0x11);
460                assert_eq!(signature.0[0], 0x22);
461            }
462            _ => panic!("Expected Ed25519 variant"),
463        }
464    }
465
466    #[test]
467    fn test_transaction_authenticator_multi_ed25519() {
468        let auth = TransactionAuthenticator::multi_ed25519(vec![0x33; 64], vec![0x44; 128]);
469        match auth {
470            TransactionAuthenticator::MultiEd25519 {
471                public_key,
472                signature,
473            } => {
474                assert_eq!(public_key.len(), 64);
475                assert_eq!(signature.len(), 128);
476            }
477            _ => panic!("Expected MultiEd25519 variant"),
478        }
479    }
480
481    #[test]
482    fn test_fee_payer_authenticator() {
483        let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
484        let fee_payer = AccountAuthenticator::ed25519(vec![1; 32], vec![1; 64]);
485        let fee_payer_address = AccountAddress::from_hex("0x123").unwrap();
486
487        let auth = TransactionAuthenticator::fee_payer(
488            sender,
489            vec![],
490            vec![],
491            fee_payer_address,
492            fee_payer,
493        );
494
495        match auth {
496            TransactionAuthenticator::FeePayer {
497                fee_payer_address: addr,
498                ..
499            } => {
500                assert_eq!(addr, fee_payer_address);
501            }
502            _ => panic!("Expected FeePayer variant"),
503        }
504    }
505
506    #[test]
507    fn test_single_sender_authenticator() {
508        let sender = AccountAuthenticator::ed25519(vec![0x55; 32], vec![0x66; 64]);
509        let auth = TransactionAuthenticator::single_sender(sender);
510
511        match auth {
512            TransactionAuthenticator::SingleSender { sender } => match sender {
513                AccountAuthenticator::Ed25519 { public_key, .. } => {
514                    assert_eq!(public_key.0[0], 0x55);
515                }
516                _ => panic!("Expected Ed25519 sender"),
517            },
518            _ => panic!("Expected SingleSender variant"),
519        }
520    }
521
522    #[test]
523    fn test_account_authenticator_multi_key() {
524        let auth = AccountAuthenticator::multi_key(vec![0x77; 100], vec![0x88; 200]);
525        match auth {
526            AccountAuthenticator::MultiKey {
527                public_key,
528                signature,
529            } => {
530                assert_eq!(public_key.len(), 100);
531                assert_eq!(signature.len(), 200);
532            }
533            _ => panic!("Expected MultiKey variant"),
534        }
535    }
536
537    #[test]
538    fn test_ed25519_public_key_from_vec() {
539        let pk: Ed25519PublicKey = vec![0x12; 32].into();
540        assert_eq!(pk.0[0], 0x12);
541        assert_eq!(pk.0.len(), 32);
542    }
543
544    #[test]
545    fn test_ed25519_signature_from_vec() {
546        let sig: Ed25519Signature = vec![0x34; 64].into();
547        assert_eq!(sig.0[0], 0x34);
548        assert_eq!(sig.0.len(), 64);
549    }
550
551    #[test]
552    fn test_ed25519_public_key_bcs_roundtrip() {
553        let pk = Ed25519PublicKey([0xef; 32]);
554        let serialized = aptos_bcs::to_bytes(&pk).unwrap();
555        // Aptos BCS format: 1 byte length prefix (32) + 32 bytes = 33 bytes
556        assert_eq!(serialized.len(), 33);
557        assert_eq!(serialized[0], 32); // Length prefix
558        let deserialized: Ed25519PublicKey = aptos_bcs::from_bytes(&serialized).unwrap();
559        assert_eq!(pk, deserialized);
560    }
561
562    #[test]
563    fn test_ed25519_signature_bcs_roundtrip() {
564        let sig = Ed25519Signature([0x99; 64]);
565        let serialized = aptos_bcs::to_bytes(&sig).unwrap();
566        let deserialized: Ed25519Signature = aptos_bcs::from_bytes(&serialized).unwrap();
567        assert_eq!(sig, deserialized);
568    }
569
570    #[test]
571    fn test_multi_agent_with_secondary_signers() {
572        let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
573        let secondary_signer1 = AccountAuthenticator::ed25519(vec![1; 32], vec![1; 64]);
574        let secondary_signer2 = AccountAuthenticator::ed25519(vec![2; 32], vec![2; 64]);
575        let addr1 = AccountAddress::from_hex("0x111").unwrap();
576        let addr2 = AccountAddress::from_hex("0x222").unwrap();
577
578        let auth = TransactionAuthenticator::multi_agent(
579            sender,
580            vec![addr1, addr2],
581            vec![secondary_signer1, secondary_signer2],
582        );
583
584        match auth {
585            TransactionAuthenticator::MultiAgent {
586                secondary_signer_addresses,
587                secondary_signers,
588                ..
589            } => {
590                assert_eq!(secondary_signer_addresses.len(), 2);
591                assert_eq!(secondary_signers.len(), 2);
592            }
593            _ => panic!("Expected MultiAgent variant"),
594        }
595    }
596
597    #[test]
598    fn test_transaction_authenticator_bcs_roundtrip() {
599        let auth = TransactionAuthenticator::Ed25519 {
600            public_key: Ed25519PublicKey([0x11; 32]),
601            signature: Ed25519Signature([0x22; 64]),
602        };
603
604        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
605        let deserialized: TransactionAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
606
607        assert_eq!(auth, deserialized);
608    }
609
610    #[test]
611    fn test_account_authenticator_bcs_roundtrip() {
612        let auth = AccountAuthenticator::Ed25519 {
613            public_key: Ed25519PublicKey([0x33; 32]),
614            signature: Ed25519Signature([0x44; 64]),
615        };
616
617        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
618        let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
619
620        assert_eq!(auth, deserialized);
621    }
622
623    #[test]
624    fn test_account_authenticator_single_key() {
625        let auth = AccountAuthenticator::single_key(vec![0x55; 33], vec![0x66; 65]);
626        match auth {
627            AccountAuthenticator::SingleKey {
628                public_key,
629                signature,
630            } => {
631                assert_eq!(public_key.len(), 33);
632                assert_eq!(signature.len(), 65);
633            }
634            _ => panic!("Expected SingleKey variant"),
635        }
636    }
637
638    #[test]
639    fn test_account_authenticator_single_key_bcs_roundtrip() {
640        let auth = AccountAuthenticator::SingleKey {
641            public_key: vec![0x77; 33],
642            signature: vec![0x88; 65],
643        };
644
645        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
646        // SingleKey should be variant index 2
647        assert_eq!(serialized[0], 2, "SingleKey variant index should be 2");
648        let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
649        assert_eq!(auth, deserialized);
650    }
651
652    #[test]
653    fn test_no_account_authenticator() {
654        let auth = AccountAuthenticator::no_account_authenticator();
655        match auth {
656            AccountAuthenticator::NoAccountAuthenticator => {}
657            _ => panic!("Expected NoAccountAuthenticator variant"),
658        }
659    }
660
661    #[test]
662    fn test_no_account_authenticator_bcs_roundtrip() {
663        let auth = AccountAuthenticator::NoAccountAuthenticator;
664
665        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
666        // NoAccountAuthenticator should be variant index 4
667        assert_eq!(
668            serialized[0], 4,
669            "NoAccountAuthenticator variant index should be 4"
670        );
671        // It should be just the variant index, no payload
672        assert_eq!(
673            serialized.len(),
674            1,
675            "NoAccountAuthenticator should be 1 byte"
676        );
677        let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
678        assert_eq!(auth, deserialized);
679    }
680
681    #[test]
682    fn test_single_sender_with_single_key() {
683        let sender = AccountAuthenticator::single_key(vec![0x99; 33], vec![0xaa; 65]);
684        let auth = TransactionAuthenticator::single_sender(sender);
685
686        match auth {
687            TransactionAuthenticator::SingleSender { sender } => match sender {
688                AccountAuthenticator::SingleKey { public_key, .. } => {
689                    assert_eq!(public_key.len(), 33);
690                }
691                _ => panic!("Expected SingleKey sender"),
692            },
693            _ => panic!("Expected SingleSender variant"),
694        }
695    }
696
697    #[test]
698    fn test_account_authenticator_variant_indices() {
699        // Verify all variant indices match Aptos core
700        let ed25519 = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
701        let multi_ed25519 = AccountAuthenticator::MultiEd25519 {
702            public_key: vec![0; 64],
703            signature: vec![0; 128],
704        };
705        let single_key = AccountAuthenticator::single_key(vec![0; 33], vec![0; 65]);
706        let multi_key = AccountAuthenticator::multi_key(vec![0; 100], vec![0; 200]);
707        let no_account = AccountAuthenticator::no_account_authenticator();
708
709        assert_eq!(aptos_bcs::to_bytes(&ed25519).unwrap()[0], 0, "Ed25519 = 0");
710        assert_eq!(
711            aptos_bcs::to_bytes(&multi_ed25519).unwrap()[0],
712            1,
713            "MultiEd25519 = 1"
714        );
715        assert_eq!(
716            aptos_bcs::to_bytes(&single_key).unwrap()[0],
717            2,
718            "SingleKey = 2"
719        );
720        assert_eq!(
721            aptos_bcs::to_bytes(&multi_key).unwrap()[0],
722            3,
723            "MultiKey = 3"
724        );
725        assert_eq!(
726            aptos_bcs::to_bytes(&no_account).unwrap()[0],
727            4,
728            "NoAccountAuthenticator = 4"
729        );
730    }
731
732    #[test]
733    fn test_ed25519_public_key_try_from_bytes_valid() {
734        let bytes = vec![0x12; 32];
735        let pk = Ed25519PublicKey::try_from_bytes(&bytes).unwrap();
736        assert_eq!(pk.0[0], 0x12);
737    }
738
739    #[test]
740    fn test_ed25519_public_key_try_from_bytes_invalid_length() {
741        let bytes = vec![0x12; 16]; // Wrong length
742        let result = Ed25519PublicKey::try_from_bytes(&bytes);
743        assert!(result.is_err());
744    }
745
746    #[test]
747    fn test_ed25519_signature_try_from_bytes_valid() {
748        let bytes = vec![0x34; 64];
749        let sig = Ed25519Signature::try_from_bytes(&bytes).unwrap();
750        assert_eq!(sig.0[0], 0x34);
751    }
752
753    #[test]
754    fn test_ed25519_signature_try_from_bytes_invalid_length() {
755        let bytes = vec![0x34; 32]; // Wrong length
756        let result = Ed25519Signature::try_from_bytes(&bytes);
757        assert!(result.is_err());
758    }
759
760    #[test]
761    fn test_transaction_authenticator_variant_indices() {
762        // Verify transaction authenticator variant indices
763        let ed25519 = TransactionAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
764        let multi_ed25519 = TransactionAuthenticator::multi_ed25519(vec![0; 64], vec![0; 128]);
765        let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
766        let multi_agent = TransactionAuthenticator::multi_agent(sender.clone(), vec![], vec![]);
767        let fee_payer = TransactionAuthenticator::fee_payer(
768            sender.clone(),
769            vec![],
770            vec![],
771            AccountAddress::ONE,
772            sender.clone(),
773        );
774        let single_sender = TransactionAuthenticator::single_sender(sender);
775
776        assert_eq!(aptos_bcs::to_bytes(&ed25519).unwrap()[0], 0, "Ed25519 = 0");
777        assert_eq!(
778            aptos_bcs::to_bytes(&multi_ed25519).unwrap()[0],
779            1,
780            "MultiEd25519 = 1"
781        );
782        assert_eq!(
783            aptos_bcs::to_bytes(&multi_agent).unwrap()[0],
784            2,
785            "MultiAgent = 2"
786        );
787        assert_eq!(
788            aptos_bcs::to_bytes(&fee_payer).unwrap()[0],
789            3,
790            "FeePayer = 3"
791        );
792        assert_eq!(
793            aptos_bcs::to_bytes(&single_sender).unwrap()[0],
794            4,
795            "SingleSender = 4"
796        );
797    }
798
799    #[test]
800    fn test_multi_key_authenticator_bcs_roundtrip() {
801        let auth = AccountAuthenticator::multi_key(vec![0xaa; 100], vec![0xbb; 200]);
802
803        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
804        // MultiKey should be variant index 3
805        assert_eq!(serialized[0], 3, "MultiKey variant index should be 3");
806        let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
807        assert_eq!(auth, deserialized);
808    }
809
810    #[test]
811    fn test_multi_ed25519_authenticator_bcs_roundtrip() {
812        let auth = AccountAuthenticator::MultiEd25519 {
813            public_key: vec![0xcc; 64],
814            signature: vec![0xdd; 128],
815        };
816
817        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
818        // MultiEd25519 should be variant index 1
819        assert_eq!(serialized[0], 1, "MultiEd25519 variant index should be 1");
820        let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
821        assert_eq!(auth, deserialized);
822    }
823
824    #[test]
825    fn test_ed25519_public_key_deserialize_invalid_length() {
826        // Serialize with wrong length (use 16 bytes instead of 32)
827        let mut bytes = vec![16u8]; // Length prefix
828        bytes.extend_from_slice(&[0xab; 16]); // Only 16 bytes
829        let result: Result<Ed25519PublicKey, _> = aptos_bcs::from_bytes(&bytes);
830        assert!(result.is_err());
831    }
832
833    #[test]
834    fn test_ed25519_signature_deserialize_invalid_length() {
835        // Serialize with wrong length (use 32 bytes instead of 64)
836        let mut bytes = vec![32u8]; // Length prefix
837        bytes.extend_from_slice(&[0xab; 32]); // Only 32 bytes
838        let result: Result<Ed25519Signature, _> = aptos_bcs::from_bytes(&bytes);
839        assert!(result.is_err());
840    }
841}