Skip to main content

aptos_sdk/crypto/
multi_ed25519.rs

1//! Multi-Ed25519 signature scheme implementation.
2//!
3//! Multi-Ed25519 enables M-of-N threshold signatures where M signatures
4//! out of N public keys are required to authorize a transaction.
5
6use crate::crypto::ed25519::{
7    ED25519_PUBLIC_KEY_LENGTH, ED25519_SIGNATURE_LENGTH, Ed25519PublicKey, Ed25519Signature,
8};
9use crate::crypto::traits::{PublicKey, Verifier};
10use crate::error::{AptosError, AptosResult};
11use serde::{Deserialize, Serialize};
12use std::fmt;
13
14/// Maximum number of keys in a multi-Ed25519 account.
15pub const MAX_NUM_OF_KEYS: usize = 32;
16
17// Compile-time assertion: MAX_NUM_OF_KEYS must fit in u8 for bitmap operations
18const _: () = assert!(MAX_NUM_OF_KEYS <= u8::MAX as usize);
19
20/// Minimum threshold (at least 1 signature required).
21pub const MIN_THRESHOLD: u8 = 1;
22
23/// A multi-Ed25519 public key.
24///
25/// This is a collection of Ed25519 public keys with a threshold value.
26/// M-of-N signatures are required where M = threshold and N = number of keys.
27///
28/// # Example
29///
30/// ```rust,ignore
31/// use aptos_sdk::crypto::{Ed25519PrivateKey, MultiEd25519PublicKey};
32///
33/// let keys: Vec<_> = (0..3).map(|_| Ed25519PrivateKey::generate().public_key()).collect();
34/// let multi_pk = MultiEd25519PublicKey::new(keys, 2).unwrap(); // 2-of-3
35/// ```
36#[derive(Clone, PartialEq, Eq)]
37pub struct MultiEd25519PublicKey {
38    /// The individual public keys.
39    public_keys: Vec<Ed25519PublicKey>,
40    /// The required threshold (M in M-of-N).
41    threshold: u8,
42}
43
44impl MultiEd25519PublicKey {
45    /// Creates a new multi-Ed25519 public key.
46    ///
47    /// # Arguments
48    ///
49    /// * `public_keys` - The individual Ed25519 public keys
50    /// * `threshold` - The number of signatures required (M in M-of-N)
51    ///
52    /// # Errors
53    ///
54    /// Returns an error if:
55    /// - No public keys are provided
56    /// - More than 32 public keys are provided
57    /// - Threshold is 0
58    /// - Threshold exceeds the number of keys
59    pub fn new(public_keys: Vec<Ed25519PublicKey>, threshold: u8) -> AptosResult<Self> {
60        if public_keys.is_empty() {
61            return Err(AptosError::InvalidPublicKey(
62                "multi-Ed25519 requires at least one public key".into(),
63            ));
64        }
65        if public_keys.len() > MAX_NUM_OF_KEYS {
66            return Err(AptosError::InvalidPublicKey(format!(
67                "multi-Ed25519 supports at most {} keys, got {}",
68                MAX_NUM_OF_KEYS,
69                public_keys.len()
70            )));
71        }
72        if threshold < MIN_THRESHOLD {
73            return Err(AptosError::InvalidPublicKey(
74                "threshold must be at least 1".into(),
75            ));
76        }
77        if threshold as usize > public_keys.len() {
78            return Err(AptosError::InvalidPublicKey(format!(
79                "threshold {} exceeds number of keys {}",
80                threshold,
81                public_keys.len()
82            )));
83        }
84        Ok(Self {
85            public_keys,
86            threshold,
87        })
88    }
89
90    /// Returns the number of public keys.
91    pub fn num_keys(&self) -> usize {
92        self.public_keys.len()
93    }
94
95    /// Returns the threshold (M in M-of-N).
96    pub fn threshold(&self) -> u8 {
97        self.threshold
98    }
99
100    /// Returns the individual public keys.
101    pub fn public_keys(&self) -> &[Ed25519PublicKey] {
102        &self.public_keys
103    }
104
105    /// Serializes the public key to bytes.
106    ///
107    /// Format: `public_key_1` || `public_key_2` || ... || `public_key_n` || threshold
108    pub fn to_bytes(&self) -> Vec<u8> {
109        let mut bytes = Vec::with_capacity(self.public_keys.len() * ED25519_PUBLIC_KEY_LENGTH + 1);
110        for pk in &self.public_keys {
111            bytes.extend_from_slice(&pk.to_bytes());
112        }
113        bytes.push(self.threshold);
114        bytes
115    }
116
117    /// Creates a public key from bytes.
118    ///
119    /// # Errors
120    ///
121    /// Returns [`AptosError::InvalidPublicKey`] if:
122    /// - The bytes are empty
123    /// - The bytes are too short (less than 33 bytes for one key + threshold)
124    /// - The key bytes length is not a multiple of 32 bytes
125    /// - Any individual public key fails to parse
126    /// - The threshold is invalid (0, exceeds number of keys, etc.)
127    pub fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
128        if bytes.is_empty() {
129            return Err(AptosError::InvalidPublicKey("empty bytes".into()));
130        }
131        if bytes.len() < ED25519_PUBLIC_KEY_LENGTH + 1 {
132            return Err(AptosError::InvalidPublicKey(format!(
133                "bytes too short: {} bytes",
134                bytes.len()
135            )));
136        }
137
138        let threshold = bytes[bytes.len() - 1];
139        let key_bytes = &bytes[..bytes.len() - 1];
140
141        if !key_bytes.len().is_multiple_of(ED25519_PUBLIC_KEY_LENGTH) {
142            return Err(AptosError::InvalidPublicKey(format!(
143                "key bytes length {} is not a multiple of {}",
144                key_bytes.len(),
145                ED25519_PUBLIC_KEY_LENGTH
146            )));
147        }
148
149        let num_keys = key_bytes.len() / ED25519_PUBLIC_KEY_LENGTH;
150        let mut public_keys = Vec::with_capacity(num_keys);
151
152        for i in 0..num_keys {
153            let start = i * ED25519_PUBLIC_KEY_LENGTH;
154            let end = start + ED25519_PUBLIC_KEY_LENGTH;
155            let pk = Ed25519PublicKey::from_bytes(&key_bytes[start..end])?;
156            public_keys.push(pk);
157        }
158
159        Self::new(public_keys, threshold)
160    }
161
162    /// Derives the account address for this multi-Ed25519 public key.
163    pub fn to_address(&self) -> crate::types::AccountAddress {
164        crate::crypto::derive_address(&self.to_bytes(), crate::crypto::MULTI_ED25519_SCHEME)
165    }
166
167    /// Derives the authentication key for this public key.
168    pub fn to_authentication_key(&self) -> [u8; 32] {
169        crate::crypto::derive_authentication_key(
170            &self.to_bytes(),
171            crate::crypto::MULTI_ED25519_SCHEME,
172        )
173    }
174
175    /// Verifies a multi-Ed25519 signature against a message.
176    ///
177    /// # Errors
178    ///
179    /// This function will return an error if:
180    /// - The number of signatures is less than the threshold
181    /// - Any individual signature verification fails
182    /// - A signer index is out of bounds
183    pub fn verify(&self, message: &[u8], signature: &MultiEd25519Signature) -> AptosResult<()> {
184        // Check that we have enough signatures
185        if signature.num_signatures() < self.threshold as usize {
186            return Err(AptosError::SignatureVerificationFailed);
187        }
188
189        // Verify each signature
190        for (index, sig) in signature.signatures() {
191            if *index as usize >= self.public_keys.len() {
192                return Err(AptosError::InvalidSignature(format!(
193                    "signer index {} out of bounds (max {})",
194                    index,
195                    self.public_keys.len() - 1
196                )));
197            }
198            let pk = &self.public_keys[*index as usize];
199            pk.verify(message, sig)?;
200        }
201
202        Ok(())
203    }
204}
205
206impl PublicKey for MultiEd25519PublicKey {
207    const LENGTH: usize = 0; // Variable length
208
209    fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
210        MultiEd25519PublicKey::from_bytes(bytes)
211    }
212
213    fn to_bytes(&self) -> Vec<u8> {
214        MultiEd25519PublicKey::to_bytes(self)
215    }
216}
217
218impl Verifier for MultiEd25519PublicKey {
219    type Signature = MultiEd25519Signature;
220
221    fn verify(&self, message: &[u8], signature: &MultiEd25519Signature) -> AptosResult<()> {
222        MultiEd25519PublicKey::verify(self, message, signature)
223    }
224}
225
226impl fmt::Debug for MultiEd25519PublicKey {
227    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228        write!(
229            f,
230            "MultiEd25519PublicKey({}-of-{} keys)",
231            self.threshold,
232            self.public_keys.len()
233        )
234    }
235}
236
237impl fmt::Display for MultiEd25519PublicKey {
238    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239        f.write_str(&const_hex::encode_prefixed(self.to_bytes()))
240    }
241}
242
243impl Serialize for MultiEd25519PublicKey {
244    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
245    where
246        S: serde::Serializer,
247    {
248        if serializer.is_human_readable() {
249            serializer.serialize_str(&const_hex::encode_prefixed(self.to_bytes()))
250        } else {
251            serializer.serialize_bytes(&self.to_bytes())
252        }
253    }
254}
255
256impl<'de> Deserialize<'de> for MultiEd25519PublicKey {
257    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
258    where
259        D: serde::Deserializer<'de>,
260    {
261        if deserializer.is_human_readable() {
262            let bytes: Vec<u8> = const_hex::deserialize(deserializer)?;
263            Self::from_bytes(&bytes).map_err(serde::de::Error::custom)
264        } else {
265            let bytes = Vec::<u8>::deserialize(deserializer)?;
266            Self::from_bytes(&bytes).map_err(serde::de::Error::custom)
267        }
268    }
269}
270
271/// A multi-Ed25519 signature.
272///
273/// This contains individual Ed25519 signatures along with a bitmap indicating
274/// which signers provided signatures.
275#[derive(Clone, PartialEq, Eq)]
276pub struct MultiEd25519Signature {
277    /// Individual signatures with their signer index.
278    signatures: Vec<(u8, Ed25519Signature)>,
279    /// Bitmap indicating which keys signed. Bits are set MSB-first within each
280    /// byte (big-endian bit order): signer index 0 is bit 7 of byte 0, index 7
281    /// is bit 0 of byte 0, index 8 is bit 7 of byte 1, and so on. This matches
282    /// aptos-core's `multi_ed25519` bitmap (`128 >> pos`); see `new`.
283    bitmap: [u8; 4],
284}
285
286impl MultiEd25519Signature {
287    /// Creates a new multi-Ed25519 signature from individual signatures.
288    ///
289    /// # Arguments
290    ///
291    /// * `signatures` - Vec of (`signer_index`, signature) pairs
292    ///
293    /// The signer indices must be in ascending order and within bounds.
294    ///
295    /// # Errors
296    ///
297    /// Returns [`AptosError::InvalidSignature`] if:
298    /// - No signatures are provided
299    /// - More than 32 signatures are provided
300    /// - A signer index is out of bounds (>= 32)
301    /// - Duplicate signer indices are present
302    pub fn new(mut signatures: Vec<(u8, Ed25519Signature)>) -> AptosResult<Self> {
303        if signatures.is_empty() {
304            return Err(AptosError::InvalidSignature(
305                "multi-Ed25519 signature requires at least one signature".into(),
306            ));
307        }
308        if signatures.len() > MAX_NUM_OF_KEYS {
309            return Err(AptosError::InvalidSignature(format!(
310                "too many signatures: {} (max {})",
311                signatures.len(),
312                MAX_NUM_OF_KEYS
313            )));
314        }
315
316        // Sort by index
317        signatures.sort_by_key(|(idx, _)| *idx);
318
319        // Check for duplicates and bounds
320        let mut bitmap = [0u8; 4];
321        let mut last_index: Option<u8> = None;
322
323        for (index, _) in &signatures {
324            if *index as usize >= MAX_NUM_OF_KEYS {
325                return Err(AptosError::InvalidSignature(format!(
326                    "signer index {} out of bounds (max {})",
327                    index,
328                    MAX_NUM_OF_KEYS - 1
329                )));
330            }
331            if last_index == Some(*index) {
332                return Err(AptosError::InvalidSignature(format!(
333                    "duplicate signer index {index}"
334                )));
335            }
336            last_index = Some(*index);
337
338            // Set bit in bitmap. Aptos uses MSB-first ordering within each byte:
339            // index 0 -> bit 7 of byte 0, index 7 -> bit 0 of byte 0, index 8 ->
340            // bit 7 of byte 1, etc. This must exactly match aptos-core's
341            // `multi_ed25519::bitmap_set_bit` (uses `128 >> bucket_pos`) or
342            // on-chain signature verification fails with INVALID_SIGNATURE
343            // because the chain reads a different set of signer indices than
344            // we wrote.
345            let byte_index = (index / 8) as usize;
346            let bit_index_in_byte = index % 8;
347            bitmap[byte_index] |= 128u8 >> bit_index_in_byte;
348        }
349
350        Ok(Self { signatures, bitmap })
351    }
352
353    /// Creates a signature from bytes.
354    ///
355    /// Format: `signature_1` || `signature_2` || ... || `signature_m` || bitmap (4 bytes)
356    ///
357    /// # Errors
358    ///
359    /// Returns [`AptosError::InvalidSignature`] if:
360    /// - The bytes are too short (less than 4 bytes for bitmap)
361    /// - The signature bytes length doesn't match the expected number of signatures from the bitmap
362    /// - Any individual signature fails to parse
363    pub fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
364        if bytes.len() < 4 {
365            return Err(AptosError::InvalidSignature("bytes too short".into()));
366        }
367
368        let bitmap_start = bytes.len() - 4;
369        let mut bitmap = [0u8; 4];
370        bitmap.copy_from_slice(&bytes[bitmap_start..]);
371
372        let sig_bytes = &bytes[..bitmap_start];
373
374        // Count signatures from bitmap
375        let num_sigs = bitmap.iter().map(|b| b.count_ones()).sum::<u32>() as usize;
376
377        if sig_bytes.len() != num_sigs * ED25519_SIGNATURE_LENGTH {
378            return Err(AptosError::InvalidSignature(format!(
379                "signature bytes length {} doesn't match expected {} signatures",
380                sig_bytes.len(),
381                num_sigs
382            )));
383        }
384
385        // Parse signatures (MAX_NUM_OF_KEYS is 32, which fits in u8). MSB-first
386        // bit ordering: signer index 0 is bit 7 of byte 0 (see `new`).
387        let mut signatures = Vec::with_capacity(num_sigs);
388        let mut sig_idx = 0;
389
390        #[allow(clippy::cast_possible_truncation)]
391        for bit_pos in 0..(MAX_NUM_OF_KEYS as u8) {
392            let byte_idx = (bit_pos / 8) as usize;
393            let bit_in_byte = bit_pos % 8;
394
395            if (bitmap[byte_idx] & (128u8 >> bit_in_byte)) != 0 {
396                let start = sig_idx * ED25519_SIGNATURE_LENGTH;
397                let end = start + ED25519_SIGNATURE_LENGTH;
398                let sig = Ed25519Signature::from_bytes(&sig_bytes[start..end])?;
399                signatures.push((bit_pos, sig));
400                sig_idx += 1;
401            }
402        }
403
404        Ok(Self { signatures, bitmap })
405    }
406
407    /// Serializes the signature to bytes.
408    pub fn to_bytes(&self) -> Vec<u8> {
409        let mut bytes = Vec::with_capacity(self.signatures.len() * ED25519_SIGNATURE_LENGTH + 4);
410        for (_, sig) in &self.signatures {
411            bytes.extend_from_slice(&sig.to_bytes());
412        }
413        bytes.extend_from_slice(&self.bitmap);
414        bytes
415    }
416
417    /// Returns the number of signatures.
418    pub fn num_signatures(&self) -> usize {
419        self.signatures.len()
420    }
421
422    /// Returns the individual signatures with their indices.
423    pub fn signatures(&self) -> &[(u8, Ed25519Signature)] {
424        &self.signatures
425    }
426
427    /// Returns the signer bitmap.
428    pub fn bitmap(&self) -> &[u8; 4] {
429        &self.bitmap
430    }
431
432    /// Checks if a particular index signed.
433    pub fn has_signature(&self, index: u8) -> bool {
434        if index as usize >= MAX_NUM_OF_KEYS {
435            return false;
436        }
437        let byte_index = (index / 8) as usize;
438        let bit_in_byte = index % 8;
439        (self.bitmap[byte_index] & (128u8 >> bit_in_byte)) != 0
440    }
441}
442
443impl crate::crypto::traits::Signature for MultiEd25519Signature {
444    type PublicKey = MultiEd25519PublicKey;
445    const LENGTH: usize = 0; // Variable length
446
447    fn from_bytes(bytes: &[u8]) -> AptosResult<Self> {
448        MultiEd25519Signature::from_bytes(bytes)
449    }
450
451    fn to_bytes(&self) -> Vec<u8> {
452        MultiEd25519Signature::to_bytes(self)
453    }
454}
455
456impl fmt::Debug for MultiEd25519Signature {
457    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
458        write!(
459            f,
460            "MultiEd25519Signature({} signatures, bitmap={:?})",
461            self.signatures.len(),
462            self.bitmap
463        )
464    }
465}
466
467impl fmt::Display for MultiEd25519Signature {
468    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469        f.write_str(&const_hex::encode_prefixed(self.to_bytes()))
470    }
471}
472
473impl Serialize for MultiEd25519Signature {
474    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
475    where
476        S: serde::Serializer,
477    {
478        if serializer.is_human_readable() {
479            serializer.serialize_str(&const_hex::encode_prefixed(self.to_bytes()))
480        } else {
481            serializer.serialize_bytes(&self.to_bytes())
482        }
483    }
484}
485
486impl<'de> Deserialize<'de> for MultiEd25519Signature {
487    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
488    where
489        D: serde::Deserializer<'de>,
490    {
491        if deserializer.is_human_readable() {
492            let bytes: Vec<u8> = const_hex::deserialize(deserializer)?;
493            Self::from_bytes(&bytes).map_err(serde::de::Error::custom)
494        } else {
495            let bytes = Vec::<u8>::deserialize(deserializer)?;
496            Self::from_bytes(&bytes).map_err(serde::de::Error::custom)
497        }
498    }
499}
500
501#[cfg(test)]
502mod tests {
503    use super::*;
504    use crate::crypto::Ed25519PrivateKey;
505
506    #[test]
507    fn test_multi_ed25519_public_key_creation() {
508        let keys: Vec<_> = (0..3)
509            .map(|_| Ed25519PrivateKey::generate().public_key())
510            .collect();
511
512        // Valid 2-of-3
513        let multi_pk = MultiEd25519PublicKey::new(keys.clone(), 2).unwrap();
514        assert_eq!(multi_pk.num_keys(), 3);
515        assert_eq!(multi_pk.threshold(), 2);
516
517        // Valid 3-of-3
518        let multi_pk = MultiEd25519PublicKey::new(keys.clone(), 3).unwrap();
519        assert_eq!(multi_pk.threshold(), 3);
520
521        // Invalid: threshold > num_keys
522        assert!(MultiEd25519PublicKey::new(keys.clone(), 4).is_err());
523
524        // Invalid: threshold = 0
525        assert!(MultiEd25519PublicKey::new(keys.clone(), 0).is_err());
526
527        // Invalid: empty keys
528        assert!(MultiEd25519PublicKey::new(vec![], 1).is_err());
529    }
530
531    #[test]
532    fn test_multi_ed25519_sign_verify() {
533        let private_keys: Vec<_> = (0..3).map(|_| Ed25519PrivateKey::generate()).collect();
534        let public_keys: Vec<_> = private_keys
535            .iter()
536            .map(Ed25519PrivateKey::public_key)
537            .collect();
538
539        let multi_pk = MultiEd25519PublicKey::new(public_keys, 2).unwrap();
540        let message = b"test message";
541
542        // Sign with keys 0 and 2 (2-of-3)
543        let sig0 = private_keys[0].sign(message);
544        let sig2 = private_keys[2].sign(message);
545
546        let multi_sig = MultiEd25519Signature::new(vec![(0, sig0), (2, sig2)]).unwrap();
547
548        // Verify should succeed
549        assert!(multi_pk.verify(message, &multi_sig).is_ok());
550
551        // Wrong message should fail
552        assert!(multi_pk.verify(b"wrong message", &multi_sig).is_err());
553    }
554
555    #[test]
556    fn test_multi_ed25519_insufficient_signatures() {
557        let private_keys: Vec<_> = (0..3).map(|_| Ed25519PrivateKey::generate()).collect();
558        let public_keys: Vec<_> = private_keys
559            .iter()
560            .map(Ed25519PrivateKey::public_key)
561            .collect();
562
563        let multi_pk = MultiEd25519PublicKey::new(public_keys, 2).unwrap();
564        let message = b"test message";
565
566        // Only 1 signature (need 2)
567        let sig0 = private_keys[0].sign(message);
568        let multi_sig = MultiEd25519Signature::new(vec![(0, sig0)]).unwrap();
569
570        // Should fail due to insufficient signatures
571        assert!(multi_pk.verify(message, &multi_sig).is_err());
572    }
573
574    #[test]
575    fn test_multi_ed25519_bytes_roundtrip() {
576        let keys: Vec<_> = (0..3)
577            .map(|_| Ed25519PrivateKey::generate().public_key())
578            .collect();
579        let multi_pk = MultiEd25519PublicKey::new(keys, 2).unwrap();
580
581        let bytes = multi_pk.to_bytes();
582        let restored = MultiEd25519PublicKey::from_bytes(&bytes).unwrap();
583
584        assert_eq!(multi_pk.threshold(), restored.threshold());
585        assert_eq!(multi_pk.num_keys(), restored.num_keys());
586        assert_eq!(multi_pk.to_bytes(), restored.to_bytes());
587    }
588
589    #[test]
590    fn test_multi_ed25519_signature_bytes_roundtrip() {
591        let private_keys: Vec<_> = (0..3).map(|_| Ed25519PrivateKey::generate()).collect();
592        let message = b"test";
593
594        let sig0 = private_keys[0].sign(message);
595        let sig2 = private_keys[2].sign(message);
596
597        let multi_sig = MultiEd25519Signature::new(vec![(0, sig0), (2, sig2)]).unwrap();
598
599        let bytes = multi_sig.to_bytes();
600        let restored = MultiEd25519Signature::from_bytes(&bytes).unwrap();
601
602        assert_eq!(multi_sig.num_signatures(), restored.num_signatures());
603        assert_eq!(multi_sig.bitmap(), restored.bitmap());
604    }
605
606    #[test]
607    fn test_multi_ed25519_address_derivation() {
608        let keys: Vec<_> = (0..3)
609            .map(|_| Ed25519PrivateKey::generate().public_key())
610            .collect();
611        let multi_pk = MultiEd25519PublicKey::new(keys, 2).unwrap();
612
613        let address = multi_pk.to_address();
614        assert!(!address.is_zero());
615
616        // Same keys should produce same address
617        let address2 = multi_pk.to_address();
618        assert_eq!(address, address2);
619    }
620
621    #[test]
622    fn test_signature_bitmap() {
623        let private_keys: Vec<_> = (0..5).map(|_| Ed25519PrivateKey::generate()).collect();
624        let message = b"test";
625
626        // Sign with indices 1, 3, 4
627        let signatures: Vec<_> = [1, 3, 4]
628            .iter()
629            .map(|&i| (i, private_keys[i as usize].sign(message)))
630            .collect();
631
632        let multi_sig = MultiEd25519Signature::new(signatures).unwrap();
633
634        assert!(!multi_sig.has_signature(0));
635        assert!(multi_sig.has_signature(1));
636        assert!(!multi_sig.has_signature(2));
637        assert!(multi_sig.has_signature(3));
638        assert!(multi_sig.has_signature(4));
639        assert!(!multi_sig.has_signature(5));
640    }
641
642    #[test]
643    fn test_multi_ed25519_public_key_too_many_keys() {
644        let keys: Vec<_> = (0..33) // MAX_NUM_OF_KEYS is 32
645            .map(|_| Ed25519PrivateKey::generate().public_key())
646            .collect();
647
648        let result = MultiEd25519PublicKey::new(keys, 2);
649        assert!(result.is_err());
650    }
651
652    #[test]
653    fn test_multi_ed25519_public_keys_accessor() {
654        let keys: Vec<_> = (0..3)
655            .map(|_| Ed25519PrivateKey::generate().public_key())
656            .collect();
657        let multi_pk = MultiEd25519PublicKey::new(keys.clone(), 2).unwrap();
658
659        assert_eq!(multi_pk.public_keys().len(), 3);
660    }
661
662    #[test]
663    fn test_multi_ed25519_signature_num_signatures() {
664        let private_keys: Vec<_> = (0..3).map(|_| Ed25519PrivateKey::generate()).collect();
665        let message = b"test";
666
667        let sig0 = private_keys[0].sign(message);
668        let sig2 = private_keys[2].sign(message);
669
670        let multi_sig = MultiEd25519Signature::new(vec![(0, sig0), (2, sig2)]).unwrap();
671
672        assert_eq!(multi_sig.num_signatures(), 2);
673        // Aptos MSB-first bit order: signer index 0 = bit 7, signer index 2 = bit 5.
674        // So with signers {0, 2}, bitmap[0] = 0b1010_0000 = 0xa0 = 160.
675        let bitmap_bytes = multi_sig.bitmap();
676        assert_eq!(bitmap_bytes[0], 0b1010_0000);
677    }
678
679    #[test]
680    fn test_multi_ed25519_signature_empty() {
681        let result = MultiEd25519Signature::new(vec![]);
682        assert!(result.is_err());
683    }
684
685    #[test]
686    fn test_multi_ed25519_signature_index_out_of_bounds() {
687        let private_key = Ed25519PrivateKey::generate();
688        let sig = private_key.sign(b"test");
689
690        // Index 33 is out of bounds (MAX_NUM_OF_KEYS is 32)
691        let result = MultiEd25519Signature::new(vec![(33, sig)]);
692        assert!(result.is_err());
693    }
694
695    #[test]
696    fn test_multi_ed25519_signature_duplicate_index() {
697        let private_key = Ed25519PrivateKey::generate();
698        let sig1 = private_key.sign(b"test1");
699        let sig2 = private_key.sign(b"test2");
700
701        // Duplicate index 0
702        let result = MultiEd25519Signature::new(vec![(0, sig1), (0, sig2)]);
703        assert!(result.is_err());
704    }
705
706    #[test]
707    fn test_multi_ed25519_public_key_from_bytes_invalid() {
708        // Too short - not even a threshold byte
709        let result = MultiEd25519PublicKey::from_bytes(&[]);
710        assert!(result.is_err());
711
712        // Just a threshold, no keys
713        let result = MultiEd25519PublicKey::from_bytes(&[2]);
714        assert!(result.is_err());
715
716        // Invalid length - not a multiple of 32 + 1
717        let result = MultiEd25519PublicKey::from_bytes(&[1, 2, 3, 4, 5]);
718        assert!(result.is_err());
719    }
720
721    #[test]
722    fn test_multi_ed25519_signature_from_bytes_invalid() {
723        // Too short
724        let result = MultiEd25519Signature::from_bytes(&[]);
725        assert!(result.is_err());
726
727        // Just bitmap, no signatures
728        let result = MultiEd25519Signature::from_bytes(&[0, 0, 0, 1]);
729        assert!(result.is_err());
730    }
731
732    #[test]
733    fn test_multi_ed25519_verify_invalid_signature_index() {
734        let private_keys: Vec<_> = (0..3).map(|_| Ed25519PrivateKey::generate()).collect();
735        let public_keys: Vec<_> = private_keys
736            .iter()
737            .map(Ed25519PrivateKey::public_key)
738            .collect();
739
740        let multi_pk = MultiEd25519PublicKey::new(public_keys, 2).unwrap();
741        let message = b"test message";
742
743        // Sign with indices 0 and 5 (5 is out of bounds for 3 keys)
744        let sig0 = private_keys[0].sign(message);
745        let sig5 = private_keys[0].sign(message); // Use same key, doesn't matter for this test
746
747        // Create bitmap with bit 5 set
748        let bitmap = (1u32 << 0) | (1u32 << 5);
749        let mut bytes = Vec::new();
750        bytes.extend_from_slice(&sig0.to_bytes());
751        bytes.extend_from_slice(&sig5.to_bytes());
752        bytes.extend_from_slice(&bitmap.to_le_bytes());
753
754        let multi_sig = MultiEd25519Signature::from_bytes(&bytes).unwrap();
755
756        // Verification should fail because index 5 is out of bounds
757        let result = multi_pk.verify(message, &multi_sig);
758        assert!(result.is_err());
759    }
760
761    #[test]
762    fn test_multi_ed25519_verify_wrong_signature() {
763        let private_keys: Vec<_> = (0..3).map(|_| Ed25519PrivateKey::generate()).collect();
764        let public_keys: Vec<_> = private_keys
765            .iter()
766            .map(Ed25519PrivateKey::public_key)
767            .collect();
768
769        let multi_pk = MultiEd25519PublicKey::new(public_keys, 2).unwrap();
770        let message = b"test message";
771
772        // Sign with key 0 but claim it's from key 1
773        let sig0 = private_keys[0].sign(message);
774        let sig1 = private_keys[0].sign(message); // Wrong key for index 1
775
776        let multi_sig = MultiEd25519Signature::new(vec![(0, sig0), (1, sig1)]).unwrap();
777
778        // Verification should fail because sig at index 1 doesn't match key 1
779        let result = multi_pk.verify(message, &multi_sig);
780        assert!(result.is_err());
781    }
782
783    #[test]
784    fn test_multi_ed25519_public_key_debug() {
785        let keys: Vec<_> = (0..2)
786            .map(|_| Ed25519PrivateKey::generate().public_key())
787            .collect();
788        let multi_pk = MultiEd25519PublicKey::new(keys, 2).unwrap();
789        let debug = format!("{multi_pk:?}");
790        assert!(debug.contains("MultiEd25519PublicKey"));
791        assert!(debug.contains("2-of-2"));
792    }
793
794    #[test]
795    fn test_multi_ed25519_signature_debug() {
796        let private_key = Ed25519PrivateKey::generate();
797        let sig = private_key.sign(b"test");
798        let multi_sig = MultiEd25519Signature::new(vec![(0, sig)]).unwrap();
799
800        let debug = format!("{multi_sig:?}");
801        assert!(debug.contains("MultiEd25519Signature"));
802    }
803
804    #[test]
805    fn test_multi_ed25519_json_serialization() {
806        let keys: Vec<_> = (0..3)
807            .map(|_| Ed25519PrivateKey::generate().public_key())
808            .collect();
809        let multi_pk = MultiEd25519PublicKey::new(keys, 2).unwrap();
810
811        let json = serde_json::to_string(&multi_pk).unwrap();
812        let parsed: MultiEd25519PublicKey = serde_json::from_str(&json).unwrap();
813
814        assert_eq!(multi_pk.threshold(), parsed.threshold());
815        assert_eq!(multi_pk.num_keys(), parsed.num_keys());
816    }
817
818    #[test]
819    fn test_multi_ed25519_signature_json_serialization() {
820        let private_keys: Vec<_> = (0..3).map(|_| Ed25519PrivateKey::generate()).collect();
821        let message = b"test";
822
823        let sig0 = private_keys[0].sign(message);
824        let sig2 = private_keys[2].sign(message);
825
826        let multi_sig = MultiEd25519Signature::new(vec![(0, sig0), (2, sig2)]).unwrap();
827
828        let json = serde_json::to_string(&multi_sig).unwrap();
829        let parsed: MultiEd25519Signature = serde_json::from_str(&json).unwrap();
830
831        assert_eq!(multi_sig.num_signatures(), parsed.num_signatures());
832        assert_eq!(multi_sig.bitmap(), parsed.bitmap());
833    }
834
835    #[test]
836    fn test_multi_ed25519_signature_from_bytes_too_short() {
837        let bytes = vec![0u8; 3]; // Less than 4 bytes (bitmap)
838        let result = MultiEd25519Signature::from_bytes(&bytes);
839        assert!(result.is_err());
840        assert!(result.unwrap_err().to_string().contains("too short"));
841    }
842
843    #[test]
844    fn test_multi_ed25519_signature_from_bytes_invalid_length() {
845        // Create bytes with bitmap indicating 1 signature but wrong number of bytes
846        let mut bytes = vec![0u8; 10]; // Not a multiple of signature length
847        // Set bitmap to indicate 1 signature (bit 0 set)
848        bytes.extend_from_slice(&[0x01, 0x00, 0x00, 0x00]);
849
850        let result = MultiEd25519Signature::from_bytes(&bytes);
851        assert!(result.is_err());
852    }
853
854    #[test]
855    fn test_multi_ed25519_signature_has_signature() {
856        let private_key = Ed25519PrivateKey::generate();
857        let sig0 = private_key.sign(b"test");
858        let sig2 = private_key.sign(b"test");
859
860        let multi_sig = MultiEd25519Signature::new(vec![(0, sig0), (2, sig2)]).unwrap();
861
862        assert!(multi_sig.has_signature(0));
863        assert!(!multi_sig.has_signature(1));
864        assert!(multi_sig.has_signature(2));
865        assert!(!multi_sig.has_signature(3));
866        assert!(!multi_sig.has_signature(32)); // Out of bounds
867    }
868
869    #[test]
870    fn test_multi_ed25519_signature_signatures_accessor() {
871        let private_key = Ed25519PrivateKey::generate();
872        let sig0 = private_key.sign(b"test");
873        let sig1 = private_key.sign(b"test");
874
875        let multi_sig = MultiEd25519Signature::new(vec![(0, sig0), (1, sig1)]).unwrap();
876
877        let signatures = multi_sig.signatures();
878        assert_eq!(signatures.len(), 2);
879        assert_eq!(signatures[0].0, 0);
880        assert_eq!(signatures[1].0, 1);
881    }
882
883    #[test]
884    fn test_multi_ed25519_public_key_public_keys_accessor() {
885        let keys: Vec<_> = (0..3)
886            .map(|_| Ed25519PrivateKey::generate().public_key())
887            .collect();
888        let multi_pk = MultiEd25519PublicKey::new(keys.clone(), 2).unwrap();
889
890        let pks = multi_pk.public_keys();
891        assert_eq!(pks.len(), 3);
892    }
893
894    #[test]
895    fn test_multi_ed25519_signature_display() {
896        let private_key = Ed25519PrivateKey::generate();
897        let sig = private_key.sign(b"test");
898        let multi_sig = MultiEd25519Signature::new(vec![(0, sig)]).unwrap();
899
900        let display = format!("{multi_sig}");
901        assert!(display.starts_with("0x"));
902    }
903
904    #[test]
905    fn test_multi_ed25519_public_key_display() {
906        let keys: Vec<_> = (0..2)
907            .map(|_| Ed25519PrivateKey::generate().public_key())
908            .collect();
909        let multi_pk = MultiEd25519PublicKey::new(keys, 2).unwrap();
910
911        let display = format!("{multi_pk}");
912        assert!(display.starts_with("0x"));
913    }
914
915    #[test]
916    fn test_multi_ed25519_signature_roundtrip() {
917        let private_key = Ed25519PrivateKey::generate();
918        let sig0 = private_key.sign(b"test");
919        let sig1 = private_key.sign(b"test");
920
921        let multi_sig = MultiEd25519Signature::new(vec![(0, sig0), (1, sig1)]).unwrap();
922        let bytes = multi_sig.to_bytes();
923        let restored = MultiEd25519Signature::from_bytes(&bytes).unwrap();
924
925        assert_eq!(multi_sig.num_signatures(), restored.num_signatures());
926        assert_eq!(multi_sig.bitmap(), restored.bitmap());
927    }
928
929    #[test]
930    fn test_multi_ed25519_public_key_roundtrip() {
931        let keys: Vec<_> = (0..3)
932            .map(|_| Ed25519PrivateKey::generate().public_key())
933            .collect();
934        let multi_pk = MultiEd25519PublicKey::new(keys, 2).unwrap();
935        let bytes = multi_pk.to_bytes();
936        let restored = MultiEd25519PublicKey::from_bytes(&bytes).unwrap();
937
938        assert_eq!(multi_pk.threshold(), restored.threshold());
939        assert_eq!(multi_pk.num_keys(), restored.num_keys());
940    }
941
942    #[test]
943    fn test_multi_ed25519_signature_new_empty() {
944        let result = MultiEd25519Signature::new(vec![]);
945        assert!(result.is_err());
946        assert!(result.unwrap_err().to_string().contains("at least one"));
947    }
948
949    #[test]
950    fn test_multi_ed25519_signature_new_duplicate_index() {
951        let private_key = Ed25519PrivateKey::generate();
952        let first_sig = private_key.sign(b"test");
953        let second_sig = private_key.sign(b"test");
954
955        let result = MultiEd25519Signature::new(vec![(0, first_sig), (0, second_sig)]);
956        assert!(result.is_err());
957        assert!(result.unwrap_err().to_string().contains("duplicate"));
958    }
959
960    #[test]
961    fn test_multi_ed25519_signature_new_index_out_of_bounds() {
962        let private_key = Ed25519PrivateKey::generate();
963        let sig = private_key.sign(b"test");
964
965        let result = MultiEd25519Signature::new(vec![(32, sig)]); // Index 32 is out of bounds
966        assert!(result.is_err());
967    }
968
969    #[test]
970    fn test_multi_ed25519_public_key_to_address() {
971        let keys: Vec<_> = (0..3)
972            .map(|_| Ed25519PrivateKey::generate().public_key())
973            .collect();
974        let multi_pk = MultiEd25519PublicKey::new(keys, 2).unwrap();
975
976        let address = multi_pk.to_address();
977        assert!(!address.is_zero());
978    }
979
980    #[test]
981    fn test_multi_ed25519_public_key_from_bytes_invalid_length() {
982        // Invalid length (not a multiple of ED25519_PUBLIC_KEY_LENGTH + 1 for threshold)
983        let bytes = vec![0u8; 10];
984        let result = MultiEd25519PublicKey::from_bytes(&bytes);
985        assert!(result.is_err());
986    }
987
988    #[test]
989    fn test_multi_ed25519_bcs_roundtrip_public_key() {
990        let keys: Vec<_> = (0..3)
991            .map(|_| Ed25519PrivateKey::generate().public_key())
992            .collect();
993        let multi_pk = MultiEd25519PublicKey::new(keys, 2).unwrap();
994
995        let bcs_bytes = aptos_bcs::to_bytes(&multi_pk).unwrap();
996        let restored: MultiEd25519PublicKey = aptos_bcs::from_bytes(&bcs_bytes).unwrap();
997
998        assert_eq!(multi_pk.threshold(), restored.threshold());
999        assert_eq!(multi_pk.num_keys(), restored.num_keys());
1000    }
1001
1002    #[test]
1003    fn test_multi_ed25519_bcs_roundtrip_signature() {
1004        let private_key = Ed25519PrivateKey::generate();
1005        let sig = private_key.sign(b"test");
1006        let multi_sig = MultiEd25519Signature::new(vec![(0, sig)]).unwrap();
1007
1008        let bcs_bytes = aptos_bcs::to_bytes(&multi_sig).unwrap();
1009        let restored: MultiEd25519Signature = aptos_bcs::from_bytes(&bcs_bytes).unwrap();
1010
1011        assert_eq!(multi_sig.num_signatures(), restored.num_signatures());
1012    }
1013}