Skip to main content

aptos_sdk/crypto/
multi_key.rs

1//! `MultiKey` signature scheme implementation.
2//!
3//! `MultiKey` enables M-of-N threshold signatures with mixed key types.
4//! Unlike `MultiEd25519`, each key can be a different signature scheme
5//! (Ed25519, Secp256k1, Secp256r1, etc.).
6
7use crate::error::{AptosError, AptosResult};
8use serde::{Deserialize, Serialize};
9use std::fmt;
10
11/// Maximum number of keys in a multi-key account.
12pub const MAX_NUM_OF_KEYS: usize = 32;
13
14// Compile-time assertion: MAX_NUM_OF_KEYS must fit in u8 for bitmap operations
15const _: () = assert!(MAX_NUM_OF_KEYS <= u8::MAX as usize);
16
17/// Minimum threshold (at least 1 signature required).
18pub const MIN_THRESHOLD: u8 = 1;
19
20/// Supported signature schemes for multi-key.
21#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
22#[repr(u8)]
23pub enum AnyPublicKeyVariant {
24    /// Ed25519 public key.
25    Ed25519 = 0,
26    /// Secp256k1 ECDSA public key.
27    Secp256k1 = 1,
28    /// Secp256r1 (P-256) ECDSA public key.
29    Secp256r1 = 2,
30    /// Keyless public key.
31    Keyless = 3,
32}
33
34impl AnyPublicKeyVariant {
35    /// Get the variant from a byte.
36    ///
37    /// # Errors
38    ///
39    /// Returns [`AptosError::InvalidPublicKey`] if the byte value is not a valid variant (0-3).
40    pub fn from_byte(byte: u8) -> AptosResult<Self> {
41        match byte {
42            0 => Ok(Self::Ed25519),
43            1 => Ok(Self::Secp256k1),
44            2 => Ok(Self::Secp256r1),
45            3 => Ok(Self::Keyless),
46            _ => Err(AptosError::InvalidPublicKey(format!(
47                "unknown public key variant: {byte}"
48            ))),
49        }
50    }
51
52    /// Get the byte representation.
53    pub fn as_byte(&self) -> u8 {
54        *self as u8
55    }
56}
57
58/// A public key that can be any supported signature scheme.
59#[derive(Clone, PartialEq, Eq)]
60pub struct AnyPublicKey {
61    /// The signature scheme variant.
62    pub variant: AnyPublicKeyVariant,
63    /// The raw public key bytes.
64    pub bytes: Vec<u8>,
65}
66
67impl AnyPublicKey {
68    /// Creates a new `AnyPublicKey`.
69    pub fn new(variant: AnyPublicKeyVariant, bytes: Vec<u8>) -> Self {
70        Self { variant, bytes }
71    }
72
73    /// Creates an Ed25519 public key.
74    #[cfg(feature = "ed25519")]
75    pub fn ed25519(public_key: &crate::crypto::Ed25519PublicKey) -> Self {
76        Self {
77            variant: AnyPublicKeyVariant::Ed25519,
78            bytes: public_key.to_bytes().to_vec(),
79        }
80    }
81
82    /// Creates a Secp256k1 public key.
83    /// Uses the 65-byte SEC1 uncompressed encoding so the chain's
84    /// `bcs::to_bytes(&AnyPublicKey::Secp256k1Ecdsa)` re-serialisation produces
85    /// the same bytes during auth-key derivation. The SDK and chain therefore
86    /// agree on the address.
87    #[cfg(feature = "secp256k1")]
88    pub fn secp256k1(public_key: &crate::crypto::Secp256k1PublicKey) -> Self {
89        Self {
90            variant: AnyPublicKeyVariant::Secp256k1,
91            bytes: public_key.to_uncompressed_bytes(),
92        }
93    }
94
95    /// Creates a Secp256r1 public key.
96    /// Uses 65-byte SEC1 uncompressed encoding (see `secp256k1` for rationale).
97    #[cfg(feature = "secp256r1")]
98    pub fn secp256r1(public_key: &crate::crypto::Secp256r1PublicKey) -> Self {
99        Self {
100            variant: AnyPublicKeyVariant::Secp256r1,
101            bytes: public_key.to_uncompressed_bytes(),
102        }
103    }
104
105    /// Serializes to BCS format: `variant_byte` || ULEB128(length) || bytes
106    ///
107    /// This is the correct BCS serialization format for `AnyPublicKey` used
108    /// in authentication key derivation: `SHA3-256(BCS(AnyPublicKey) || scheme_id)`
109    pub fn to_bcs_bytes(&self) -> Vec<u8> {
110        let mut result = Vec::with_capacity(1 + 1 + self.bytes.len());
111        result.push(self.variant.as_byte());
112        // BCS uses ULEB128 for vector lengths
113        result.extend(uleb128_encode(self.bytes.len()));
114        result.extend_from_slice(&self.bytes);
115        result
116    }
117
118    /// Parses BCS `AnyPublicKey` bytes (`variant` || `ULEB128(len)` || raw key bytes).
119    ///
120    /// # Errors
121    ///
122    /// Returns [`AptosError::InvalidPublicKey`] if the slice is empty, the variant byte is
123    /// unknown, the length prefix is malformed, the payload is truncated, or trailing bytes
124    /// remain after the declared key bytes.
125    pub fn from_bcs_bytes(bytes: &[u8]) -> AptosResult<Self> {
126        if bytes.is_empty() {
127            return Err(AptosError::InvalidPublicKey(
128                "AnyPublicKey BCS empty".into(),
129            ));
130        }
131        let variant = AnyPublicKeyVariant::from_byte(bytes[0])?;
132        let (len, len_bytes) = uleb128_decode(&bytes[1..]).ok_or_else(|| {
133            AptosError::InvalidPublicKey("AnyPublicKey BCS invalid length prefix".into())
134        })?;
135        let start = 1 + len_bytes;
136        let end = start.checked_add(len).ok_or_else(|| {
137            AptosError::InvalidPublicKey("AnyPublicKey BCS length overflow".into())
138        })?;
139        if end > bytes.len() {
140            return Err(AptosError::InvalidPublicKey(
141                "AnyPublicKey BCS truncated payload".into(),
142            ));
143        }
144        if end != bytes.len() {
145            return Err(AptosError::InvalidPublicKey(
146                "AnyPublicKey BCS trailing bytes".into(),
147            ));
148        }
149        Ok(Self::new(variant, bytes[start..end].to_vec()))
150    }
151
152    /// Verifies a signature against a message.
153    ///
154    /// # Errors
155    ///
156    /// This function will return an error if:
157    /// - The signature variant doesn't match the public key variant
158    /// - The public key bytes are invalid for the variant
159    /// - The signature bytes are invalid for the variant
160    /// - Signature verification fails
161    /// - Verification is not supported for the variant
162    #[allow(unused_variables)]
163    pub fn verify(&self, message: &[u8], signature: &AnySignature) -> AptosResult<()> {
164        if signature.variant != self.variant {
165            return Err(AptosError::InvalidSignature(format!(
166                "signature variant {:?} doesn't match public key variant {:?}",
167                signature.variant, self.variant
168            )));
169        }
170
171        match self.variant {
172            #[cfg(feature = "ed25519")]
173            AnyPublicKeyVariant::Ed25519 => {
174                let pk = crate::crypto::Ed25519PublicKey::from_bytes(&self.bytes)?;
175                let sig = crate::crypto::Ed25519Signature::from_bytes(&signature.bytes)?;
176                pk.verify(message, &sig)
177            }
178            #[cfg(feature = "secp256k1")]
179            AnyPublicKeyVariant::Secp256k1 => {
180                // Public key can be either compressed (33 bytes) or uncompressed (65 bytes)
181                let pk = crate::crypto::Secp256k1PublicKey::from_bytes(&self.bytes)?;
182                let sig = crate::crypto::Secp256k1Signature::from_bytes(&signature.bytes)?;
183                pk.verify(message, &sig)
184            }
185            #[cfg(feature = "secp256r1")]
186            AnyPublicKeyVariant::Secp256r1 => {
187                // Public key can be either compressed (33 bytes) or uncompressed (65 bytes)
188                let pk = crate::crypto::Secp256r1PublicKey::from_bytes(&self.bytes)?;
189                let sig = crate::crypto::Secp256r1Signature::from_bytes(&signature.bytes)?;
190                pk.verify(message, &sig)
191            }
192            #[allow(unreachable_patterns)]
193            _ => Err(AptosError::InvalidPublicKey(format!(
194                "verification not supported for variant {:?}",
195                self.variant
196            ))),
197        }
198    }
199}
200
201impl fmt::Debug for AnyPublicKey {
202    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203        write!(
204            f,
205            "AnyPublicKey({:?}, {})",
206            self.variant,
207            const_hex::encode_prefixed(&self.bytes)
208        )
209    }
210}
211
212impl fmt::Display for AnyPublicKey {
213    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214        write!(
215            f,
216            "{:?}:{}",
217            self.variant,
218            const_hex::encode_prefixed(&self.bytes)
219        )
220    }
221}
222
223/// A signature that can be any supported signature scheme.
224#[derive(Clone, PartialEq, Eq)]
225pub struct AnySignature {
226    /// The signature scheme variant.
227    pub variant: AnyPublicKeyVariant,
228    /// The raw signature bytes.
229    pub bytes: Vec<u8>,
230}
231
232impl AnySignature {
233    /// Creates a new `AnySignature`.
234    pub fn new(variant: AnyPublicKeyVariant, bytes: Vec<u8>) -> Self {
235        Self { variant, bytes }
236    }
237
238    /// Creates an Ed25519 signature.
239    #[cfg(feature = "ed25519")]
240    pub fn ed25519(signature: &crate::crypto::Ed25519Signature) -> Self {
241        Self {
242            variant: AnyPublicKeyVariant::Ed25519,
243            bytes: signature.to_bytes().to_vec(),
244        }
245    }
246
247    /// Creates a Secp256k1 signature.
248    #[cfg(feature = "secp256k1")]
249    pub fn secp256k1(signature: &crate::crypto::Secp256k1Signature) -> Self {
250        Self {
251            variant: AnyPublicKeyVariant::Secp256k1,
252            bytes: signature.to_bytes().to_vec(),
253        }
254    }
255
256    /// Creates a Secp256r1 signature.
257    #[cfg(feature = "secp256r1")]
258    pub fn secp256r1(signature: &crate::crypto::Secp256r1Signature) -> Self {
259        Self {
260            variant: AnyPublicKeyVariant::Secp256r1,
261            bytes: signature.to_bytes().to_vec(),
262        }
263    }
264
265    /// Serializes to BCS `AnySignature` bytes.
266    ///
267    /// Most variants use `variant_byte` || `ULEB128(len)` || `payload`.
268    ///
269    /// On Aptos, discriminant `2` is shared by bare `Secp256r1Ecdsa` signatures (64-byte
270    /// payload) and the `WebAuthn` variant, which embeds a `PartialAuthenticatorAssertionResponse`
271    /// struct **without** an outer `ULEB128` length prefix after the enum tag. When this struct
272    /// is present, the first payload byte is `0x00` (`AssertionSignature::Secp256r1Ecdsa`).
273    /// For that shape we serialize as `0x02 || payload` to match the chain and
274    /// [`crate::account::WebAuthnAccount`].
275    pub fn to_bcs_bytes(&self) -> Vec<u8> {
276        if self.variant == AnyPublicKeyVariant::Secp256r1 && self.bytes.len() != 64 {
277            let mut result = Vec::with_capacity(1 + self.bytes.len());
278            result.push(self.variant.as_byte());
279            result.extend_from_slice(&self.bytes);
280            return result;
281        }
282        let mut result = Vec::with_capacity(1 + 1 + self.bytes.len());
283        result.push(self.variant.as_byte());
284        // BCS uses ULEB128 for vector lengths
285        result.extend(uleb128_encode(self.bytes.len()));
286        result.extend_from_slice(&self.bytes);
287        result
288    }
289
290    /// Parses BCS `AnySignature` bytes from the wire.
291    ///
292    /// For variants other than `Secp256r1` (`2`), this expects
293    /// `variant` || `ULEB128(len)` || `payload`.
294    ///
295    /// For discriminant `2`, Aptos uses two layouts:
296    ///
297    /// - Bare ECDSA: `0x02` || `ULEB128(64)` || 64-byte signature. The length prefix always
298    ///   begins with `0x40` when `64` is encoded as a single ULEB128 byte.
299    /// - WebAuthn: `0x02` || BCS(`PartialAuthenticatorAssertionResponse`), which begins with
300    ///   `0x00` (`AssertionSignature::Secp256r1Ecdsa`) — **no** outer `ULEB128` wrapping the
301    ///   struct.
302    ///
303    /// # Errors
304    ///
305    /// Returns [`AptosError::InvalidSignature`] if the slice is empty, the variant byte is
306    /// unknown, the length prefix is malformed, the payload is truncated, or trailing bytes
307    /// remain after the declared signature bytes.
308    pub fn from_bcs_bytes(bytes: &[u8]) -> AptosResult<Self> {
309        if bytes.is_empty() {
310            return Err(AptosError::InvalidSignature(
311                "AnySignature BCS empty".into(),
312            ));
313        }
314        let variant = AnyPublicKeyVariant::from_byte(bytes[0]).map_err(|e| {
315            AptosError::InvalidSignature(format!("AnySignature BCS bad variant: {e}"))
316        })?;
317        if variant == AnyPublicKeyVariant::Secp256r1 && bytes.len() > 1 && bytes[1] == 0x00 {
318            return Ok(Self::new(variant, bytes[1..].to_vec()));
319        }
320        let (len, len_bytes) = uleb128_decode(&bytes[1..]).ok_or_else(|| {
321            AptosError::InvalidSignature("AnySignature BCS invalid length prefix".into())
322        })?;
323        let start = 1 + len_bytes;
324        let end = start.checked_add(len).ok_or_else(|| {
325            AptosError::InvalidSignature("AnySignature BCS length overflow".into())
326        })?;
327        if end > bytes.len() {
328            return Err(AptosError::InvalidSignature(
329                "AnySignature BCS truncated payload".into(),
330            ));
331        }
332        if end != bytes.len() {
333            return Err(AptosError::InvalidSignature(
334                "AnySignature BCS trailing bytes".into(),
335            ));
336        }
337        Ok(Self::new(variant, bytes[start..end].to_vec()))
338    }
339}
340
341/// Encodes a value as `ULEB128` (unsigned `LEB128`).
342/// BCS uses `ULEB128` for encoding vector/sequence lengths.
343/// For typical sizes (< 128), this returns a single byte.
344#[allow(clippy::cast_possible_truncation)] // value & 0x7F is always <= 127
345#[inline]
346pub(crate) fn uleb128_encode(mut value: usize) -> Vec<u8> {
347    // Pre-allocate for common case: values < 128 need 1 byte, < 16384 need 2 bytes
348    let mut result = Vec::with_capacity(if value < 128 { 1 } else { 2 });
349    loop {
350        let byte = (value & 0x7F) as u8;
351        value >>= 7;
352        if value == 0 {
353            result.push(byte);
354            break;
355        }
356        result.push(byte | 0x80);
357    }
358    result
359}
360
361/// Decodes a `ULEB128` value from bytes, returning `(value, bytes_consumed)`.
362fn uleb128_decode(bytes: &[u8]) -> Option<(usize, usize)> {
363    let mut result: usize = 0;
364    let mut shift = 0;
365    for (i, &byte) in bytes.iter().enumerate() {
366        result |= ((byte & 0x7F) as usize) << shift;
367        if byte & 0x80 == 0 {
368            return Some((result, i + 1));
369        }
370        shift += 7;
371        if shift >= 64 {
372            return None; // Overflow
373        }
374    }
375    None
376}
377
378impl fmt::Debug for AnySignature {
379    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380        write!(
381            f,
382            "AnySignature({:?}, {} bytes)",
383            self.variant,
384            self.bytes.len()
385        )
386    }
387}
388
389/// A multi-key public key supporting mixed signature schemes.
390///
391/// This allows M-of-N threshold signing where each key can be a different type.
392#[derive(Clone, PartialEq, Eq)]
393pub struct MultiKeyPublicKey {
394    /// The individual public keys.
395    public_keys: Vec<AnyPublicKey>,
396    /// The required threshold (M in M-of-N).
397    threshold: u8,
398}
399
400impl MultiKeyPublicKey {
401    /// Creates a new multi-key public key.
402    ///
403    /// # Arguments
404    ///
405    /// * `public_keys` - The individual public keys (can be mixed types)
406    /// * `threshold` - The number of signatures required (M in M-of-N)
407    ///
408    /// # Errors
409    ///
410    /// Returns [`AptosError::InvalidPublicKey`] if:
411    /// - No public keys are provided
412    /// - More than 32 public keys are provided
413    /// - Threshold is 0
414    /// - Threshold exceeds the number of keys
415    pub fn new(public_keys: Vec<AnyPublicKey>, threshold: u8) -> AptosResult<Self> {
416        if public_keys.is_empty() {
417            return Err(AptosError::InvalidPublicKey(
418                "multi-key requires at least one public key".into(),
419            ));
420        }
421        if public_keys.len() > MAX_NUM_OF_KEYS {
422            return Err(AptosError::InvalidPublicKey(format!(
423                "multi-key supports at most {} keys, got {}",
424                MAX_NUM_OF_KEYS,
425                public_keys.len()
426            )));
427        }
428        if threshold < MIN_THRESHOLD {
429            return Err(AptosError::InvalidPublicKey(
430                "threshold must be at least 1".into(),
431            ));
432        }
433        if threshold as usize > public_keys.len() {
434            return Err(AptosError::InvalidPublicKey(format!(
435                "threshold {} exceeds number of keys {}",
436                threshold,
437                public_keys.len()
438            )));
439        }
440        Ok(Self {
441            public_keys,
442            threshold,
443        })
444    }
445
446    /// Returns the number of public keys.
447    pub fn num_keys(&self) -> usize {
448        self.public_keys.len()
449    }
450
451    /// Returns the threshold.
452    pub fn threshold(&self) -> u8 {
453        self.threshold
454    }
455
456    /// Returns the individual public keys.
457    pub fn public_keys(&self) -> &[AnyPublicKey] {
458        &self.public_keys
459    }
460
461    /// Returns the key at the given index.
462    pub fn get(&self, index: usize) -> Option<&AnyPublicKey> {
463        self.public_keys.get(index)
464    }
465
466    /// Serializes to bytes for authentication key derivation.
467    ///
468    /// Format: `num_keys` || `pk1_bcs` || `pk2_bcs` || ... || threshold
469    #[allow(clippy::cast_possible_truncation)] // public_keys.len() <= MAX_NUM_OF_KEYS (32)
470    pub fn to_bytes(&self) -> Vec<u8> {
471        // Pre-allocate: 1 byte num_keys + estimated key size (avg ~35 bytes per key) + 1 byte threshold
472        let estimated_size = 2 + self.public_keys.len() * 36;
473        let mut bytes = Vec::with_capacity(estimated_size);
474
475        // Number of keys (1 byte, validated in new())
476        bytes.push(self.public_keys.len() as u8);
477
478        // Each public key in BCS format
479        for pk in &self.public_keys {
480            bytes.extend(pk.to_bcs_bytes());
481        }
482
483        // Threshold (1 byte)
484        bytes.push(self.threshold);
485
486        bytes
487    }
488
489    /// Creates from bytes.
490    ///
491    /// # Errors
492    ///
493    /// Returns [`AptosError::InvalidPublicKey`] if:
494    /// - The bytes are empty
495    /// - The number of keys is invalid (0 or > 32)
496    /// - The bytes are too short for the expected structure
497    /// - Any public key variant byte is invalid
498    /// - Any public key length or data is invalid
499    /// - The threshold is invalid
500    pub fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
501        // SECURITY: Limit individual key size to prevent DoS via large allocations
502        // Largest supported key is uncompressed secp256k1/secp256r1 at 65 bytes
503        const MAX_KEY_SIZE: usize = 128;
504
505        if bytes.is_empty() {
506            return Err(AptosError::InvalidPublicKey("empty bytes".into()));
507        }
508
509        let num_keys = bytes[0] as usize;
510        if num_keys == 0 || num_keys > MAX_NUM_OF_KEYS {
511            return Err(AptosError::InvalidPublicKey(format!(
512                "invalid number of keys: {num_keys}"
513            )));
514        }
515
516        let mut offset = 1;
517        let mut public_keys = Vec::with_capacity(num_keys);
518
519        for _ in 0..num_keys {
520            if offset >= bytes.len() {
521                return Err(AptosError::InvalidPublicKey("bytes too short".into()));
522            }
523
524            let variant = AnyPublicKeyVariant::from_byte(bytes[offset])?;
525            offset += 1;
526
527            // Decode ULEB128 length
528            let (len, len_bytes) = uleb128_decode(&bytes[offset..]).ok_or_else(|| {
529                AptosError::InvalidPublicKey("invalid ULEB128 length encoding".into())
530            })?;
531            offset += len_bytes;
532
533            if len > MAX_KEY_SIZE {
534                return Err(AptosError::InvalidPublicKey(format!(
535                    "key size {len} exceeds maximum {MAX_KEY_SIZE}"
536                )));
537            }
538
539            if offset + len > bytes.len() {
540                return Err(AptosError::InvalidPublicKey(
541                    "bytes too short for key".into(),
542                ));
543            }
544
545            let key_bytes = bytes[offset..offset + len].to_vec();
546            offset += len;
547
548            public_keys.push(AnyPublicKey::new(variant, key_bytes));
549        }
550
551        if offset >= bytes.len() {
552            return Err(AptosError::InvalidPublicKey(
553                "bytes too short for threshold".into(),
554            ));
555        }
556
557        let threshold = bytes[offset];
558
559        Self::new(public_keys, threshold)
560    }
561
562    /// Derives the account address for this multi-key public key.
563    pub fn to_address(&self) -> crate::types::AccountAddress {
564        crate::crypto::derive_address(&self.to_bytes(), crate::crypto::MULTI_KEY_SCHEME)
565    }
566
567    /// Derives the authentication key for this public key.
568    pub fn to_authentication_key(&self) -> [u8; 32] {
569        crate::crypto::derive_authentication_key(&self.to_bytes(), crate::crypto::MULTI_KEY_SCHEME)
570    }
571
572    /// Verifies a multi-key signature against a message.
573    ///
574    /// # Errors
575    ///
576    /// This function will return an error if:
577    /// - The number of signatures is less than the threshold
578    /// - Any individual signature verification fails
579    /// - A signer index is out of bounds
580    pub fn verify(&self, message: &[u8], signature: &MultiKeySignature) -> AptosResult<()> {
581        // Check that we have enough signatures
582        if signature.num_signatures() < self.threshold as usize {
583            return Err(AptosError::SignatureVerificationFailed);
584        }
585
586        // Verify each signature
587        for (index, sig) in signature.signatures() {
588            if *index as usize >= self.public_keys.len() {
589                return Err(AptosError::InvalidSignature(format!(
590                    "signer index {} out of bounds (max {})",
591                    index,
592                    self.public_keys.len() - 1
593                )));
594            }
595            let pk = &self.public_keys[*index as usize];
596            pk.verify(message, sig)?;
597        }
598
599        Ok(())
600    }
601}
602
603impl fmt::Debug for MultiKeyPublicKey {
604    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
605        write!(
606            f,
607            "MultiKeyPublicKey({}-of-{} keys)",
608            self.threshold,
609            self.public_keys.len()
610        )
611    }
612}
613
614impl fmt::Display for MultiKeyPublicKey {
615    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
616        f.write_str(&const_hex::encode_prefixed(self.to_bytes()))
617    }
618}
619
620/// A multi-key signature containing signatures from multiple signers.
621#[derive(Clone, PartialEq, Eq)]
622pub struct MultiKeySignature {
623    /// Individual signatures with their signer index.
624    signatures: Vec<(u8, AnySignature)>,
625    /// Bitmap indicating which keys signed (up to 4 bytes for 32 keys). Bits are
626    /// set MSB-first within each byte (big-endian bit order): signer index 0 is
627    /// bit 7 of byte 0, index 7 is bit 0 of byte 0, and so on. This matches
628    /// aptos-core's `aptos_bitvec::BitVec` (`0b1000_0000 >> pos`); see `new`.
629    bitmap: [u8; 4],
630}
631
632impl MultiKeySignature {
633    /// Creates a new multi-key signature from individual signatures.
634    ///
635    /// # Arguments
636    ///
637    /// * `signatures` - Vec of (`signer_index`, signature) pairs
638    ///
639    /// # Errors
640    ///
641    /// Returns [`AptosError::InvalidSignature`] if:
642    /// - No signatures are provided
643    /// - More than 32 signatures are provided
644    /// - A signer index is out of bounds (>= 32)
645    /// - Duplicate signer indices are present
646    pub fn new(mut signatures: Vec<(u8, AnySignature)>) -> AptosResult<Self> {
647        if signatures.is_empty() {
648            return Err(AptosError::InvalidSignature(
649                "multi-key signature requires at least one signature".into(),
650            ));
651        }
652        if signatures.len() > MAX_NUM_OF_KEYS {
653            return Err(AptosError::InvalidSignature(format!(
654                "too many signatures: {} (max {})",
655                signatures.len(),
656                MAX_NUM_OF_KEYS
657            )));
658        }
659
660        // Sort by index
661        signatures.sort_by_key(|(idx, _)| *idx);
662
663        // Check for duplicates and bounds, build bitmap
664        let mut bitmap = [0u8; 4];
665        let mut last_index: Option<u8> = None;
666
667        for (index, _) in &signatures {
668            if *index as usize >= MAX_NUM_OF_KEYS {
669                return Err(AptosError::InvalidSignature(format!(
670                    "signer index {} out of bounds (max {})",
671                    index,
672                    MAX_NUM_OF_KEYS - 1
673                )));
674            }
675            if last_index == Some(*index) {
676                return Err(AptosError::InvalidSignature(format!(
677                    "duplicate signer index {index}"
678                )));
679            }
680            last_index = Some(*index);
681
682            // Set bit in bitmap
683            // Aptos uses MSB-first ordering within each bitmap byte
684            // (matches `aptos_bitvec::BitVec::set`: `0b1000_0000 >> pos`).
685            // index 0 -> bit 7 of byte 0, index 7 -> bit 0 of byte 0, etc.
686            let byte_index = (index / 8) as usize;
687            let bit_in_byte = index % 8;
688            bitmap[byte_index] |= 0b1000_0000u8 >> bit_in_byte;
689        }
690
691        Ok(Self { signatures, bitmap })
692    }
693
694    /// Returns the number of signatures.
695    pub fn num_signatures(&self) -> usize {
696        self.signatures.len()
697    }
698
699    /// Returns the individual signatures with their indices.
700    pub fn signatures(&self) -> &[(u8, AnySignature)] {
701        &self.signatures
702    }
703
704    /// Returns the signer bitmap.
705    pub fn bitmap(&self) -> &[u8; 4] {
706        &self.bitmap
707    }
708
709    /// Checks if a particular index signed.
710    pub fn has_signature(&self, index: u8) -> bool {
711        if index as usize >= MAX_NUM_OF_KEYS {
712            return false;
713        }
714        let byte_index = (index / 8) as usize;
715        let bit_in_byte = index % 8;
716        (self.bitmap[byte_index] & (0b1000_0000u8 >> bit_in_byte)) != 0
717    }
718
719    /// Serializes to bytes, matching the on-chain BCS layout of
720    /// `MultiKeyAuthenticator { signatures: Vec<AnySignature>, signatures_bitmap: BitVec }`.
721    ///
722    /// Wire layout: `ULEB128(num_sigs) || BCS(AnySignature)... || BCS(BitVec)`
723    /// where `BCS(BitVec) = ULEB128(num_bitmap_bytes) || bitmap_bytes`.
724    #[allow(clippy::cast_possible_truncation)] // signatures.len() <= MAX_NUM_OF_KEYS (32)
725    pub fn to_bytes(&self) -> Vec<u8> {
726        // Pre-allocate: 1 byte num_sigs + estimated sig size (~68 bytes per sig)
727        // + 1 byte bitmap length prefix + 4 bytes bitmap.
728        let estimated_size = 1 + self.signatures.len() * 68 + 1 + 4;
729        let mut bytes = Vec::with_capacity(estimated_size);
730
731        // ULEB128(num_signatures). num_sigs <= 32 fits in a single byte.
732        bytes.push(self.signatures.len() as u8);
733
734        // Each AnySignature in BCS format (ordered by signer index).
735        for (_, sig) in &self.signatures {
736            bytes.extend(sig.to_bcs_bytes());
737        }
738
739        // BitVec BCS prefix: ULEB128(4).
740        bytes.push(4);
741        // Bitmap bytes.
742        bytes.extend_from_slice(&self.bitmap);
743
744        bytes
745    }
746
747    /// Creates from bytes.
748    ///
749    /// # Errors
750    ///
751    /// Returns [`AptosError::InvalidSignature`] if:
752    /// - The bytes are too short (fewer than 6 bytes: 1 `num_sigs` byte + a
753    ///   1-byte `BitVec` ULEB128 length prefix + 4 bitmap bytes)
754    /// - The number of signatures is invalid (0 or > 32)
755    /// - The bitmap doesn't match the number of signatures
756    /// - The bytes are too short for the expected structure
757    /// - Any signature variant byte is invalid
758    /// - Any signature length or data is invalid
759    pub fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
760        // SECURITY: Limit individual signature size to prevent DoS via large allocations
761        // Largest supported signature is ~72 bytes for ECDSA DER format
762        const MAX_SIGNATURE_SIZE: usize = 128;
763
764        // Wire layout (matches `to_bytes`):
765        //   ULEB128(num_sigs) || sigs... || ULEB128(4) || 4 bitmap bytes
766        // Minimum length is 1 (num_sigs) + 1 (BitVec length prefix) + 4 (bitmap) = 6.
767        if bytes.len() < 6 {
768            return Err(AptosError::InvalidSignature("bytes too short".into()));
769        }
770
771        let num_sigs = bytes[0] as usize;
772        if num_sigs == 0 || num_sigs > MAX_NUM_OF_KEYS {
773            return Err(AptosError::InvalidSignature(format!(
774                "invalid number of signatures: {num_sigs}"
775            )));
776        }
777
778        // Read bitmap from the end. Last 4 bytes are the bitmap bytes; the byte
779        // just before is the ULEB128(4) length prefix from BCS(BitVec).
780        let bitmap_start = bytes.len() - 4;
781        let mut bitmap = [0u8; 4];
782        bitmap.copy_from_slice(&bytes[bitmap_start..]);
783        let bitvec_prefix_idx = bitmap_start.checked_sub(1).ok_or_else(|| {
784            AptosError::InvalidSignature("MultiKeySignature too short for BitVec prefix".into())
785        })?;
786        if bytes[bitvec_prefix_idx] != 4 {
787            return Err(AptosError::InvalidSignature(
788                "MultiKeySignature: expected BCS BitVec length prefix = 4".into(),
789            ));
790        }
791
792        // Parse signatures
793        let mut offset = 1;
794        let mut signatures = Vec::with_capacity(num_sigs);
795
796        // MSB-first bit order (matches aptos-core's `aptos_bitvec::BitVec`).
797        let mut signer_indices = Vec::new();
798        #[allow(clippy::cast_possible_truncation)]
799        for bit_pos in 0..(MAX_NUM_OF_KEYS as u8) {
800            let byte_idx = (bit_pos / 8) as usize;
801            let bit_in_byte = bit_pos % 8;
802            if (bitmap[byte_idx] & (0b1000_0000u8 >> bit_in_byte)) != 0 {
803                signer_indices.push(bit_pos);
804            }
805        }
806
807        if signer_indices.len() != num_sigs {
808            return Err(AptosError::InvalidSignature(
809                "bitmap doesn't match number of signatures".into(),
810            ));
811        }
812
813        // Signatures occupy the range `[1, bitvec_prefix_idx)` -- everything
814        // between the leading num_sigs byte and the BCS BitVec length prefix.
815        let sigs_end = bitvec_prefix_idx;
816        for &index in &signer_indices {
817            if offset >= sigs_end {
818                return Err(AptosError::InvalidSignature("bytes too short".into()));
819            }
820
821            let variant = AnyPublicKeyVariant::from_byte(bytes[offset])?;
822            offset += 1;
823
824            // Decode ULEB128 length
825            let (len, len_bytes) = uleb128_decode(&bytes[offset..sigs_end]).ok_or_else(|| {
826                AptosError::InvalidSignature("invalid ULEB128 length encoding".into())
827            })?;
828            offset += len_bytes;
829
830            if len > MAX_SIGNATURE_SIZE {
831                return Err(AptosError::InvalidSignature(format!(
832                    "signature size {len} exceeds maximum {MAX_SIGNATURE_SIZE}"
833                )));
834            }
835
836            if offset + len > sigs_end {
837                return Err(AptosError::InvalidSignature(
838                    "bytes too short for signature".into(),
839                ));
840            }
841
842            let sig_bytes = bytes[offset..offset + len].to_vec();
843            offset += len;
844
845            signatures.push((index, AnySignature::new(variant, sig_bytes)));
846        }
847
848        Ok(Self { signatures, bitmap })
849    }
850}
851
852impl fmt::Debug for MultiKeySignature {
853    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
854        write!(
855            f,
856            "MultiKeySignature({} signatures, bitmap={:?})",
857            self.signatures.len(),
858            self.bitmap
859        )
860    }
861}
862
863impl fmt::Display for MultiKeySignature {
864    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
865        f.write_str(&const_hex::encode_prefixed(self.to_bytes()))
866    }
867}
868
869#[cfg(test)]
870mod tests {
871    use super::*;
872
873    #[test]
874    fn test_any_public_key_variant_from_byte() {
875        assert_eq!(
876            AnyPublicKeyVariant::from_byte(0).unwrap(),
877            AnyPublicKeyVariant::Ed25519
878        );
879        assert_eq!(
880            AnyPublicKeyVariant::from_byte(1).unwrap(),
881            AnyPublicKeyVariant::Secp256k1
882        );
883        assert_eq!(
884            AnyPublicKeyVariant::from_byte(2).unwrap(),
885            AnyPublicKeyVariant::Secp256r1
886        );
887        assert_eq!(
888            AnyPublicKeyVariant::from_byte(3).unwrap(),
889            AnyPublicKeyVariant::Keyless
890        );
891        assert!(AnyPublicKeyVariant::from_byte(4).is_err());
892        assert!(AnyPublicKeyVariant::from_byte(255).is_err());
893    }
894
895    #[test]
896    fn test_any_public_key_variant_as_byte() {
897        assert_eq!(AnyPublicKeyVariant::Ed25519.as_byte(), 0);
898        assert_eq!(AnyPublicKeyVariant::Secp256k1.as_byte(), 1);
899        assert_eq!(AnyPublicKeyVariant::Secp256r1.as_byte(), 2);
900        assert_eq!(AnyPublicKeyVariant::Keyless.as_byte(), 3);
901    }
902
903    #[test]
904    fn test_any_public_key_new() {
905        let pk = AnyPublicKey::new(AnyPublicKeyVariant::Ed25519, vec![0x11; 32]);
906        assert_eq!(pk.variant, AnyPublicKeyVariant::Ed25519);
907        assert_eq!(pk.bytes.len(), 32);
908        assert_eq!(pk.bytes[0], 0x11);
909    }
910
911    #[test]
912    fn test_any_public_key_to_bcs_bytes() {
913        let pk = AnyPublicKey::new(AnyPublicKeyVariant::Ed25519, vec![0xaa; 32]);
914        let bcs = pk.to_bcs_bytes();
915
916        // Format: variant_byte || ULEB128(length) || bytes
917        assert_eq!(bcs[0], 0); // Ed25519 variant
918        assert_eq!(bcs[1], 32); // ULEB128(32) = 0x20 (since 32 < 128)
919        assert_eq!(bcs[2], 0xaa); // first byte of key
920        assert_eq!(bcs.len(), 1 + 1 + 32); // variant + length + bytes
921    }
922
923    #[test]
924    fn test_any_public_key_debug() {
925        let pk = AnyPublicKey::new(AnyPublicKeyVariant::Secp256k1, vec![0xbb; 33]);
926        let debug = format!("{pk:?}");
927        assert!(debug.contains("Secp256k1"));
928        assert!(debug.contains("0x"));
929    }
930
931    #[test]
932    fn test_any_signature_new() {
933        let sig = AnySignature::new(AnyPublicKeyVariant::Ed25519, vec![0xcc; 64]);
934        assert_eq!(sig.variant, AnyPublicKeyVariant::Ed25519);
935        assert_eq!(sig.bytes.len(), 64);
936    }
937
938    #[test]
939    fn test_any_signature_to_bcs_bytes() {
940        let sig = AnySignature::new(AnyPublicKeyVariant::Ed25519, vec![0xdd; 64]);
941        let bcs = sig.to_bcs_bytes();
942
943        // Format: variant_byte || ULEB128(length) || bytes
944        assert_eq!(bcs[0], 0); // Ed25519 variant
945        assert_eq!(bcs[1], 64); // ULEB128(64) = 0x40 (since 64 < 128)
946        assert_eq!(bcs[2], 0xdd); // first byte of signature
947        assert_eq!(bcs.len(), 1 + 1 + 64); // variant + length + bytes
948    }
949
950    #[test]
951    fn test_any_signature_secp256r1_bare_bcs_roundtrip() {
952        let inner = vec![0x42u8; 64];
953        let mut wire = vec![0x02, 0x40];
954        wire.extend_from_slice(&inner);
955        let sig = AnySignature::from_bcs_bytes(&wire).expect("parse bare Secp256r1");
956        assert_eq!(sig.variant, AnyPublicKeyVariant::Secp256r1);
957        assert_eq!(sig.bytes, inner);
958        assert_eq!(sig.to_bcs_bytes(), wire);
959    }
960
961    #[test]
962    fn test_any_signature_webauthn_style_bcs_roundtrip() {
963        // Synthetic PAAR-shaped payload: starts with AssertionSignature::Secp256r1Ecdsa (0x00)
964        // and is not exactly 64 bytes so `to_bcs_bytes` uses WebAuthn framing.
965        let mut paar = vec![0x00u8, 0x40];
966        paar.extend(vec![0x11u8; 64]);
967        let mut wire = vec![0x02];
968        wire.extend_from_slice(&paar);
969        let sig = AnySignature::from_bcs_bytes(&wire).expect("parse WebAuthn-style");
970        assert_eq!(sig.variant, AnyPublicKeyVariant::Secp256r1);
971        assert_eq!(sig.bytes, paar);
972        assert_eq!(sig.to_bcs_bytes(), wire);
973    }
974
975    #[test]
976    fn test_any_signature_debug() {
977        let sig = AnySignature::new(AnyPublicKeyVariant::Secp256r1, vec![0xee; 64]);
978        let debug = format!("{sig:?}");
979        assert!(debug.contains("Secp256r1"));
980        assert!(debug.contains("64 bytes"));
981    }
982
983    #[test]
984    fn test_any_public_key_verify_mismatched_variant() {
985        let pk = AnyPublicKey::new(AnyPublicKeyVariant::Ed25519, vec![0; 32]);
986        let sig = AnySignature::new(AnyPublicKeyVariant::Secp256k1, vec![0; 64]);
987
988        let result = pk.verify(b"message", &sig);
989        assert!(result.is_err());
990        assert!(result.unwrap_err().to_string().contains("variant"));
991    }
992
993    #[test]
994    fn test_multi_key_signature_insufficient_sigs() {
995        // Empty signatures should fail
996        let result = MultiKeySignature::new(vec![]);
997        assert!(result.is_err());
998    }
999
1000    #[test]
1001    fn test_multi_key_signature_duplicate_indices() {
1002        let sig1 = AnySignature::new(AnyPublicKeyVariant::Ed25519, vec![0; 64]);
1003        let sig2 = AnySignature::new(AnyPublicKeyVariant::Ed25519, vec![1; 64]);
1004
1005        // Duplicate index should fail
1006        let result = MultiKeySignature::new(vec![(0, sig1.clone()), (0, sig2)]);
1007        assert!(result.is_err());
1008    }
1009
1010    #[test]
1011    fn test_multi_key_signature_index_out_of_range() {
1012        let sig = AnySignature::new(AnyPublicKeyVariant::Ed25519, vec![0; 64]);
1013
1014        // Index 32 is out of range (0-31)
1015        let result = MultiKeySignature::new(vec![(32, sig)]);
1016        assert!(result.is_err());
1017    }
1018
1019    #[test]
1020    fn test_multi_key_signature_basic() {
1021        let sig1 = AnySignature::new(AnyPublicKeyVariant::Ed25519, vec![0xaa; 64]);
1022        let sig2 = AnySignature::new(AnyPublicKeyVariant::Ed25519, vec![0xbb; 64]);
1023
1024        let multi_sig = MultiKeySignature::new(vec![(0, sig1), (5, sig2)]).unwrap();
1025
1026        assert_eq!(multi_sig.num_signatures(), 2);
1027        assert!(multi_sig.has_signature(0));
1028        assert!(!multi_sig.has_signature(1));
1029        assert!(multi_sig.has_signature(5));
1030    }
1031
1032    #[test]
1033    fn test_multi_key_signature_debug_display() {
1034        let sig = AnySignature::new(AnyPublicKeyVariant::Ed25519, vec![0; 64]);
1035        let multi_sig = MultiKeySignature::new(vec![(0, sig)]).unwrap();
1036
1037        let debug = format!("{multi_sig:?}");
1038        let display = format!("{multi_sig}");
1039
1040        assert!(debug.contains("MultiKeySignature"));
1041        assert!(display.starts_with("0x"));
1042    }
1043
1044    #[test]
1045    #[cfg(feature = "ed25519")]
1046    fn test_multi_key_public_key_creation() {
1047        use crate::crypto::Ed25519PrivateKey;
1048
1049        let keys: Vec<_> = (0..3)
1050            .map(|_| AnyPublicKey::ed25519(&Ed25519PrivateKey::generate().public_key()))
1051            .collect();
1052
1053        // Valid 2-of-3
1054        let multi_pk = MultiKeyPublicKey::new(keys.clone(), 2).unwrap();
1055        assert_eq!(multi_pk.num_keys(), 3);
1056        assert_eq!(multi_pk.threshold(), 2);
1057
1058        // Invalid: threshold > num_keys
1059        assert!(MultiKeyPublicKey::new(keys.clone(), 4).is_err());
1060
1061        // Invalid: threshold = 0
1062        assert!(MultiKeyPublicKey::new(keys.clone(), 0).is_err());
1063
1064        // Invalid: empty keys
1065        assert!(MultiKeyPublicKey::new(vec![], 1).is_err());
1066    }
1067
1068    #[test]
1069    #[cfg(all(feature = "ed25519", feature = "secp256k1"))]
1070    fn test_multi_key_mixed_types() {
1071        use crate::crypto::{Ed25519PrivateKey, Secp256k1PrivateKey};
1072
1073        // Create mixed key types
1074        let ed_key = AnyPublicKey::ed25519(&Ed25519PrivateKey::generate().public_key());
1075        let secp_key = AnyPublicKey::secp256k1(&Secp256k1PrivateKey::generate().public_key());
1076
1077        let multi_pk = MultiKeyPublicKey::new(vec![ed_key, secp_key], 2).unwrap();
1078        assert_eq!(multi_pk.num_keys(), 2);
1079        assert_eq!(
1080            multi_pk.get(0).unwrap().variant,
1081            AnyPublicKeyVariant::Ed25519
1082        );
1083        assert_eq!(
1084            multi_pk.get(1).unwrap().variant,
1085            AnyPublicKeyVariant::Secp256k1
1086        );
1087    }
1088
1089    #[test]
1090    #[cfg(feature = "ed25519")]
1091    fn test_multi_key_sign_verify() {
1092        use crate::crypto::Ed25519PrivateKey;
1093
1094        let private_keys: Vec<_> = (0..3).map(|_| Ed25519PrivateKey::generate()).collect();
1095        let public_keys: Vec<_> = private_keys
1096            .iter()
1097            .map(|k| AnyPublicKey::ed25519(&k.public_key()))
1098            .collect();
1099
1100        let multi_pk = MultiKeyPublicKey::new(public_keys, 2).unwrap();
1101        let message = b"test message";
1102
1103        // Sign with keys 0 and 2 (2-of-3)
1104        let sig0 = AnySignature::ed25519(&private_keys[0].sign(message));
1105        let sig2 = AnySignature::ed25519(&private_keys[2].sign(message));
1106
1107        let multi_sig = MultiKeySignature::new(vec![(0, sig0), (2, sig2)]).unwrap();
1108
1109        // Verify should succeed
1110        assert!(multi_pk.verify(message, &multi_sig).is_ok());
1111
1112        // Wrong message should fail
1113        assert!(multi_pk.verify(b"wrong message", &multi_sig).is_err());
1114    }
1115
1116    #[test]
1117    #[cfg(feature = "ed25519")]
1118    fn test_multi_key_bytes_roundtrip() {
1119        use crate::crypto::Ed25519PrivateKey;
1120
1121        let keys: Vec<_> = (0..3)
1122            .map(|_| AnyPublicKey::ed25519(&Ed25519PrivateKey::generate().public_key()))
1123            .collect();
1124        let multi_pk = MultiKeyPublicKey::new(keys, 2).unwrap();
1125
1126        let bytes = multi_pk.to_bytes();
1127        let restored = MultiKeyPublicKey::from_bytes(&bytes).unwrap();
1128
1129        assert_eq!(multi_pk.threshold(), restored.threshold());
1130        assert_eq!(multi_pk.num_keys(), restored.num_keys());
1131    }
1132
1133    #[test]
1134    #[cfg(feature = "ed25519")]
1135    fn test_multi_key_signature_bytes_roundtrip() {
1136        use crate::crypto::Ed25519PrivateKey;
1137
1138        let private_keys: Vec<_> = (0..3).map(|_| Ed25519PrivateKey::generate()).collect();
1139        let message = b"test";
1140
1141        let sig0 = AnySignature::ed25519(&private_keys[0].sign(message));
1142        let sig2 = AnySignature::ed25519(&private_keys[2].sign(message));
1143
1144        let multi_sig = MultiKeySignature::new(vec![(0, sig0), (2, sig2)]).unwrap();
1145
1146        let bytes = multi_sig.to_bytes();
1147        let restored = MultiKeySignature::from_bytes(&bytes).unwrap();
1148
1149        assert_eq!(multi_sig.num_signatures(), restored.num_signatures());
1150        assert_eq!(multi_sig.bitmap(), restored.bitmap());
1151    }
1152
1153    #[test]
1154    #[cfg(feature = "ed25519")]
1155    fn test_signature_bitmap() {
1156        use crate::crypto::Ed25519PrivateKey;
1157
1158        let private_keys: Vec<_> = (0..5).map(|_| Ed25519PrivateKey::generate()).collect();
1159        let message = b"test";
1160
1161        // Sign with indices 1, 3, 4
1162        let signatures: Vec<_> = [1, 3, 4]
1163            .iter()
1164            .map(|&i| {
1165                (
1166                    i,
1167                    AnySignature::ed25519(&private_keys[i as usize].sign(message)),
1168                )
1169            })
1170            .collect();
1171
1172        let multi_sig = MultiKeySignature::new(signatures).unwrap();
1173
1174        assert!(!multi_sig.has_signature(0));
1175        assert!(multi_sig.has_signature(1));
1176        assert!(!multi_sig.has_signature(2));
1177        assert!(multi_sig.has_signature(3));
1178        assert!(multi_sig.has_signature(4));
1179        assert!(!multi_sig.has_signature(5));
1180    }
1181
1182    #[test]
1183    fn test_multi_key_public_key_empty_keys() {
1184        let result = MultiKeyPublicKey::new(vec![], 1);
1185        assert!(result.is_err());
1186        assert!(result.unwrap_err().to_string().contains("at least one"));
1187    }
1188
1189    #[test]
1190    #[cfg(feature = "ed25519")]
1191    fn test_multi_key_public_key_threshold_zero() {
1192        use crate::crypto::Ed25519PrivateKey;
1193
1194        let keys: Vec<_> = (0..2)
1195            .map(|_| AnyPublicKey::ed25519(&Ed25519PrivateKey::generate().public_key()))
1196            .collect();
1197        let result = MultiKeyPublicKey::new(keys, 0);
1198        assert!(result.is_err());
1199        assert!(result.unwrap_err().to_string().contains("at least 1"));
1200    }
1201
1202    #[test]
1203    #[cfg(feature = "ed25519")]
1204    fn test_multi_key_public_key_threshold_exceeds() {
1205        use crate::crypto::Ed25519PrivateKey;
1206
1207        let keys: Vec<_> = (0..2)
1208            .map(|_| AnyPublicKey::ed25519(&Ed25519PrivateKey::generate().public_key()))
1209            .collect();
1210        let result = MultiKeyPublicKey::new(keys, 5);
1211        assert!(result.is_err());
1212        assert!(result.unwrap_err().to_string().contains("exceed"));
1213    }
1214
1215    #[test]
1216    #[cfg(feature = "ed25519")]
1217    fn test_multi_key_signature_empty() {
1218        let result = MultiKeySignature::new(vec![]);
1219        assert!(result.is_err());
1220        assert!(result.unwrap_err().to_string().contains("at least one"));
1221    }
1222
1223    #[test]
1224    #[cfg(feature = "ed25519")]
1225    fn test_multi_key_signature_duplicate_index() {
1226        use crate::crypto::Ed25519PrivateKey;
1227
1228        let private_key = Ed25519PrivateKey::generate();
1229        let sig = AnySignature::ed25519(&private_key.sign(b"test"));
1230
1231        let result = MultiKeySignature::new(vec![(0, sig.clone()), (0, sig)]);
1232        assert!(result.is_err());
1233        assert!(result.unwrap_err().to_string().contains("duplicate"));
1234    }
1235
1236    #[test]
1237    #[cfg(feature = "ed25519")]
1238    fn test_multi_key_public_key_accessors() {
1239        use crate::crypto::Ed25519PrivateKey;
1240
1241        let keys: Vec<_> = (0..3)
1242            .map(|_| AnyPublicKey::ed25519(&Ed25519PrivateKey::generate().public_key()))
1243            .collect();
1244        let multi_pk = MultiKeyPublicKey::new(keys, 2).unwrap();
1245
1246        assert_eq!(multi_pk.threshold(), 2);
1247        assert_eq!(multi_pk.num_keys(), 3);
1248        assert_eq!(multi_pk.public_keys().len(), 3);
1249    }
1250
1251    #[test]
1252    #[cfg(feature = "ed25519")]
1253    fn test_multi_key_signature_accessors() {
1254        use crate::crypto::Ed25519PrivateKey;
1255
1256        let private_key = Ed25519PrivateKey::generate();
1257        let sig0 = AnySignature::ed25519(&private_key.sign(b"test"));
1258        let sig2 = AnySignature::ed25519(&private_key.sign(b"test"));
1259
1260        let multi_sig = MultiKeySignature::new(vec![(0, sig0), (2, sig2)]).unwrap();
1261
1262        assert_eq!(multi_sig.num_signatures(), 2);
1263        assert_eq!(multi_sig.signatures().len(), 2);
1264    }
1265
1266    #[test]
1267    #[cfg(feature = "ed25519")]
1268    fn test_multi_key_public_key_debug() {
1269        use crate::crypto::Ed25519PrivateKey;
1270
1271        let keys: Vec<_> = (0..2)
1272            .map(|_| AnyPublicKey::ed25519(&Ed25519PrivateKey::generate().public_key()))
1273            .collect();
1274        let multi_pk = MultiKeyPublicKey::new(keys, 2).unwrap();
1275
1276        let debug = format!("{multi_pk:?}");
1277        assert!(debug.contains("MultiKeyPublicKey"));
1278    }
1279
1280    #[test]
1281    #[cfg(feature = "ed25519")]
1282    fn test_multi_key_signature_debug() {
1283        use crate::crypto::Ed25519PrivateKey;
1284
1285        let private_key = Ed25519PrivateKey::generate();
1286        let sig = AnySignature::ed25519(&private_key.sign(b"test"));
1287        let multi_sig = MultiKeySignature::new(vec![(0, sig)]).unwrap();
1288
1289        let debug = format!("{multi_sig:?}");
1290        assert!(debug.contains("MultiKeySignature"));
1291    }
1292
1293    #[test]
1294    #[cfg(feature = "ed25519")]
1295    fn test_multi_key_public_key_display() {
1296        use crate::crypto::Ed25519PrivateKey;
1297
1298        let keys: Vec<_> = (0..2)
1299            .map(|_| AnyPublicKey::ed25519(&Ed25519PrivateKey::generate().public_key()))
1300            .collect();
1301        let multi_pk = MultiKeyPublicKey::new(keys, 2).unwrap();
1302
1303        let display = format!("{multi_pk}");
1304        assert!(display.starts_with("0x"));
1305    }
1306
1307    #[test]
1308    #[cfg(feature = "ed25519")]
1309    fn test_multi_key_signature_display() {
1310        use crate::crypto::Ed25519PrivateKey;
1311
1312        let private_key = Ed25519PrivateKey::generate();
1313        let sig = AnySignature::ed25519(&private_key.sign(b"test"));
1314        let multi_sig = MultiKeySignature::new(vec![(0, sig)]).unwrap();
1315
1316        let display = format!("{multi_sig}");
1317        assert!(display.starts_with("0x"));
1318    }
1319
1320    #[test]
1321    #[cfg(feature = "ed25519")]
1322    fn test_multi_key_public_key_to_address() {
1323        use crate::crypto::Ed25519PrivateKey;
1324
1325        let keys: Vec<_> = (0..2)
1326            .map(|_| AnyPublicKey::ed25519(&Ed25519PrivateKey::generate().public_key()))
1327            .collect();
1328        let multi_pk = MultiKeyPublicKey::new(keys, 2).unwrap();
1329
1330        let address = multi_pk.to_address();
1331        assert!(!address.is_zero());
1332    }
1333
1334    #[test]
1335    fn test_any_public_key_variant_debug() {
1336        let variant = AnyPublicKeyVariant::Ed25519;
1337        let debug = format!("{variant:?}");
1338        assert!(debug.contains("Ed25519"));
1339    }
1340
1341    #[test]
1342    #[cfg(feature = "ed25519")]
1343    fn test_any_public_key_ed25519_debug() {
1344        use crate::crypto::Ed25519PrivateKey;
1345
1346        let pk = AnyPublicKey::ed25519(&Ed25519PrivateKey::generate().public_key());
1347        let debug = format!("{pk:?}");
1348        assert!(debug.contains("Ed25519"));
1349    }
1350
1351    #[test]
1352    #[cfg(feature = "ed25519")]
1353    fn test_any_signature_ed25519_debug() {
1354        use crate::crypto::Ed25519PrivateKey;
1355
1356        let private_key = Ed25519PrivateKey::generate();
1357        let sig = AnySignature::ed25519(&private_key.sign(b"test"));
1358        let debug = format!("{sig:?}");
1359        assert!(debug.contains("Ed25519"));
1360    }
1361
1362    #[test]
1363    #[cfg(feature = "ed25519")]
1364    fn test_multi_key_insufficient_signatures() {
1365        use crate::crypto::Ed25519PrivateKey;
1366
1367        let private_keys: Vec<_> = (0..3).map(|_| Ed25519PrivateKey::generate()).collect();
1368        let public_keys: Vec<_> = private_keys
1369            .iter()
1370            .map(|k| AnyPublicKey::ed25519(&k.public_key()))
1371            .collect();
1372
1373        let multi_pk = MultiKeyPublicKey::new(public_keys, 2).unwrap();
1374        let message = b"test message";
1375
1376        // Only provide 1 signature when threshold is 2
1377        let sig0 = AnySignature::ed25519(&private_keys[0].sign(message));
1378        let multi_sig = MultiKeySignature::new(vec![(0, sig0)]).unwrap();
1379
1380        // Verify should fail
1381        let result = multi_pk.verify(message, &multi_sig);
1382        assert!(result.is_err());
1383    }
1384
1385    // ---- AnyPublicKey::from_bcs_bytes ----
1386
1387    #[test]
1388    fn test_any_public_key_from_bcs_bytes_roundtrip() {
1389        let pk = AnyPublicKey::new(AnyPublicKeyVariant::Ed25519, vec![0x7c; 32]);
1390        let wire = pk.to_bcs_bytes();
1391        let parsed = AnyPublicKey::from_bcs_bytes(&wire).unwrap();
1392        assert_eq!(parsed, pk);
1393    }
1394
1395    #[test]
1396    fn test_any_public_key_from_bcs_bytes_empty() {
1397        let err = AnyPublicKey::from_bcs_bytes(&[]).unwrap_err();
1398        assert!(matches!(err, AptosError::InvalidPublicKey(_)));
1399        assert!(err.to_string().contains("empty"));
1400    }
1401
1402    #[test]
1403    fn test_any_public_key_from_bcs_bytes_bad_variant() {
1404        let err = AnyPublicKey::from_bcs_bytes(&[9, 0]).unwrap_err();
1405        assert!(matches!(err, AptosError::InvalidPublicKey(_)));
1406        assert!(err.to_string().contains("unknown public key variant"));
1407    }
1408
1409    #[test]
1410    fn test_any_public_key_from_bcs_bytes_invalid_length_prefix() {
1411        // 0x80 is an unterminated ULEB128 continuation byte.
1412        let err = AnyPublicKey::from_bcs_bytes(&[0, 0x80]).unwrap_err();
1413        assert!(err.to_string().contains("invalid length prefix"));
1414    }
1415
1416    #[test]
1417    fn test_any_public_key_from_bcs_bytes_length_overflow() {
1418        // variant byte + ULEB128(usize::MAX): start (1 + len_bytes) + len overflows.
1419        let mut wire = vec![0u8];
1420        wire.extend(uleb128_encode(usize::MAX));
1421        let err = AnyPublicKey::from_bcs_bytes(&wire).unwrap_err();
1422        assert!(err.to_string().contains("length overflow"));
1423    }
1424
1425    #[test]
1426    fn test_any_public_key_from_bcs_bytes_truncated() {
1427        // declares 64 bytes but only 2 present.
1428        let err = AnyPublicKey::from_bcs_bytes(&[0, 0x40, 1, 2]).unwrap_err();
1429        assert!(err.to_string().contains("truncated"));
1430    }
1431
1432    #[test]
1433    fn test_any_public_key_from_bcs_bytes_trailing() {
1434        // declares 1 byte but 2 payload bytes present.
1435        let err = AnyPublicKey::from_bcs_bytes(&[0, 0x01, 0xaa, 0xbb]).unwrap_err();
1436        assert!(err.to_string().contains("trailing"));
1437    }
1438
1439    // ---- AnyPublicKey::verify additional paths ----
1440
1441    #[test]
1442    #[cfg(feature = "secp256r1")]
1443    fn test_any_public_key_verify_secp256r1_ok() {
1444        use crate::crypto::Secp256r1PrivateKey;
1445
1446        let sk = Secp256r1PrivateKey::from_bytes(&[9u8; 32]).unwrap();
1447        let pk = AnyPublicKey::secp256r1(&sk.public_key());
1448        let message = b"secp256r1 verify path";
1449        let sig = AnySignature::secp256r1(&sk.sign(message));
1450        assert!(pk.verify(message, &sig).is_ok());
1451        assert!(pk.verify(b"different", &sig).is_err());
1452    }
1453
1454    #[test]
1455    fn test_any_public_key_verify_keyless_unsupported() {
1456        // Keyless has no verification arm; matching variants still hit the
1457        // "verification not supported" fallthrough.
1458        let pk = AnyPublicKey::new(AnyPublicKeyVariant::Keyless, vec![0u8; 32]);
1459        let sig = AnySignature::new(AnyPublicKeyVariant::Keyless, vec![0u8; 64]);
1460        let err = pk.verify(b"msg", &sig).unwrap_err();
1461        assert!(err.to_string().contains("verification not supported"));
1462    }
1463
1464    #[test]
1465    fn test_any_public_key_display() {
1466        let pk = AnyPublicKey::new(AnyPublicKeyVariant::Secp256r1, vec![0xab; 4]);
1467        let display = format!("{pk}");
1468        assert_eq!(display, "Secp256r1:0xabababab");
1469    }
1470
1471    // ---- AnySignature::from_bcs_bytes ----
1472
1473    #[test]
1474    fn test_any_signature_from_bcs_bytes_empty() {
1475        let err = AnySignature::from_bcs_bytes(&[]).unwrap_err();
1476        assert!(matches!(err, AptosError::InvalidSignature(_)));
1477        assert!(err.to_string().contains("empty"));
1478    }
1479
1480    #[test]
1481    fn test_any_signature_from_bcs_bytes_bad_variant() {
1482        let err = AnySignature::from_bcs_bytes(&[9, 0]).unwrap_err();
1483        assert!(err.to_string().contains("bad variant"));
1484    }
1485
1486    #[test]
1487    fn test_any_signature_from_bcs_bytes_invalid_length_prefix() {
1488        let err = AnySignature::from_bcs_bytes(&[0, 0x80]).unwrap_err();
1489        assert!(err.to_string().contains("invalid length prefix"));
1490    }
1491
1492    #[test]
1493    fn test_any_signature_from_bcs_bytes_length_overflow() {
1494        let mut wire = vec![0u8];
1495        wire.extend(uleb128_encode(usize::MAX));
1496        let err = AnySignature::from_bcs_bytes(&wire).unwrap_err();
1497        assert!(err.to_string().contains("length overflow"));
1498    }
1499
1500    #[test]
1501    fn test_any_signature_from_bcs_bytes_truncated() {
1502        let err = AnySignature::from_bcs_bytes(&[0, 0x40, 1, 2]).unwrap_err();
1503        assert!(err.to_string().contains("truncated"));
1504    }
1505
1506    #[test]
1507    fn test_any_signature_from_bcs_bytes_trailing() {
1508        let err = AnySignature::from_bcs_bytes(&[0, 0x01, 0xaa, 0xbb]).unwrap_err();
1509        assert!(err.to_string().contains("trailing"));
1510    }
1511
1512    // ---- uleb128_decode error branches ----
1513
1514    #[test]
1515    fn test_uleb128_decode_overflow() {
1516        // Ten continuation bytes push the shift past 64 bits.
1517        assert_eq!(uleb128_decode(&[0x80; 10]), None);
1518    }
1519
1520    #[test]
1521    fn test_uleb128_decode_unterminated() {
1522        // A single continuation byte with no terminator exhausts the slice.
1523        assert_eq!(uleb128_decode(&[0x80]), None);
1524    }
1525
1526    #[test]
1527    fn test_uleb128_decode_roundtrip_multibyte() {
1528        let (value, consumed) = uleb128_decode(&uleb128_encode(300)).unwrap();
1529        assert_eq!(value, 300);
1530        assert_eq!(consumed, 2);
1531    }
1532
1533    // ---- MultiKeyPublicKey::new bounds ----
1534
1535    #[test]
1536    fn test_multi_key_public_key_too_many_keys() {
1537        let keys: Vec<_> = (0..=MAX_NUM_OF_KEYS)
1538            .map(|_| AnyPublicKey::new(AnyPublicKeyVariant::Ed25519, vec![0u8; 32]))
1539            .collect();
1540        let err = MultiKeyPublicKey::new(keys, 1).unwrap_err();
1541        assert!(err.to_string().contains("at most"));
1542    }
1543
1544    // ---- MultiKeyPublicKey::from_bytes error branches ----
1545
1546    #[test]
1547    fn test_multi_key_public_key_from_bytes_empty() {
1548        let err = MultiKeyPublicKey::from_bytes(&[]).unwrap_err();
1549        assert!(err.to_string().contains("empty bytes"));
1550    }
1551
1552    #[test]
1553    fn test_multi_key_public_key_from_bytes_zero_keys() {
1554        let err = MultiKeyPublicKey::from_bytes(&[0]).unwrap_err();
1555        assert!(err.to_string().contains("invalid number of keys"));
1556    }
1557
1558    #[test]
1559    fn test_multi_key_public_key_from_bytes_too_many_keys() {
1560        let err = MultiKeyPublicKey::from_bytes(&[33]).unwrap_err();
1561        assert!(err.to_string().contains("invalid number of keys"));
1562    }
1563
1564    #[test]
1565    fn test_multi_key_public_key_from_bytes_too_short_for_key_header() {
1566        // Declares 1 key but no bytes follow the count.
1567        let err = MultiKeyPublicKey::from_bytes(&[1]).unwrap_err();
1568        assert!(err.to_string().contains("bytes too short"));
1569    }
1570
1571    #[test]
1572    fn test_multi_key_public_key_from_bytes_bad_variant() {
1573        let err = MultiKeyPublicKey::from_bytes(&[1, 9]).unwrap_err();
1574        assert!(err.to_string().contains("unknown public key variant"));
1575    }
1576
1577    #[test]
1578    fn test_multi_key_public_key_from_bytes_invalid_uleb() {
1579        let err = MultiKeyPublicKey::from_bytes(&[1, 0, 0x80]).unwrap_err();
1580        assert!(err.to_string().contains("invalid ULEB128"));
1581    }
1582
1583    #[test]
1584    fn test_multi_key_public_key_from_bytes_key_too_large() {
1585        // ULEB128(200) exceeds the 128-byte MAX_KEY_SIZE cap.
1586        let mut wire = vec![1u8, 0u8];
1587        wire.extend(uleb128_encode(200));
1588        let err = MultiKeyPublicKey::from_bytes(&wire).unwrap_err();
1589        assert!(err.to_string().contains("exceeds maximum"));
1590    }
1591
1592    #[test]
1593    fn test_multi_key_public_key_from_bytes_too_short_for_key() {
1594        // Declares a 64-byte key but no payload follows.
1595        let err = MultiKeyPublicKey::from_bytes(&[1, 0, 0x40]).unwrap_err();
1596        assert!(err.to_string().contains("bytes too short for key"));
1597    }
1598
1599    #[test]
1600    fn test_multi_key_public_key_from_bytes_too_short_for_threshold() {
1601        // A single zero-length key parses, but no threshold byte remains.
1602        let err = MultiKeyPublicKey::from_bytes(&[1, 0, 0]).unwrap_err();
1603        assert!(err.to_string().contains("bytes too short for threshold"));
1604    }
1605
1606    // ---- MultiKeyPublicKey::verify index out of bounds ----
1607
1608    #[test]
1609    fn test_multi_key_verify_signer_index_out_of_bounds() {
1610        let pk = AnyPublicKey::new(AnyPublicKeyVariant::Ed25519, vec![0u8; 32]);
1611        let multi_pk = MultiKeyPublicKey::new(vec![pk], 1).unwrap();
1612        // A signature claiming signer index 5 while only one key exists.
1613        let sig = AnySignature::new(AnyPublicKeyVariant::Ed25519, vec![0u8; 64]);
1614        let multi_sig = MultiKeySignature::new(vec![(5, sig)]).unwrap();
1615        let err = multi_pk.verify(b"msg", &multi_sig).unwrap_err();
1616        assert!(err.to_string().contains("out of bounds"));
1617    }
1618
1619    // ---- MultiKeySignature::new / has_signature bounds ----
1620
1621    #[test]
1622    fn test_multi_key_signature_too_many_signatures() {
1623        let sigs: Vec<_> = (0..=MAX_NUM_OF_KEYS)
1624            .map(|i| {
1625                (
1626                    i as u8,
1627                    AnySignature::new(AnyPublicKeyVariant::Ed25519, vec![0u8; 64]),
1628                )
1629            })
1630            .collect();
1631        let err = MultiKeySignature::new(sigs).unwrap_err();
1632        assert!(err.to_string().contains("too many signatures"));
1633    }
1634
1635    #[test]
1636    fn test_multi_key_signature_has_signature_out_of_bounds() {
1637        let sig = AnySignature::new(AnyPublicKeyVariant::Ed25519, vec![0u8; 64]);
1638        let multi_sig = MultiKeySignature::new(vec![(0, sig)]).unwrap();
1639        assert!(!multi_sig.has_signature(255));
1640        assert!(!multi_sig.has_signature(MAX_NUM_OF_KEYS as u8));
1641    }
1642
1643    // ---- MultiKeySignature::from_bytes error branches ----
1644
1645    #[test]
1646    fn test_multi_key_signature_from_bytes_too_short() {
1647        let err = MultiKeySignature::from_bytes(&[1, 2, 3]).unwrap_err();
1648        assert!(err.to_string().contains("bytes too short"));
1649    }
1650
1651    #[test]
1652    fn test_multi_key_signature_from_bytes_zero_sigs() {
1653        let err = MultiKeySignature::from_bytes(&[0, 4, 0, 0, 0, 0]).unwrap_err();
1654        assert!(err.to_string().contains("invalid number of signatures"));
1655    }
1656
1657    #[test]
1658    fn test_multi_key_signature_from_bytes_too_many_sigs() {
1659        let err = MultiKeySignature::from_bytes(&[33, 4, 0, 0, 0, 0]).unwrap_err();
1660        assert!(err.to_string().contains("invalid number of signatures"));
1661    }
1662
1663    #[test]
1664    fn test_multi_key_signature_from_bytes_bad_bitvec_prefix() {
1665        // BitVec length prefix must be 4; here it is 5.
1666        let err = MultiKeySignature::from_bytes(&[1, 5, 0, 0, 0, 0]).unwrap_err();
1667        assert!(err.to_string().contains("BitVec length prefix"));
1668    }
1669
1670    #[test]
1671    fn test_multi_key_signature_from_bytes_bitmap_mismatch() {
1672        // Declares 2 signatures but the bitmap has no bits set.
1673        let err = MultiKeySignature::from_bytes(&[2, 4, 0, 0, 0, 0]).unwrap_err();
1674        assert!(err.to_string().contains("bitmap doesn't match"));
1675    }
1676
1677    #[test]
1678    fn test_multi_key_signature_from_bytes_too_short_for_sig() {
1679        // num_sigs=1, bitmap bit 0 set, but no room for the signature body.
1680        let err = MultiKeySignature::from_bytes(&[1, 4, 0x80, 0, 0, 0]).unwrap_err();
1681        assert!(err.to_string().contains("bytes too short"));
1682    }
1683
1684    #[test]
1685    fn test_multi_key_signature_from_bytes_bad_sig_variant() {
1686        // [num_sigs=1][variant=9][len=0][bitvec prefix=4][bitmap index0]
1687        let err = MultiKeySignature::from_bytes(&[1, 9, 0, 4, 0x80, 0, 0, 0]).unwrap_err();
1688        assert!(err.to_string().contains("unknown public key variant"));
1689    }
1690
1691    #[test]
1692    fn test_multi_key_signature_from_bytes_invalid_sig_uleb() {
1693        // [num_sigs=1][variant=0][0x80 unterminated][prefix=4][bitmap]
1694        let err = MultiKeySignature::from_bytes(&[1, 0, 0x80, 4, 0x80, 0, 0, 0]).unwrap_err();
1695        assert!(err.to_string().contains("invalid ULEB128"));
1696    }
1697
1698    #[test]
1699    fn test_multi_key_signature_from_bytes_sig_too_large() {
1700        // ULEB128(200) exceeds the 128-byte MAX_SIGNATURE_SIZE cap.
1701        let err = MultiKeySignature::from_bytes(&[1, 0, 0xC8, 0x01, 4, 0x80, 0, 0, 0]).unwrap_err();
1702        assert!(err.to_string().contains("exceeds maximum"));
1703    }
1704
1705    #[test]
1706    fn test_multi_key_signature_from_bytes_too_short_for_sig_body() {
1707        // Declares a 64-byte signature but the body is absent.
1708        let err = MultiKeySignature::from_bytes(&[1, 0, 0x40, 4, 0x80, 0, 0, 0]).unwrap_err();
1709        assert!(err.to_string().contains("bytes too short for signature"));
1710    }
1711}