Skip to main content

aptos_sdk/transaction/
authenticator.rs

1//! Transaction authenticators.
2
3use crate::types::AccountAddress;
4use serde::ser::{SerializeTuple, SerializeTupleVariant};
5use serde::{Deserialize, Deserializer, Serialize, Serializer};
6
7/// Helpers for emitting/consuming raw, length-prefix-free byte runs inside
8/// BCS-serialized structures.
9///
10/// The Aptos on-chain `AccountAuthenticator::{SingleKey, MultiKey, Keyless}` variants
11/// carry typed fields (e.g. `AnyPublicKey`, `AnySignature`, `MultiKeyPublicKey`,
12/// `MultiKeySignature`, `SingleKeyAuthenticator`) whose BCS encodings already begin
13/// with their own enum/struct tags. When the SDK represents those fields as
14/// `Vec<u8>` of pre-encoded bytes, the default serde-BCS impl wraps each `Vec<u8>`
15/// with another ULEB128 length prefix, producing wire bytes the on-chain
16/// deserializer rejects.
17///
18/// `serialize_tuple(len)` in `aptos_bcs` emits its elements without a length prefix,
19/// which is exactly what we need.
20fn serialize_raw_bytes<S: Serializer>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
21    // For empty payloads we can't open a 0-element tuple in some serializers,
22    // but BCS handles `serialize_tuple(0)` fine -- it produces no bytes.
23    let mut tup = serializer.serialize_tuple(bytes.len())?;
24    for byte in bytes {
25        tup.serialize_element(byte)?;
26    }
27    tup.end()
28}
29
30/// Ed25519 public key (32 bytes).
31/// Serializes WITH a length prefix as required by Aptos BCS format.
32#[derive(Clone, Debug, PartialEq, Eq)]
33pub struct Ed25519PublicKey(pub [u8; 32]);
34
35impl Serialize for Ed25519PublicKey {
36    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
37        // Aptos BCS format requires a length prefix for public keys
38        // Use serde_bytes to serialize with ULEB128 length prefix
39        serde_bytes::Bytes::new(&self.0).serialize(serializer)
40    }
41}
42
43impl<'de> Deserialize<'de> for Ed25519PublicKey {
44    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
45        // Deserialize with length prefix
46        let bytes: Vec<u8> = serde_bytes::deserialize(deserializer)?;
47        if bytes.len() != 32 {
48            return Err(serde::de::Error::invalid_length(bytes.len(), &"32 bytes"));
49        }
50        let mut arr = [0u8; 32];
51        arr.copy_from_slice(&bytes);
52        Ok(Ed25519PublicKey(arr))
53    }
54}
55
56impl From<Vec<u8>> for Ed25519PublicKey {
57    /// Converts a `Vec<u8>` to `Ed25519PublicKey`.
58    ///
59    /// # Panics
60    ///
61    /// Panics if the input is not exactly 32 bytes. Use `Ed25519PublicKey::try_from_bytes`
62    /// for fallible conversion.
63    fn from(bytes: Vec<u8>) -> Self {
64        assert!(
65            bytes.len() == 32,
66            "Ed25519PublicKey requires exactly 32 bytes, got {}",
67            bytes.len()
68        );
69        let mut arr = [0u8; 32];
70        arr.copy_from_slice(&bytes);
71        Ed25519PublicKey(arr)
72    }
73}
74
75impl Ed25519PublicKey {
76    /// Attempts to create an `Ed25519PublicKey` from a byte slice.
77    ///
78    /// Returns an error if the input is not exactly 32 bytes.
79    ///
80    /// # Errors
81    ///
82    /// Returns an error if the input slice is not exactly 32 bytes.
83    pub fn try_from_bytes(bytes: &[u8]) -> crate::error::AptosResult<Self> {
84        if bytes.len() != 32 {
85            return Err(crate::error::AptosError::InvalidPublicKey(format!(
86                "Ed25519PublicKey requires exactly 32 bytes, got {}",
87                bytes.len()
88            )));
89        }
90        let mut arr = [0u8; 32];
91        arr.copy_from_slice(bytes);
92        Ok(Ed25519PublicKey(arr))
93    }
94}
95
96/// Ed25519 signature (64 bytes).
97/// Serializes WITH a length prefix as required by Aptos BCS format.
98#[derive(Clone, Debug, PartialEq, Eq)]
99pub struct Ed25519Signature(pub [u8; 64]);
100
101impl Serialize for Ed25519Signature {
102    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
103        // Aptos BCS format requires a length prefix for signatures
104        // Use serde_bytes to serialize with ULEB128 length prefix
105        serde_bytes::Bytes::new(&self.0).serialize(serializer)
106    }
107}
108
109impl<'de> Deserialize<'de> for Ed25519Signature {
110    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
111        // Deserialize with length prefix
112        let bytes: Vec<u8> = serde_bytes::deserialize(deserializer)?;
113        if bytes.len() != 64 {
114            return Err(serde::de::Error::invalid_length(bytes.len(), &"64 bytes"));
115        }
116        let mut arr = [0u8; 64];
117        arr.copy_from_slice(&bytes);
118        Ok(Ed25519Signature(arr))
119    }
120}
121
122impl From<Vec<u8>> for Ed25519Signature {
123    /// Converts a `Vec<u8>` to `Ed25519Signature`.
124    ///
125    /// # Panics
126    ///
127    /// Panics if the input is not exactly 64 bytes. Use `Ed25519Signature::try_from_bytes`
128    /// for fallible conversion.
129    fn from(bytes: Vec<u8>) -> Self {
130        assert!(
131            bytes.len() == 64,
132            "Ed25519Signature requires exactly 64 bytes, got {}",
133            bytes.len()
134        );
135        let mut arr = [0u8; 64];
136        arr.copy_from_slice(&bytes);
137        Ed25519Signature(arr)
138    }
139}
140
141impl Ed25519Signature {
142    /// Attempts to create an `Ed25519Signature` from a byte slice.
143    ///
144    /// # Errors
145    ///
146    /// Returns an error if the input is not exactly 64 bytes.
147    pub fn try_from_bytes(bytes: &[u8]) -> crate::error::AptosResult<Self> {
148        if bytes.len() != 64 {
149            return Err(crate::error::AptosError::InvalidSignature(format!(
150                "Ed25519Signature requires exactly 64 bytes, got {}",
151                bytes.len()
152            )));
153        }
154        let mut arr = [0u8; 64];
155        arr.copy_from_slice(bytes);
156        Ok(Ed25519Signature(arr))
157    }
158}
159
160/// An authenticator for a transaction.
161///
162/// This contains the signature(s) and public key(s) that prove
163/// the transaction was authorized by the sender.
164///
165/// Note: Variant indices must match Aptos core for BCS compatibility:
166/// - 0: Ed25519
167/// - 1: `MultiEd25519`
168/// - 2: `MultiAgent`
169/// - 3: `FeePayer`
170/// - 4: `SingleSender` (for unified key support)
171#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
172pub enum TransactionAuthenticator {
173    /// Ed25519 single-key authentication (variant 0).
174    Ed25519 {
175        /// The Ed25519 public key (32 bytes).
176        public_key: Ed25519PublicKey,
177        /// The Ed25519 signature (64 bytes).
178        signature: Ed25519Signature,
179    },
180    /// Multi-Ed25519 authentication (variant 1).
181    MultiEd25519 {
182        /// The multi-Ed25519 public key.
183        public_key: Vec<u8>,
184        /// The multi-Ed25519 signature.
185        signature: Vec<u8>,
186    },
187    /// Multi-agent transaction authentication (variant 2).
188    MultiAgent {
189        /// The sender's authenticator.
190        sender: AccountAuthenticator,
191        /// Secondary signer addresses.
192        secondary_signer_addresses: Vec<AccountAddress>,
193        /// Secondary signers' authenticators.
194        secondary_signers: Vec<AccountAuthenticator>,
195    },
196    /// Fee payer transaction authentication (variant 3).
197    FeePayer {
198        /// The sender's authenticator.
199        sender: AccountAuthenticator,
200        /// Secondary signer addresses.
201        secondary_signer_addresses: Vec<AccountAddress>,
202        /// Secondary signers' authenticators.
203        secondary_signers: Vec<AccountAuthenticator>,
204        /// The fee payer's address.
205        fee_payer_address: AccountAddress,
206        /// The fee payer's authenticator.
207        fee_payer_signer: AccountAuthenticator,
208    },
209    /// Single sender authentication with account authenticator (variant 4).
210    /// Used for newer single-key and multi-key accounts.
211    SingleSender {
212        /// The account authenticator.
213        sender: AccountAuthenticator,
214    },
215}
216
217/// An authenticator for a single account (not the full transaction).
218///
219/// The on-chain BCS schema for the `SingleKey`, `MultiKey`, and `Keyless`
220/// variants wraps the public key and signature in typed Aptos-core structs
221/// (`SingleKeyAuthenticator`, `MultiKeyAuthenticator`, `KeylessSignature`)
222/// whose BCS encodings already begin with their own enum/struct tags.
223/// Internally we still hold pre-encoded `Vec<u8>` (callers produce those via the
224/// `AnyPublicKey`/`AnySignature`/`MultiKeyPublicKey`/`MultiKeySignature` helpers).
225/// To match the on-chain wire format exactly we hand-roll the `Serialize`
226/// implementation so those variants emit the inner bytes inline -- without the
227/// extra ULEB128 length prefix that the derive impl would add to a `Vec<u8>` field.
228#[derive(Clone, Debug, PartialEq, Eq)]
229pub enum AccountAuthenticator {
230    /// Ed25519 authentication (variant 0).
231    Ed25519 {
232        /// The public key (32 bytes).
233        public_key: Ed25519PublicKey,
234        /// The signature (64 bytes).
235        signature: Ed25519Signature,
236    },
237    /// Multi-Ed25519 authentication (variant 1).
238    MultiEd25519 {
239        /// The public key.
240        public_key: Vec<u8>,
241        /// The signature.
242        signature: Vec<u8>,
243    },
244    /// Single-key authentication (ed25519, secp256k1 and secp256r1) (variant 2).
245    SingleKey {
246        /// The public key (BCS-serialized `AnyPublicKey`).
247        public_key: Vec<u8>,
248        /// The signature (BCS-serialized `AnySignature`).
249        signature: Vec<u8>,
250    },
251    /// Multi-key authentication (mixed signature types) (variant 3).
252    MultiKey {
253        /// The public key (BCS-serialized `MultiKeyPublicKey`).
254        public_key: Vec<u8>,
255        /// The signature (BCS-serialized `MultiKeySignature`).
256        signature: Vec<u8>,
257    },
258    /// No account authenticator used for simulation only (variant 4).
259    NoAccountAuthenticator,
260    /// Keyless (OIDC-based) authentication (variant 5).
261    /// Uses ephemeral keys and ZK proofs for authentication.
262    #[cfg(feature = "keyless")]
263    Keyless {
264        /// The ephemeral public key bytes.
265        public_key: Vec<u8>,
266        /// The BCS-serialized `KeylessSignature` containing ephemeral signature and ZK proof.
267        signature: Vec<u8>,
268    },
269}
270
271// Tag values must match the order of the on-chain Rust enum, exactly.
272const ACCOUNT_AUTH_TAG_ED25519: u32 = 0;
273const ACCOUNT_AUTH_TAG_MULTI_ED25519: u32 = 1;
274const ACCOUNT_AUTH_TAG_SINGLE_KEY: u32 = 2;
275const ACCOUNT_AUTH_TAG_MULTI_KEY: u32 = 3;
276const ACCOUNT_AUTH_TAG_NO_ACCOUNT: u32 = 4;
277#[cfg(feature = "keyless")]
278const ACCOUNT_AUTH_TAG_KEYLESS: u32 = 5;
279
280impl Serialize for AccountAuthenticator {
281    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
282        match self {
283            AccountAuthenticator::Ed25519 {
284                public_key,
285                signature,
286            } => {
287                // Ed25519 carries strongly-typed fields whose Serialize impls already
288                // produce the correct BCS bytes; derive-equivalent emission is fine.
289                let mut tv = serializer.serialize_tuple_variant(
290                    "AccountAuthenticator",
291                    ACCOUNT_AUTH_TAG_ED25519,
292                    "Ed25519",
293                    2,
294                )?;
295                tv.serialize_field(public_key)?;
296                tv.serialize_field(signature)?;
297                tv.end()
298            }
299            AccountAuthenticator::MultiEd25519 {
300                public_key,
301                signature,
302            } => {
303                // On-chain `MultiEd25519PublicKey` and `MultiEd25519Signature` are both
304                // `Vec<u8>`-wrappers, so emitting our `Vec<u8>` fields with a length
305                // prefix matches the wire format.
306                let mut tv = serializer.serialize_tuple_variant(
307                    "AccountAuthenticator",
308                    ACCOUNT_AUTH_TAG_MULTI_ED25519,
309                    "MultiEd25519",
310                    2,
311                )?;
312                tv.serialize_field(public_key)?;
313                tv.serialize_field(signature)?;
314                tv.end()
315            }
316            AccountAuthenticator::SingleKey {
317                public_key,
318                signature,
319            } => {
320                // `SingleKey { authenticator: SingleKeyAuthenticator }`. We emit the inner
321                // `SingleKeyAuthenticator` bytes inline (AnyPublicKey then AnySignature).
322                serialize_account_auth_raw_pair(
323                    serializer,
324                    ACCOUNT_AUTH_TAG_SINGLE_KEY,
325                    "SingleKey",
326                    public_key,
327                    signature,
328                )
329            }
330            AccountAuthenticator::MultiKey {
331                public_key,
332                signature,
333            } => {
334                // `MultiKey { authenticator: MultiKeyAuthenticator }`. Emit the inner
335                // bytes inline (MultiKeyPublicKey then MultiKeySignature).
336                serialize_account_auth_raw_pair(
337                    serializer,
338                    ACCOUNT_AUTH_TAG_MULTI_KEY,
339                    "MultiKey",
340                    public_key,
341                    signature,
342                )
343            }
344            AccountAuthenticator::NoAccountAuthenticator => serializer
345                .serialize_tuple_variant(
346                    "AccountAuthenticator",
347                    ACCOUNT_AUTH_TAG_NO_ACCOUNT,
348                    "NoAccountAuthenticator",
349                    0,
350                )
351                .and_then(SerializeTupleVariant::end),
352            #[cfg(feature = "keyless")]
353            AccountAuthenticator::Keyless {
354                public_key,
355                signature,
356            } => serialize_account_auth_raw_pair(
357                serializer,
358                ACCOUNT_AUTH_TAG_KEYLESS,
359                "Keyless",
360                public_key,
361                signature,
362            ),
363        }
364    }
365}
366
367fn serialize_account_auth_raw_pair<S: Serializer>(
368    serializer: S,
369    tag: u32,
370    name: &'static str,
371    public_key: &[u8],
372    signature: &[u8],
373) -> Result<S::Ok, S::Error> {
374    // We model the inner authenticator struct (e.g. `SingleKeyAuthenticator`) as
375    // two raw-byte-runs concatenated together: emitting them as tuple-variant
376    // fields means BCS writes the tag then each field's bytes inline.
377    //
378    // Each raw field is serialized via `serialize_raw_bytes` which uses
379    // `serialize_tuple(len)` -- BCS emits no length prefix for tuples.
380    struct Raw<'a>(&'a [u8]);
381    impl Serialize for Raw<'_> {
382        fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
383            serialize_raw_bytes(self.0, s)
384        }
385    }
386
387    let mut tv = serializer.serialize_tuple_variant("AccountAuthenticator", tag, name, 2)?;
388    tv.serialize_field(&Raw(public_key))?;
389    tv.serialize_field(&Raw(signature))?;
390    tv.end()
391}
392
393impl<'de> Deserialize<'de> for AccountAuthenticator {
394    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
395        // The chain wire format for SingleKey/MultiKey/Keyless does not include
396        // explicit length prefixes for the inner public_key/signature byte runs
397        // (they are typed BCS structs whose total length is parser-recoverable from
398        // their content). This makes a length-agnostic deserializer non-trivial
399        // and out of scope here -- the SDK only ever *constructs* these
400        // authenticators locally and *serializes* them, never deserializes
401        // foreign on-wire bytes back into them.
402        //
403        // For tests that round-trip the SDK's own representation we deserialize
404        // a stable internal layout that matches the prior derive-based Serialize
405        // implementation: ULEB128(len)-prefixed Vec<u8> fields for the
406        // SingleKey/MultiKey/Keyless variants. This is sufficient for the
407        // existing test_account_authenticator_*_bcs_roundtrip tests, which
408        // serialize *and* deserialize entirely inside the SDK.
409        #[derive(Deserialize)]
410        enum Compat {
411            Ed25519 {
412                public_key: Ed25519PublicKey,
413                signature: Ed25519Signature,
414            },
415            MultiEd25519 {
416                public_key: Vec<u8>,
417                signature: Vec<u8>,
418            },
419            SingleKey {
420                public_key: Vec<u8>,
421                signature: Vec<u8>,
422            },
423            MultiKey {
424                public_key: Vec<u8>,
425                signature: Vec<u8>,
426            },
427            NoAccountAuthenticator,
428            #[cfg(feature = "keyless")]
429            Keyless {
430                public_key: Vec<u8>,
431                signature: Vec<u8>,
432            },
433        }
434
435        Compat::deserialize(deserializer).map(|c| match c {
436            Compat::Ed25519 {
437                public_key,
438                signature,
439            } => AccountAuthenticator::Ed25519 {
440                public_key,
441                signature,
442            },
443            Compat::MultiEd25519 {
444                public_key,
445                signature,
446            } => AccountAuthenticator::MultiEd25519 {
447                public_key,
448                signature,
449            },
450            Compat::SingleKey {
451                public_key,
452                signature,
453            } => AccountAuthenticator::SingleKey {
454                public_key,
455                signature,
456            },
457            Compat::MultiKey {
458                public_key,
459                signature,
460            } => AccountAuthenticator::MultiKey {
461                public_key,
462                signature,
463            },
464            Compat::NoAccountAuthenticator => AccountAuthenticator::NoAccountAuthenticator,
465            #[cfg(feature = "keyless")]
466            Compat::Keyless {
467                public_key,
468                signature,
469            } => AccountAuthenticator::Keyless {
470                public_key,
471                signature,
472            },
473        })
474    }
475}
476
477/// Ed25519 authenticator helper.
478#[derive(Clone, Debug, PartialEq, Eq)]
479pub struct Ed25519Authenticator {
480    /// The public key.
481    pub public_key: Vec<u8>,
482    /// The signature.
483    pub signature: Vec<u8>,
484}
485
486impl Ed25519Authenticator {
487    /// Creates a new Ed25519 authenticator.
488    pub fn new(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
489        Self {
490            public_key,
491            signature,
492        }
493    }
494}
495
496impl From<Ed25519Authenticator> for TransactionAuthenticator {
497    fn from(auth: Ed25519Authenticator) -> Self {
498        TransactionAuthenticator::Ed25519 {
499            public_key: auth.public_key.into(),
500            signature: auth.signature.into(),
501        }
502    }
503}
504
505impl From<Ed25519Authenticator> for AccountAuthenticator {
506    fn from(auth: Ed25519Authenticator) -> Self {
507        AccountAuthenticator::Ed25519 {
508            public_key: auth.public_key.into(),
509            signature: auth.signature.into(),
510        }
511    }
512}
513
514impl TransactionAuthenticator {
515    /// Creates an Ed25519 authenticator.
516    pub fn ed25519(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
517        Self::Ed25519 {
518            public_key: public_key.into(),
519            signature: signature.into(),
520        }
521    }
522
523    /// Creates a multi-Ed25519 authenticator.
524    pub fn multi_ed25519(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
525        Self::MultiEd25519 {
526            public_key,
527            signature,
528        }
529    }
530
531    /// Creates a multi-agent authenticator.
532    pub fn multi_agent(
533        sender: AccountAuthenticator,
534        secondary_signer_addresses: Vec<AccountAddress>,
535        secondary_signers: Vec<AccountAuthenticator>,
536    ) -> Self {
537        Self::MultiAgent {
538            sender,
539            secondary_signer_addresses,
540            secondary_signers,
541        }
542    }
543
544    /// Creates a fee payer authenticator.
545    pub fn fee_payer(
546        sender: AccountAuthenticator,
547        secondary_signer_addresses: Vec<AccountAddress>,
548        secondary_signers: Vec<AccountAuthenticator>,
549        fee_payer_address: AccountAddress,
550        fee_payer_signer: AccountAuthenticator,
551    ) -> Self {
552        Self::FeePayer {
553            sender,
554            secondary_signer_addresses,
555            secondary_signers,
556            fee_payer_address,
557            fee_payer_signer,
558        }
559    }
560
561    /// Creates a single sender authenticator.
562    /// This is used for accounts with the unified key model (including multi-key accounts).
563    pub fn single_sender(sender: AccountAuthenticator) -> Self {
564        Self::SingleSender { sender }
565    }
566
567    /// Rewrites this transaction authenticator for `/transactions/simulate`.
568    ///
569    /// Delegates nested [`AccountAuthenticator`] values to
570    /// [`AccountAuthenticator::for_simulate_endpoint`]. Top-level legacy
571    /// [`TransactionAuthenticator::Ed25519`] / [`TransactionAuthenticator::MultiEd25519`]
572    /// variants keep their public keys but zero signature bytes (there is no
573    /// [`AccountAuthenticator::NoAccountAuthenticator`] field in those top-level
574    /// authenticator shapes).
575    #[must_use]
576    pub fn for_simulate_endpoint(self) -> Self {
577        match self {
578            Self::Ed25519 {
579                public_key,
580                signature: _,
581            } => Self::Ed25519 {
582                public_key,
583                signature: Ed25519Signature([0u8; 64]),
584            },
585            Self::MultiEd25519 {
586                public_key,
587                signature,
588            } => Self::MultiEd25519 {
589                public_key,
590                signature: vec![0u8; signature.len()],
591            },
592            Self::MultiAgent {
593                sender,
594                secondary_signer_addresses,
595                secondary_signers,
596            } => {
597                let secondary: Vec<AccountAuthenticator> = secondary_signers
598                    .into_iter()
599                    .map(AccountAuthenticator::for_simulate_endpoint)
600                    .collect();
601                Self::multi_agent(
602                    sender.for_simulate_endpoint(),
603                    secondary_signer_addresses,
604                    secondary,
605                )
606            }
607            Self::FeePayer {
608                sender,
609                secondary_signer_addresses,
610                secondary_signers,
611                fee_payer_address,
612                fee_payer_signer,
613            } => {
614                let secondary: Vec<AccountAuthenticator> = secondary_signers
615                    .into_iter()
616                    .map(AccountAuthenticator::for_simulate_endpoint)
617                    .collect();
618                Self::fee_payer(
619                    sender.for_simulate_endpoint(),
620                    secondary_signer_addresses,
621                    secondary,
622                    fee_payer_address,
623                    fee_payer_signer.for_simulate_endpoint(),
624                )
625            }
626            Self::SingleSender { sender } => Self::single_sender(sender.for_simulate_endpoint()),
627        }
628    }
629}
630
631impl AccountAuthenticator {
632    /// Creates an Ed25519 account authenticator.
633    pub fn ed25519(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
634        Self::Ed25519 {
635            public_key: public_key.into(),
636            signature: signature.into(),
637        }
638    }
639    /// Creates a single-key account authenticator.
640    pub fn single_key(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
641        Self::SingleKey {
642            public_key,
643            signature,
644        }
645    }
646
647    /// Creates a multi-key account authenticator.
648    pub fn multi_key(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
649        Self::MultiKey {
650            public_key,
651            signature,
652        }
653    }
654
655    /// Creates a no account authenticator.
656    pub fn no_account_authenticator() -> Self {
657        Self::NoAccountAuthenticator
658    }
659
660    /// Rewrites this authenticator for the Aptos `/transactions/simulate` endpoint.
661    ///
662    /// The fullnode rejects requests whose authenticators contain a cryptographically
663    /// **valid** signature (HTTP 400: "Simulated transactions must not have a valid
664    /// signature"). The SDK applies this transform automatically before simulate HTTP
665    /// calls so callers do not need to hand-replace authenticators.
666    ///
667    /// * [`SingleKey`](AccountAuthenticator::SingleKey) and [`Keyless`](AccountAuthenticator::Keyless)
668    ///   become [`AccountAuthenticator::NoAccountAuthenticator`], matching the common workaround for unified-key
669    ///   accounts.
670    /// * [`Ed25519`](AccountAuthenticator::Ed25519), [`MultiEd25519`](AccountAuthenticator::MultiEd25519),
671    ///   and [`MultiKey`](AccountAuthenticator::MultiKey) keep their public key material but replace
672    ///   signature bytes with zeros (preserving `MultiEd25519` / `MultiKey` vector lengths).
673    #[must_use]
674    pub fn for_simulate_endpoint(self) -> Self {
675        match self {
676            Self::NoAccountAuthenticator => Self::NoAccountAuthenticator,
677            Self::Ed25519 {
678                public_key,
679                signature: _,
680            } => Self::Ed25519 {
681                public_key,
682                signature: Ed25519Signature([0u8; 64]),
683            },
684            Self::MultiEd25519 {
685                public_key,
686                signature,
687            } => Self::MultiEd25519 {
688                public_key,
689                signature: vec![0u8; signature.len()],
690            },
691            Self::SingleKey { .. } => Self::NoAccountAuthenticator,
692            Self::MultiKey {
693                public_key,
694                signature,
695            } => Self::MultiKey {
696                public_key,
697                signature: vec![0u8; signature.len()],
698            },
699            #[cfg(feature = "keyless")]
700            Self::Keyless { .. } => Self::NoAccountAuthenticator,
701        }
702    }
703
704    /// Creates a keyless account authenticator.
705    ///
706    /// # Arguments
707    ///
708    /// * `public_key` - The ephemeral public key bytes
709    /// * `signature` - The BCS-serialized `KeylessSignature`
710    #[cfg(feature = "keyless")]
711    pub fn keyless(public_key: Vec<u8>, signature: Vec<u8>) -> Self {
712        Self::Keyless {
713            public_key,
714            signature,
715        }
716    }
717
718    /// Verifies the authenticator against a signing message.
719    ///
720    /// # Errors
721    ///
722    /// Returns an error if the authenticator does not verify for the message.
723    pub fn verify(&self, message: &[u8]) -> crate::error::AptosResult<()> {
724        match self {
725            #[cfg(feature = "ed25519")]
726            Self::Ed25519 {
727                public_key,
728                signature,
729            } => {
730                let public_key = crate::crypto::Ed25519PublicKey::from_bytes(&public_key.0)?;
731                let signature = crate::crypto::Ed25519Signature::from_bytes(&signature.0)?;
732                public_key.verify(message, &signature)
733            }
734            #[cfg(not(feature = "ed25519"))]
735            Self::Ed25519 { .. } => Err(crate::error::AptosError::FeatureNotEnabled(
736                "Ed25519 verification".into(),
737            )),
738            #[cfg(feature = "ed25519")]
739            Self::MultiEd25519 {
740                public_key,
741                signature,
742            } => {
743                let public_key = crate::crypto::MultiEd25519PublicKey::from_bytes(public_key)?;
744                let signature = crate::crypto::MultiEd25519Signature::from_bytes(signature)?;
745                public_key.verify(message, &signature)
746            }
747            #[cfg(not(feature = "ed25519"))]
748            Self::MultiEd25519 { .. } => Err(crate::error::AptosError::FeatureNotEnabled(
749                "MultiEd25519 verification".into(),
750            )),
751            Self::SingleKey {
752                public_key,
753                signature,
754            } => {
755                let pk = crate::crypto::AnyPublicKey::from_bcs_bytes(public_key)?;
756                let sig = crate::crypto::AnySignature::from_bcs_bytes(signature)?;
757                pk.verify(message, &sig)
758            }
759            Self::MultiKey {
760                public_key,
761                signature,
762            } => {
763                let pk = crate::crypto::MultiKeyPublicKey::from_bytes(public_key)?;
764                let sig = crate::crypto::MultiKeySignature::from_bytes(signature)?;
765                pk.verify(message, &sig)
766            }
767            Self::NoAccountAuthenticator => Err(crate::error::AptosError::InvalidSignature(
768                "no account authenticator cannot be verified".into(),
769            )),
770            #[cfg(feature = "keyless")]
771            Self::Keyless { .. } => Err(crate::error::AptosError::FeatureNotEnabled(
772                "local keyless verification".into(),
773            )),
774        }
775    }
776
777    /// Returns the account address implied by this authenticator's public key material.
778    ///
779    /// # Errors
780    ///
781    /// Returns an error if the contained public key bytes cannot be parsed.
782    pub fn derived_address(&self) -> crate::error::AptosResult<AccountAddress> {
783        match self {
784            #[cfg(feature = "ed25519")]
785            Self::Ed25519 { public_key, .. } => {
786                let public_key = crate::crypto::Ed25519PublicKey::from_bytes(&public_key.0)?;
787                Ok(public_key.to_address())
788            }
789            #[cfg(not(feature = "ed25519"))]
790            Self::Ed25519 { .. } => Err(crate::error::AptosError::FeatureNotEnabled(
791                "Ed25519 address derivation".into(),
792            )),
793            #[cfg(feature = "ed25519")]
794            Self::MultiEd25519 { public_key, .. } => {
795                let public_key = crate::crypto::MultiEd25519PublicKey::from_bytes(public_key)?;
796                Ok(public_key.to_address())
797            }
798            #[cfg(not(feature = "ed25519"))]
799            Self::MultiEd25519 { .. } => Err(crate::error::AptosError::FeatureNotEnabled(
800                "MultiEd25519 address derivation".into(),
801            )),
802            Self::SingleKey { public_key, .. } => Ok(AccountAddress::new(
803                crate::crypto::derive_authentication_key(
804                    public_key,
805                    crate::crypto::SINGLE_KEY_SCHEME,
806                ),
807            )),
808            Self::MultiKey { public_key, .. } => {
809                let pk = crate::crypto::MultiKeyPublicKey::from_bytes(public_key)?;
810                Ok(pk.to_address())
811            }
812            Self::NoAccountAuthenticator => Err(crate::error::AptosError::InvalidSignature(
813                "no account authenticator has no derived address".into(),
814            )),
815            #[cfg(feature = "keyless")]
816            Self::Keyless { .. } => Err(crate::error::AptosError::FeatureNotEnabled(
817                "local keyless address derivation".into(),
818            )),
819        }
820    }
821}
822
823#[cfg(test)]
824mod tests {
825    use super::*;
826    use crate::crypto::{AnyPublicKey, AnySignature, MultiKeyPublicKey, MultiKeySignature};
827
828    #[test]
829    fn test_ed25519_authenticator() {
830        let mut pk = [0u8; 32];
831        pk[0..3].copy_from_slice(&[1, 2, 3]);
832        let mut sig = [0u8; 64];
833        sig[0..3].copy_from_slice(&[4, 5, 6]);
834
835        let auth = Ed25519Authenticator::new(pk.to_vec(), sig.to_vec());
836        let txn_auth: TransactionAuthenticator = auth.into();
837
838        match txn_auth {
839            TransactionAuthenticator::Ed25519 {
840                public_key,
841                signature,
842            } => {
843                assert_eq!(public_key.0[0..3], [1, 2, 3]);
844                assert_eq!(signature.0[0..3], [4, 5, 6]);
845            }
846            _ => panic!("wrong authenticator type"),
847        }
848    }
849
850    #[test]
851    fn test_multi_agent_authenticator() {
852        let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
853        let auth = TransactionAuthenticator::multi_agent(sender, vec![], vec![]);
854
855        match auth {
856            TransactionAuthenticator::MultiAgent { .. } => {}
857            _ => panic!("wrong authenticator type"),
858        }
859    }
860
861    #[test]
862    fn test_ed25519_bcs_format() {
863        // Test that Ed25519 serializes WITH length prefixes (Aptos BCS format)
864        let auth = TransactionAuthenticator::Ed25519 {
865            public_key: Ed25519PublicKey([0xab; 32]),
866            signature: Ed25519Signature([0xcd; 64]),
867        };
868        let bcs = aptos_bcs::to_bytes(&auth).unwrap();
869
870        // Ed25519 variant should be index 0
871        assert_eq!(bcs[0], 0, "Ed25519 variant index should be 0");
872        // Next byte is length prefix for pubkey (32 = 0x20)
873        assert_eq!(bcs[1], 32, "Pubkey length prefix should be 32");
874        // Next 32 bytes should be the pubkey
875        assert_eq!(bcs[2], 0xab, "First pubkey byte should be 0xab");
876        // After pubkey (1 + 1 + 32 = 34), length prefix for signature (64 = 0x40)
877        assert_eq!(bcs[34], 64, "Signature length prefix should be 64");
878        // Signature starts at offset 35
879        assert_eq!(bcs[35], 0xcd, "First signature byte should be 0xcd");
880        // Total: 1 (variant) + 1 (pubkey len) + 32 (pubkey) + 1 (sig len) + 64 (sig) = 99
881        assert_eq!(bcs.len(), 99, "BCS length should be 99");
882    }
883
884    #[test]
885    fn test_ed25519_authenticator_into_account_authenticator() {
886        let auth = Ed25519Authenticator::new(vec![0xaa; 32], vec![0xbb; 64]);
887        let account_auth: AccountAuthenticator = auth.into();
888
889        match account_auth {
890            AccountAuthenticator::Ed25519 {
891                public_key,
892                signature,
893            } => {
894                assert_eq!(public_key.0[0], 0xaa);
895                assert_eq!(signature.0[0], 0xbb);
896            }
897            _ => panic!("Expected Ed25519 variant"),
898        }
899    }
900
901    #[test]
902    fn test_transaction_authenticator_ed25519() {
903        let auth = TransactionAuthenticator::ed25519(vec![0x11; 32], vec![0x22; 64]);
904        match auth {
905            TransactionAuthenticator::Ed25519 {
906                public_key,
907                signature,
908            } => {
909                assert_eq!(public_key.0[0], 0x11);
910                assert_eq!(signature.0[0], 0x22);
911            }
912            _ => panic!("Expected Ed25519 variant"),
913        }
914    }
915
916    #[test]
917    fn test_transaction_authenticator_multi_ed25519() {
918        let auth = TransactionAuthenticator::multi_ed25519(vec![0x33; 64], vec![0x44; 128]);
919        match auth {
920            TransactionAuthenticator::MultiEd25519 {
921                public_key,
922                signature,
923            } => {
924                assert_eq!(public_key.len(), 64);
925                assert_eq!(signature.len(), 128);
926            }
927            _ => panic!("Expected MultiEd25519 variant"),
928        }
929    }
930
931    #[test]
932    fn test_fee_payer_authenticator() {
933        let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
934        let fee_payer = AccountAuthenticator::ed25519(vec![1; 32], vec![1; 64]);
935        let fee_payer_address = AccountAddress::from_hex("0x123").unwrap();
936
937        let auth = TransactionAuthenticator::fee_payer(
938            sender,
939            vec![],
940            vec![],
941            fee_payer_address,
942            fee_payer,
943        );
944
945        match auth {
946            TransactionAuthenticator::FeePayer {
947                fee_payer_address: addr,
948                ..
949            } => {
950                assert_eq!(addr, fee_payer_address);
951            }
952            _ => panic!("Expected FeePayer variant"),
953        }
954    }
955
956    #[test]
957    fn test_single_sender_authenticator() {
958        let sender = AccountAuthenticator::ed25519(vec![0x55; 32], vec![0x66; 64]);
959        let auth = TransactionAuthenticator::single_sender(sender);
960
961        match auth {
962            TransactionAuthenticator::SingleSender { sender } => match sender {
963                AccountAuthenticator::Ed25519 { public_key, .. } => {
964                    assert_eq!(public_key.0[0], 0x55);
965                }
966                _ => panic!("Expected Ed25519 sender"),
967            },
968            _ => panic!("Expected SingleSender variant"),
969        }
970    }
971
972    #[test]
973    fn test_account_authenticator_multi_key() {
974        let auth = AccountAuthenticator::multi_key(vec![0x77; 100], vec![0x88; 200]);
975        match auth {
976            AccountAuthenticator::MultiKey {
977                public_key,
978                signature,
979            } => {
980                assert_eq!(public_key.len(), 100);
981                assert_eq!(signature.len(), 200);
982            }
983            _ => panic!("Expected MultiKey variant"),
984        }
985    }
986
987    #[test]
988    fn test_ed25519_public_key_from_vec() {
989        let pk: Ed25519PublicKey = vec![0x12; 32].into();
990        assert_eq!(pk.0[0], 0x12);
991        assert_eq!(pk.0.len(), 32);
992    }
993
994    #[test]
995    fn test_ed25519_signature_from_vec() {
996        let sig: Ed25519Signature = vec![0x34; 64].into();
997        assert_eq!(sig.0[0], 0x34);
998        assert_eq!(sig.0.len(), 64);
999    }
1000
1001    #[test]
1002    fn test_ed25519_public_key_bcs_roundtrip() {
1003        let pk = Ed25519PublicKey([0xef; 32]);
1004        let serialized = aptos_bcs::to_bytes(&pk).unwrap();
1005        // Aptos BCS format: 1 byte length prefix (32) + 32 bytes = 33 bytes
1006        assert_eq!(serialized.len(), 33);
1007        assert_eq!(serialized[0], 32); // Length prefix
1008        let deserialized: Ed25519PublicKey = aptos_bcs::from_bytes(&serialized).unwrap();
1009        assert_eq!(pk, deserialized);
1010    }
1011
1012    #[test]
1013    fn test_ed25519_signature_bcs_roundtrip() {
1014        let sig = Ed25519Signature([0x99; 64]);
1015        let serialized = aptos_bcs::to_bytes(&sig).unwrap();
1016        let deserialized: Ed25519Signature = aptos_bcs::from_bytes(&serialized).unwrap();
1017        assert_eq!(sig, deserialized);
1018    }
1019
1020    #[test]
1021    fn test_multi_agent_with_secondary_signers() {
1022        let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
1023        let secondary_signer1 = AccountAuthenticator::ed25519(vec![1; 32], vec![1; 64]);
1024        let secondary_signer2 = AccountAuthenticator::ed25519(vec![2; 32], vec![2; 64]);
1025        let addr1 = AccountAddress::from_hex("0x111").unwrap();
1026        let addr2 = AccountAddress::from_hex("0x222").unwrap();
1027
1028        let auth = TransactionAuthenticator::multi_agent(
1029            sender,
1030            vec![addr1, addr2],
1031            vec![secondary_signer1, secondary_signer2],
1032        );
1033
1034        match auth {
1035            TransactionAuthenticator::MultiAgent {
1036                secondary_signer_addresses,
1037                secondary_signers,
1038                ..
1039            } => {
1040                assert_eq!(secondary_signer_addresses.len(), 2);
1041                assert_eq!(secondary_signers.len(), 2);
1042            }
1043            _ => panic!("Expected MultiAgent variant"),
1044        }
1045    }
1046
1047    #[test]
1048    fn test_transaction_authenticator_bcs_roundtrip() {
1049        let auth = TransactionAuthenticator::Ed25519 {
1050            public_key: Ed25519PublicKey([0x11; 32]),
1051            signature: Ed25519Signature([0x22; 64]),
1052        };
1053
1054        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
1055        let deserialized: TransactionAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
1056
1057        assert_eq!(auth, deserialized);
1058    }
1059
1060    #[test]
1061    fn test_account_authenticator_bcs_roundtrip() {
1062        let auth = AccountAuthenticator::Ed25519 {
1063            public_key: Ed25519PublicKey([0x33; 32]),
1064            signature: Ed25519Signature([0x44; 64]),
1065        };
1066
1067        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
1068        let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
1069
1070        assert_eq!(auth, deserialized);
1071    }
1072
1073    #[test]
1074    fn test_account_authenticator_single_key() {
1075        let auth = AccountAuthenticator::single_key(vec![0x55; 33], vec![0x66; 65]);
1076        match auth {
1077            AccountAuthenticator::SingleKey {
1078                public_key,
1079                signature,
1080            } => {
1081                assert_eq!(public_key.len(), 33);
1082                assert_eq!(signature.len(), 65);
1083            }
1084            _ => panic!("Expected SingleKey variant"),
1085        }
1086    }
1087
1088    #[test]
1089    fn test_account_authenticator_single_key_bcs_wire_format() {
1090        // The on-chain `AccountAuthenticator::SingleKey { authenticator: SingleKeyAuthenticator }`
1091        // BCS encoding is:
1092        //   * variant tag (ULEB128 of 2) -> 1 byte
1093        //   * BCS(SingleKeyAuthenticator) = BCS(AnyPublicKey) || BCS(AnySignature)
1094        //
1095        // The inner public_key/signature byte runs already start with their own
1096        // enum/struct tags, so they must be emitted *without* any additional
1097        // length prefix. Verify this by hand-building the expected output.
1098        let pk = vec![0x77; 33]; // simulated AnyPublicKey bytes
1099        let sig = vec![0x88; 65]; // simulated AnySignature bytes
1100
1101        let auth = AccountAuthenticator::SingleKey {
1102            public_key: pk.clone(),
1103            signature: sig.clone(),
1104        };
1105
1106        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
1107        let mut expected = Vec::new();
1108        expected.push(2u8); // variant tag
1109        expected.extend_from_slice(&pk);
1110        expected.extend_from_slice(&sig);
1111        assert_eq!(
1112            serialized, expected,
1113            "SingleKey wire format must be variant tag + raw pubkey bytes + raw signature bytes \
1114             (no inner length prefixes)"
1115        );
1116    }
1117
1118    #[cfg(feature = "ed25519")]
1119    #[test]
1120    fn test_account_authenticator_single_key_verify_and_derived_address() {
1121        use crate::crypto::{Ed25519PrivateKey, SINGLE_KEY_SCHEME, derive_authentication_key};
1122
1123        let private_key = Ed25519PrivateKey::generate();
1124        let message = b"single-key verify test";
1125        let public_key = crate::crypto::AnyPublicKey::ed25519(&private_key.public_key());
1126        let signature = crate::crypto::AnySignature::ed25519(&private_key.sign(message));
1127        let auth =
1128            AccountAuthenticator::single_key(public_key.to_bcs_bytes(), signature.to_bcs_bytes());
1129
1130        auth.verify(message).unwrap();
1131        let expected = AccountAddress::new(derive_authentication_key(
1132            &public_key.to_bcs_bytes(),
1133            SINGLE_KEY_SCHEME,
1134        ));
1135        assert_eq!(auth.derived_address().unwrap(), expected);
1136    }
1137
1138    #[cfg(feature = "ed25519")]
1139    #[test]
1140    fn test_account_authenticator_multi_ed25519_verify_and_derived_address() {
1141        use crate::account::{Account, MultiEd25519Account};
1142        use crate::crypto::Ed25519PrivateKey;
1143
1144        let account = MultiEd25519Account::new(
1145            vec![Ed25519PrivateKey::generate(), Ed25519PrivateKey::generate()],
1146            2,
1147        )
1148        .unwrap();
1149        let message = b"multi-ed25519 verify test";
1150        let auth = AccountAuthenticator::MultiEd25519 {
1151            public_key: account.public_key_bytes(),
1152            signature: account.sign(message).unwrap().to_bytes(),
1153        };
1154
1155        auth.verify(message).unwrap();
1156        assert_eq!(auth.derived_address().unwrap(), account.address());
1157    }
1158
1159    #[test]
1160    fn test_no_account_authenticator() {
1161        let auth = AccountAuthenticator::no_account_authenticator();
1162        match auth {
1163            AccountAuthenticator::NoAccountAuthenticator => {}
1164            _ => panic!("Expected NoAccountAuthenticator variant"),
1165        }
1166    }
1167
1168    #[cfg(feature = "ed25519")]
1169    #[test]
1170    fn test_account_authenticator_for_simulate_endpoint_single_key_to_no_account() {
1171        let auth = AccountAuthenticator::single_key(vec![0x01, 0x02], vec![0x03, 0x04]);
1172        let sanitized = auth.for_simulate_endpoint();
1173        assert!(matches!(
1174            sanitized,
1175            AccountAuthenticator::NoAccountAuthenticator
1176        ));
1177    }
1178
1179    #[cfg(feature = "ed25519")]
1180    #[test]
1181    fn test_transaction_authenticator_for_simulate_endpoint_single_sender_strips_single_key() {
1182        let sender = AccountAuthenticator::single_key(vec![0x05, 0x06], vec![0x07, 0x08]);
1183        let auth = TransactionAuthenticator::single_sender(sender);
1184        let sanitized = auth.for_simulate_endpoint();
1185        assert!(matches!(
1186            sanitized,
1187            TransactionAuthenticator::SingleSender { ref sender }
1188                if matches!(sender, AccountAuthenticator::NoAccountAuthenticator)
1189        ));
1190    }
1191
1192    #[cfg(feature = "ed25519")]
1193    #[test]
1194    fn test_transaction_authenticator_for_simulate_endpoint_ed25519_zeros_sig() {
1195        let auth = TransactionAuthenticator::Ed25519 {
1196            public_key: Ed25519PublicKey([7u8; 32]),
1197            signature: Ed25519Signature([9u8; 64]),
1198        };
1199        let sanitized = auth.for_simulate_endpoint();
1200        match sanitized {
1201            TransactionAuthenticator::Ed25519 { signature, .. } => {
1202                assert_eq!(signature.0, [0u8; 64]);
1203            }
1204            _ => panic!("expected Ed25519"),
1205        }
1206    }
1207
1208    #[test]
1209    fn test_no_account_authenticator_verify_and_derived_address_errors() {
1210        let auth = AccountAuthenticator::NoAccountAuthenticator;
1211        assert!(auth.verify(b"no-auth").is_err());
1212        assert!(auth.derived_address().is_err());
1213    }
1214
1215    #[cfg(feature = "keyless")]
1216    #[test]
1217    fn test_keyless_authenticator_verify_and_derived_address_not_enabled() {
1218        let auth = AccountAuthenticator::keyless(vec![0x11; 32], vec![0x22; 64]);
1219        assert!(auth.verify(b"keyless-local").is_err());
1220        assert!(auth.derived_address().is_err());
1221    }
1222
1223    #[test]
1224    fn test_no_account_authenticator_bcs_roundtrip() {
1225        let auth = AccountAuthenticator::NoAccountAuthenticator;
1226
1227        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
1228        // NoAccountAuthenticator should be variant index 4
1229        assert_eq!(
1230            serialized[0], 4,
1231            "NoAccountAuthenticator variant index should be 4"
1232        );
1233        // It should be just the variant index, no payload
1234        assert_eq!(
1235            serialized.len(),
1236            1,
1237            "NoAccountAuthenticator should be 1 byte"
1238        );
1239        let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
1240        assert_eq!(auth, deserialized);
1241    }
1242
1243    #[test]
1244    fn test_single_sender_with_single_key() {
1245        let sender = AccountAuthenticator::single_key(vec![0x99; 33], vec![0xaa; 65]);
1246        let auth = TransactionAuthenticator::single_sender(sender);
1247
1248        match auth {
1249            TransactionAuthenticator::SingleSender { sender } => match sender {
1250                AccountAuthenticator::SingleKey { public_key, .. } => {
1251                    assert_eq!(public_key.len(), 33);
1252                }
1253                _ => panic!("Expected SingleKey sender"),
1254            },
1255            _ => panic!("Expected SingleSender variant"),
1256        }
1257    }
1258
1259    #[test]
1260    fn test_account_authenticator_variant_indices() {
1261        // Verify all variant indices match Aptos core
1262        let ed25519 = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
1263        let multi_ed25519 = AccountAuthenticator::MultiEd25519 {
1264            public_key: vec![0; 64],
1265            signature: vec![0; 128],
1266        };
1267        let single_key = AccountAuthenticator::single_key(vec![0; 33], vec![0; 65]);
1268        let multi_key = AccountAuthenticator::multi_key(vec![0; 100], vec![0; 200]);
1269        let no_account = AccountAuthenticator::no_account_authenticator();
1270
1271        assert_eq!(aptos_bcs::to_bytes(&ed25519).unwrap()[0], 0, "Ed25519 = 0");
1272        assert_eq!(
1273            aptos_bcs::to_bytes(&multi_ed25519).unwrap()[0],
1274            1,
1275            "MultiEd25519 = 1"
1276        );
1277        assert_eq!(
1278            aptos_bcs::to_bytes(&single_key).unwrap()[0],
1279            2,
1280            "SingleKey = 2"
1281        );
1282        assert_eq!(
1283            aptos_bcs::to_bytes(&multi_key).unwrap()[0],
1284            3,
1285            "MultiKey = 3"
1286        );
1287        assert_eq!(
1288            aptos_bcs::to_bytes(&no_account).unwrap()[0],
1289            4,
1290            "NoAccountAuthenticator = 4"
1291        );
1292    }
1293
1294    #[test]
1295    fn test_ed25519_public_key_try_from_bytes_valid() {
1296        let bytes = vec![0x12; 32];
1297        let pk = Ed25519PublicKey::try_from_bytes(&bytes).unwrap();
1298        assert_eq!(pk.0[0], 0x12);
1299    }
1300
1301    #[test]
1302    fn test_ed25519_public_key_try_from_bytes_invalid_length() {
1303        let bytes = vec![0x12; 16]; // Wrong length
1304        let result = Ed25519PublicKey::try_from_bytes(&bytes);
1305        assert!(result.is_err());
1306    }
1307
1308    #[test]
1309    fn test_ed25519_signature_try_from_bytes_valid() {
1310        let bytes = vec![0x34; 64];
1311        let sig = Ed25519Signature::try_from_bytes(&bytes).unwrap();
1312        assert_eq!(sig.0[0], 0x34);
1313    }
1314
1315    #[test]
1316    fn test_ed25519_signature_try_from_bytes_invalid_length() {
1317        let bytes = vec![0x34; 32]; // Wrong length
1318        let result = Ed25519Signature::try_from_bytes(&bytes);
1319        assert!(result.is_err());
1320    }
1321
1322    #[test]
1323    fn test_transaction_authenticator_variant_indices() {
1324        // Verify transaction authenticator variant indices
1325        let ed25519 = TransactionAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
1326        let multi_ed25519 = TransactionAuthenticator::multi_ed25519(vec![0; 64], vec![0; 128]);
1327        let sender = AccountAuthenticator::ed25519(vec![0; 32], vec![0; 64]);
1328        let multi_agent = TransactionAuthenticator::multi_agent(sender.clone(), vec![], vec![]);
1329        let fee_payer = TransactionAuthenticator::fee_payer(
1330            sender.clone(),
1331            vec![],
1332            vec![],
1333            AccountAddress::ONE,
1334            sender.clone(),
1335        );
1336        let single_sender = TransactionAuthenticator::single_sender(sender);
1337
1338        assert_eq!(aptos_bcs::to_bytes(&ed25519).unwrap()[0], 0, "Ed25519 = 0");
1339        assert_eq!(
1340            aptos_bcs::to_bytes(&multi_ed25519).unwrap()[0],
1341            1,
1342            "MultiEd25519 = 1"
1343        );
1344        assert_eq!(
1345            aptos_bcs::to_bytes(&multi_agent).unwrap()[0],
1346            2,
1347            "MultiAgent = 2"
1348        );
1349        assert_eq!(
1350            aptos_bcs::to_bytes(&fee_payer).unwrap()[0],
1351            3,
1352            "FeePayer = 3"
1353        );
1354        assert_eq!(
1355            aptos_bcs::to_bytes(&single_sender).unwrap()[0],
1356            4,
1357            "SingleSender = 4"
1358        );
1359    }
1360
1361    #[test]
1362    fn test_single_key_single_sender_bcs_wire_format() {
1363        // Pin the byte-for-byte wire layout of
1364        // `TransactionAuthenticator::SingleSender(AccountAuthenticator::SingleKey)`
1365        // so that a future regression in the hand-rolled Serialize impl is
1366        // caught at unit-test time (rather than at submission time on the
1367        // chain). The inner AnyPublicKey / AnySignature payloads must be
1368        // emitted *inline* after the variant tags -- no outer length prefixes.
1369        let mut pk = vec![0u8; 67];
1370        pk[0] = 0x02; // AnyPublicKey::Secp256r1Ecdsa variant
1371        pk[1] = 65; // ULEB128(65)
1372        pk[2] = 0x04; // SEC1 uncompressed marker
1373        let mut sig = vec![0u8; 66];
1374        sig[0] = 0x02; // AnySignature::WebAuthn variant
1375        sig[1] = 64; // ULEB128(64)
1376
1377        let auth = AccountAuthenticator::single_key(pk.clone(), sig.clone());
1378        let bytes = aptos_bcs::to_bytes(&auth).unwrap();
1379        let mut expected_inner = Vec::new();
1380        expected_inner.push(2u8); // AccountAuthenticator::SingleKey variant tag
1381        expected_inner.extend_from_slice(&pk); // AnyPublicKey inline (no length prefix)
1382        expected_inner.extend_from_slice(&sig); // AnySignature inline (no length prefix)
1383        assert_eq!(bytes, expected_inner);
1384
1385        let txn = TransactionAuthenticator::single_sender(auth);
1386        let bytes = aptos_bcs::to_bytes(&txn).unwrap();
1387        let mut expected_outer = Vec::new();
1388        expected_outer.push(4u8); // TransactionAuthenticator::SingleSender variant tag
1389        expected_outer.extend_from_slice(&expected_inner);
1390        assert_eq!(bytes, expected_outer);
1391    }
1392
1393    #[test]
1394    fn test_multi_key_authenticator_bcs_wire_format() {
1395        // Same logic as test_account_authenticator_single_key_bcs_wire_format, but for
1396        // MultiKey. The on-chain `AccountAuthenticator::MultiKey { authenticator: MultiKeyAuthenticator }`
1397        // BCS encoding is:
1398        //   * variant tag (ULEB128 of 3) -> 1 byte
1399        //   * BCS(MultiKeyPublicKey) || BCS(MultiKeySignature)
1400        // Each inner blob already carries its own structural framing.
1401        let pk = vec![0xaa; 100];
1402        let sig = vec![0xbb; 200];
1403        let auth = AccountAuthenticator::multi_key(pk.clone(), sig.clone());
1404
1405        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
1406        let mut expected = Vec::new();
1407        expected.push(3u8); // variant tag
1408        expected.extend_from_slice(&pk);
1409        expected.extend_from_slice(&sig);
1410        assert_eq!(
1411            serialized, expected,
1412            "MultiKey wire format must be variant tag + raw pubkey bytes + raw signature bytes"
1413        );
1414    }
1415
1416    #[test]
1417    fn test_multi_key_authenticator_bcs_rejects_keyless_public_key() {
1418        let mk_pk = MultiKeyPublicKey::new(
1419            vec![AnyPublicKey::new(
1420                crate::crypto::AnyPublicKeyVariant::Keyless,
1421                vec![],
1422            )],
1423            1,
1424        )
1425        .unwrap();
1426        let mk_sig = MultiKeySignature::new(vec![(
1427            0,
1428            AnySignature::new(crate::crypto::AnyPublicKeyVariant::Ed25519, vec![0x66; 64]),
1429        )])
1430        .unwrap();
1431        let auth = AccountAuthenticator::multi_key(mk_pk.to_bytes(), mk_sig.to_bytes());
1432
1433        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
1434        let result: Result<AccountAuthenticator, _> = aptos_bcs::from_bytes(&serialized);
1435        assert!(result.is_err());
1436    }
1437
1438    #[test]
1439    fn test_multi_ed25519_authenticator_bcs_roundtrip() {
1440        let auth = AccountAuthenticator::MultiEd25519 {
1441            public_key: vec![0xcc; 64],
1442            signature: vec![0xdd; 128],
1443        };
1444
1445        let serialized = aptos_bcs::to_bytes(&auth).unwrap();
1446        // MultiEd25519 should be variant index 1
1447        assert_eq!(serialized[0], 1, "MultiEd25519 variant index should be 1");
1448        let deserialized: AccountAuthenticator = aptos_bcs::from_bytes(&serialized).unwrap();
1449        assert_eq!(auth, deserialized);
1450    }
1451
1452    #[test]
1453    fn test_ed25519_public_key_deserialize_invalid_length() {
1454        // Serialize with wrong length (use 16 bytes instead of 32)
1455        let mut bytes = vec![16u8]; // Length prefix
1456        bytes.extend_from_slice(&[0xab; 16]); // Only 16 bytes
1457        let result: Result<Ed25519PublicKey, _> = aptos_bcs::from_bytes(&bytes);
1458        assert!(result.is_err());
1459    }
1460
1461    #[test]
1462    fn test_ed25519_signature_deserialize_invalid_length() {
1463        // Serialize with wrong length (use 32 bytes instead of 64)
1464        let mut bytes = vec![32u8]; // Length prefix
1465        bytes.extend_from_slice(&[0xab; 32]); // Only 32 bytes
1466        let result: Result<Ed25519Signature, _> = aptos_bcs::from_bytes(&bytes);
1467        assert!(result.is_err());
1468    }
1469}