Skip to main content

csv_adapter_core/
signature.rs

1//! Signature verification trait and implementations
2//!
3//! This module provides chain-agnostic signature verification support.
4//! Different chains use different signature schemes:
5//! - Bitcoin/Ethereum: ECDSA over secp256k1
6//! - Sui/Aptos: Ed25519
7//! - Celestia: ECDSA over secp256k1 (Tendermint style)
8
9use crate::error::{AdapterError, Result};
10
11/// Signature scheme used by a chain
12#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
13pub enum SignatureScheme {
14    /// ECDSA over secp256k1 (Bitcoin, Ethereum, Celestia)
15    Secp256k1,
16    /// Ed25519 (Sui, Aptos)
17    Ed25519,
18}
19
20/// A signature with its associated public key
21#[derive(Clone, Debug)]
22pub struct Signature {
23    /// Signature bytes (scheme-specific format)
24    pub signature: Vec<u8>,
25    /// Public key bytes (scheme-specific format)
26    pub public_key: Vec<u8>,
27    /// Message that was signed
28    pub message: Vec<u8>,
29}
30
31impl Signature {
32    /// Create a new signature
33    pub fn new(signature: Vec<u8>, public_key: Vec<u8>, message: Vec<u8>) -> Self {
34        Self {
35            signature,
36            public_key,
37            message,
38        }
39    }
40
41    /// Verify this signature using the appropriate scheme
42    pub fn verify(&self, scheme: SignatureScheme) -> Result<()> {
43        match scheme {
44            SignatureScheme::Secp256k1 => {
45                verify_secp256k1(&self.signature, &self.public_key, &self.message)
46            }
47            SignatureScheme::Ed25519 => {
48                verify_ed25519(&self.signature, &self.public_key, &self.message)
49            }
50        }
51    }
52}
53
54/// Verify an ECDSA secp256k1 signature
55///
56/// Signature format: 64 bytes (r || s) or 65 bytes (recovery_id || r || s)
57/// Public key format: 33 bytes (compressed) or 65 bytes (uncompressed)
58/// Message: 32 bytes (pre-hashed)
59fn verify_secp256k1(signature: &[u8], public_key: &[u8], message: &[u8]) -> Result<()> {
60    use secp256k1::{ecdsa, Message, PublicKey, Secp256k1};
61
62    // Validate input sizes
63    if message.len() != 32 {
64        return Err(AdapterError::SignatureVerificationFailed(format!(
65            "Message must be 32 bytes, got {}",
66            message.len()
67        )));
68    }
69
70    if public_key.is_empty() {
71        return Err(AdapterError::SignatureVerificationFailed(
72            "Empty public key".to_string(),
73        ));
74    }
75
76    if signature.is_empty() {
77        return Err(AdapterError::SignatureVerificationFailed(
78            "Empty signature".to_string(),
79        ));
80    }
81
82    // Validate public key format (33 bytes compressed or 65 bytes uncompressed)
83    if public_key.len() != 33 && public_key.len() != 65 {
84        return Err(AdapterError::SignatureVerificationFailed(format!(
85            "Invalid public key length: {} (expected 33 or 65)",
86            public_key.len()
87        )));
88    }
89
90    // Signature should be 64 bytes (r || s) or 65 bytes (recovery_id || r || s)
91    if signature.len() != 64 && signature.len() != 65 {
92        return Err(AdapterError::SignatureVerificationFailed(format!(
93            "Invalid signature length: {} (expected 64 or 65)",
94            signature.len()
95        )));
96    }
97
98    // Parse public key
99    let pubkey = PublicKey::from_slice(public_key).map_err(|e| {
100        AdapterError::SignatureVerificationFailed(format!("Invalid public key: {}", e))
101    })?;
102
103    // Parse signature
104    let sig = if signature.len() == 64 {
105        ecdsa::Signature::from_compact(signature).map_err(|e| {
106            AdapterError::SignatureVerificationFailed(format!("Invalid signature format: {}", e))
107        })?
108    } else {
109        // 65 bytes: skip recovery ID
110        ecdsa::Signature::from_compact(&signature[1..]).map_err(|e| {
111            AdapterError::SignatureVerificationFailed(format!("Invalid signature format: {}", e))
112        })?
113    };
114
115    // Parse message
116    let msg = Message::from_digest_slice(message).map_err(|e| {
117        AdapterError::SignatureVerificationFailed(format!("Invalid message: {}", e))
118    })?;
119
120    // Perform actual cryptographic verification
121    let secp = Secp256k1::verification_only();
122    secp.verify_ecdsa(&msg, &sig, &pubkey).map_err(|e| {
123        AdapterError::SignatureVerificationFailed(format!("Signature verification failed: {}", e))
124    })?;
125
126    Ok(())
127}
128
129/// Verify an Ed25519 signature
130///
131/// Signature format: 64 bytes (R || S)
132/// Public key format: 32 bytes
133/// Message: arbitrary length
134fn verify_ed25519(signature: &[u8], public_key: &[u8], message: &[u8]) -> Result<()> {
135    use ed25519_dalek::{Signature, Verifier, VerifyingKey};
136
137    // Validate input sizes
138    if public_key.is_empty() {
139        return Err(AdapterError::SignatureVerificationFailed(
140            "Empty public key".to_string(),
141        ));
142    }
143
144    if signature.is_empty() {
145        return Err(AdapterError::SignatureVerificationFailed(
146            "Empty signature".to_string(),
147        ));
148    }
149
150    // Ed25519 public key must be 32 bytes
151    if public_key.len() != 32 {
152        return Err(AdapterError::SignatureVerificationFailed(format!(
153            "Invalid Ed25519 public key length: {} (expected 32)",
154            public_key.len()
155        )));
156    }
157
158    // Ed25519 signature must be 64 bytes
159    if signature.len() != 64 {
160        return Err(AdapterError::SignatureVerificationFailed(format!(
161            "Invalid Ed25519 signature length: {} (expected 64)",
162            signature.len()
163        )));
164    }
165
166    // Parse public key
167    let verifying_key = VerifyingKey::from_bytes(public_key.try_into().unwrap()).map_err(|e| {
168        AdapterError::SignatureVerificationFailed(format!("Invalid Ed25519 public key: {}", e))
169    })?;
170
171    // Parse signature
172    let sig_bytes_arr: [u8; 64] = signature.try_into().unwrap();
173    let sig = Signature::from_bytes(&sig_bytes_arr);
174
175    // Perform actual cryptographic verification
176    verifying_key.verify(message, &sig).map_err(|e| {
177        AdapterError::SignatureVerificationFailed(format!(
178            "Ed25519 signature verification failed: {}",
179            e
180        ))
181    })?;
182
183    Ok(())
184}
185
186/// Verify multiple signatures
187pub fn verify_signatures(signatures: &[Signature], scheme: SignatureScheme) -> Result<()> {
188    if signatures.is_empty() {
189        return Err(AdapterError::SignatureVerificationFailed(
190            "No signatures to verify".to_string(),
191        ));
192    }
193
194    for (i, sig) in signatures.iter().enumerate() {
195        sig.verify(scheme).map_err(|e| {
196            AdapterError::SignatureVerificationFailed(format!(
197                "Signature {} verification failed: {}",
198                i, e
199            ))
200        })?;
201    }
202
203    Ok(())
204}
205
206/// Parse signatures from raw bytes (chain-specific format)
207///
208/// This is a helper that adapters can use to parse their signature format
209pub fn parse_signatures_from_bytes(
210    raw_signatures: &[Vec<u8>],
211    public_keys: &[Vec<u8>],
212    message: &[u8],
213) -> Vec<Signature> {
214    raw_signatures
215        .iter()
216        .zip(public_keys.iter())
217        .map(|(sig, pk)| Signature::new(sig.clone(), pk.clone(), message.to_vec()))
218        .collect()
219}
220
221#[cfg(test)]
222mod tests {
223    use super::*;
224
225    #[test]
226    fn test_secp256k1_valid_signature() {
227        use secp256k1::{Message, Secp256k1, SecretKey};
228
229        let secp = Secp256k1::new();
230        let secret_key = SecretKey::new(&mut secp256k1::rand::thread_rng());
231        let public_key = secp256k1::PublicKey::from_secret_key(&secp, &secret_key);
232        let message = [0xCD; 32];
233        let msg = Message::from_digest_slice(&message).unwrap();
234        let signature = secp.sign_ecdsa(&msg, &secret_key);
235        let sig_bytes = signature.serialize_compact();
236        let pubkey_bytes = public_key.serialize();
237
238        let sig = Signature::new(sig_bytes.to_vec(), pubkey_bytes.to_vec(), message.to_vec());
239        assert!(sig.verify(SignatureScheme::Secp256k1).is_ok());
240    }
241
242    #[test]
243    fn test_secp256k1_invalid_signature_fails() {
244        use secp256k1::{Message, Secp256k1, SecretKey};
245
246        let secp = Secp256k1::new();
247        let secret_key = SecretKey::new(&mut secp256k1::rand::thread_rng());
248        let public_key = secp256k1::PublicKey::from_secret_key(&secp, &secret_key);
249        let pubkey_bytes = public_key.serialize();
250
251        // Wrong message
252        let message = [0xCD; 32];
253        let different_message = [0xAB; 32];
254        let msg = Message::from_digest_slice(&message).unwrap();
255        let signature = secp.sign_ecdsa(&msg, &secret_key);
256        let sig_bytes = signature.serialize_compact();
257
258        let sig = Signature::new(
259            sig_bytes.to_vec(),
260            pubkey_bytes.to_vec(),
261            different_message.to_vec(),
262        );
263        assert!(sig.verify(SignatureScheme::Secp256k1).is_err());
264    }
265
266    #[test]
267    fn test_secp256k1_invalid_message_length() {
268        let signature = vec![0u8; 64];
269        let public_key = vec![0x02; 33];
270        let message = vec![0u8; 16]; // Wrong length
271
272        let sig = Signature::new(signature, public_key, message);
273        assert!(sig.verify(SignatureScheme::Secp256k1).is_err());
274    }
275
276    #[test]
277    fn test_secp256k1_empty_signature() {
278        let public_key = vec![0x02; 33];
279        let message = [0u8; 32];
280
281        let sig = Signature::new(vec![], public_key, message.to_vec());
282        assert!(sig.verify(SignatureScheme::Secp256k1).is_err());
283    }
284
285    #[test]
286    fn test_secp256k1_empty_public_key() {
287        let signature = vec![0u8; 64];
288        let message = [0u8; 32];
289
290        let sig = Signature::new(signature, vec![], message.to_vec());
291        assert!(sig.verify(SignatureScheme::Secp256k1).is_err());
292    }
293
294    #[test]
295    fn test_secp256k1_invalid_public_key_length() {
296        let signature = vec![0u8; 64];
297        let public_key = vec![0x02; 32]; // Wrong length
298        let message = [0u8; 32];
299
300        let sig = Signature::new(signature, public_key, message.to_vec());
301        assert!(sig.verify(SignatureScheme::Secp256k1).is_err());
302    }
303
304    #[test]
305    fn test_secp256k1_invalid_compressed_key_prefix() {
306        let signature = vec![0u8; 64];
307        let mut public_key = vec![0u8; 33];
308        public_key[0] = 0x05; // Invalid prefix
309        let message = [0u8; 32];
310
311        let sig = Signature::new(signature, public_key, message.to_vec());
312        assert!(sig.verify(SignatureScheme::Secp256k1).is_err());
313    }
314
315    #[test]
316    fn test_secp256k1_tampered_signature() {
317        use secp256k1::{Message, Secp256k1, SecretKey};
318
319        let secp = Secp256k1::new();
320        let secret_key = SecretKey::new(&mut secp256k1::rand::thread_rng());
321        let public_key = secp256k1::PublicKey::from_secret_key(&secp, &secret_key);
322        let message = [0xCD; 32];
323        let msg = Message::from_digest_slice(&message).unwrap();
324        let signature = secp.sign_ecdsa(&msg, &secret_key);
325        let mut sig_bytes = signature.serialize_compact();
326        // Tamper with signature
327        sig_bytes[0] ^= 0xFF;
328        let pubkey_bytes = public_key.serialize();
329
330        let sig = Signature::new(sig_bytes.to_vec(), pubkey_bytes.to_vec(), message.to_vec());
331        assert!(sig.verify(SignatureScheme::Secp256k1).is_err());
332    }
333
334    #[test]
335    fn test_ed25519_valid_signature() {
336        use ed25519_dalek::Signature as DalekSignature;
337        use ed25519_dalek::{Signer, SigningKey, VerifyingKey};
338        use rand::rngs::OsRng;
339
340        let signing_key = SigningKey::generate(&mut OsRng);
341        let verifying_key: VerifyingKey = signing_key.verifying_key();
342        let message = b"This is a test message for Ed25519 verification";
343        let signature: DalekSignature = signing_key.sign(message);
344
345        let sig = Signature::new(
346            signature.to_bytes().to_vec(),
347            verifying_key.to_bytes().to_vec(),
348            message.to_vec(),
349        );
350        assert!(sig.verify(SignatureScheme::Ed25519).is_ok());
351    }
352
353    #[test]
354    fn test_ed25519_invalid_signature_fails() {
355        use ed25519_dalek::Signature as DalekSignature;
356        use ed25519_dalek::{Signer, SigningKey, VerifyingKey};
357        use rand::rngs::OsRng;
358
359        let signing_key = SigningKey::generate(&mut OsRng);
360        let verifying_key: VerifyingKey = signing_key.verifying_key();
361        let message = b"Original message";
362        let different_message = b"Different message";
363        let signature: DalekSignature = signing_key.sign(message);
364
365        let sig = Signature::new(
366            signature.to_bytes().to_vec(),
367            verifying_key.to_bytes().to_vec(),
368            different_message.to_vec(),
369        );
370        assert!(sig.verify(SignatureScheme::Ed25519).is_err());
371    }
372
373    #[test]
374    fn test_ed25519_invalid_public_key_length() {
375        let signature = vec![0u8; 64];
376        let public_key = vec![0u8; 33]; // Wrong length
377        let message = vec![0u8; 32];
378
379        let sig = Signature::new(signature, public_key, message);
380        assert!(sig.verify(SignatureScheme::Ed25519).is_err());
381    }
382
383    #[test]
384    fn test_ed25519_invalid_signature_length() {
385        let signature = vec![0u8; 63]; // Wrong length
386        let public_key = vec![0u8; 32];
387        let message = vec![0u8; 32];
388
389        let sig = Signature::new(signature, public_key, message);
390        assert!(sig.verify(SignatureScheme::Ed25519).is_err());
391    }
392
393    #[test]
394    fn test_ed25519_empty_signature() {
395        let public_key = vec![0u8; 32];
396        let message = vec![0u8; 32];
397
398        let sig = Signature::new(vec![], public_key, message);
399        assert!(sig.verify(SignatureScheme::Ed25519).is_err());
400    }
401
402    #[test]
403    fn test_ed25519_empty_public_key() {
404        let signature = vec![0u8; 64];
405        let message = vec![0u8; 32];
406
407        let sig = Signature::new(signature, vec![], message);
408        assert!(sig.verify(SignatureScheme::Ed25519).is_err());
409    }
410
411    #[test]
412    fn test_ed25519_tampered_signature() {
413        use ed25519_dalek::Signature as DalekSignature;
414        use ed25519_dalek::{Signer, SigningKey, VerifyingKey};
415        use rand::rngs::OsRng;
416
417        let signing_key = SigningKey::generate(&mut OsRng);
418        let verifying_key: VerifyingKey = signing_key.verifying_key();
419        let message = b"Test message";
420        let signature: DalekSignature = signing_key.sign(message);
421        let mut sig_bytes = signature.to_bytes();
422        // Tamper with signature
423        sig_bytes[0] ^= 0xFF;
424
425        let sig = Signature::new(
426            sig_bytes.to_vec(),
427            verifying_key.to_bytes().to_vec(),
428            message.to_vec(),
429        );
430        assert!(sig.verify(SignatureScheme::Ed25519).is_err());
431    }
432
433    #[test]
434    fn test_verify_signatures_multiple() {
435        use secp256k1::{Message, Secp256k1, SecretKey};
436
437        let secp = Secp256k1::new();
438        let message = [0xCD; 32];
439        let msg = Message::from_digest_slice(&message).unwrap();
440
441        // Create 3 valid secp256k1 signatures with different keys
442        let mut sigs = Vec::new();
443        for _ in 0..3 {
444            let secret_key = SecretKey::new(&mut secp256k1::rand::thread_rng());
445            let public_key = secp256k1::PublicKey::from_secret_key(&secp, &secret_key);
446            let signature = secp.sign_ecdsa(&msg, &secret_key);
447            let sig_bytes = signature.serialize_compact();
448            let pubkey_bytes = public_key.serialize();
449            sigs.push(Signature::new(
450                sig_bytes.to_vec(),
451                pubkey_bytes.to_vec(),
452                message.to_vec(),
453            ));
454        }
455
456        assert!(verify_signatures(&sigs, SignatureScheme::Secp256k1).is_ok());
457    }
458
459    #[test]
460    fn test_verify_signatures_empty() {
461        let sigs: Vec<Signature> = vec![];
462        assert!(verify_signatures(&sigs, SignatureScheme::Secp256k1).is_err());
463    }
464
465    #[test]
466    fn test_verify_signatures_one_invalid() {
467        use secp256k1::{Message, Secp256k1, SecretKey};
468
469        let secp = Secp256k1::new();
470        let message = [0xCD; 32];
471        let msg = Message::from_digest_slice(&message).unwrap();
472
473        // First signature is valid
474        let secret_key = SecretKey::new(&mut secp256k1::rand::thread_rng());
475        let public_key = secp256k1::PublicKey::from_secret_key(&secp, &secret_key);
476        let signature = secp.sign_ecdsa(&msg, &secret_key);
477        let sig_bytes = signature.serialize_compact();
478        let pubkey_bytes = public_key.serialize();
479        let mut sigs = vec![Signature::new(
480            sig_bytes.to_vec(),
481            pubkey_bytes.to_vec(),
482            message.to_vec(),
483        )];
484
485        // Second signature has wrong message length
486        let signature2 = vec![0u8; 64];
487        let public_key2 = vec![0x02; 33];
488        let message2 = vec![0u8; 16];
489        sigs.push(Signature::new(signature2, public_key2, message2));
490
491        assert!(verify_signatures(&sigs, SignatureScheme::Secp256k1).is_err());
492    }
493
494    #[test]
495    fn test_parse_signatures_from_bytes() {
496        let raw_sigs = vec![vec![0xAB; 64], vec![0xCD; 64]];
497        let public_keys = vec![vec![0x02; 33], vec![0x03; 33]];
498        let message = vec![0xEF; 32];
499
500        let signatures = parse_signatures_from_bytes(&raw_sigs, &public_keys, &message);
501
502        assert_eq!(signatures.len(), 2);
503        assert_eq!(signatures[0].signature, vec![0xAB; 64]);
504        assert_eq!(signatures[0].public_key, vec![0x02; 33]);
505        assert_eq!(signatures[1].signature, vec![0xCD; 64]);
506        assert_eq!(signatures[1].public_key, vec![0x03; 33]);
507    }
508
509    #[test]
510    fn test_signature_scheme_debug() {
511        assert_eq!(format!("{:?}", SignatureScheme::Secp256k1), "Secp256k1");
512        assert_eq!(format!("{:?}", SignatureScheme::Ed25519), "Ed25519");
513    }
514}