tlsn_core/
signing.rs

1//! Cryptographic signatures.
2
3use std::collections::HashMap;
4
5use serde::{Deserialize, Serialize};
6
7use crate::hash::impl_domain_separator;
8
9/// Key algorithm identifier.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
11pub struct KeyAlgId(u8);
12
13impl KeyAlgId {
14    /// secp256k1 elliptic curve key algorithm.
15    pub const K256: Self = Self(1);
16    /// NIST P-256 elliptic curve key algorithm.
17    pub const P256: Self = Self(2);
18
19    /// Creates a new key algorithm identifier.
20    ///
21    /// # Panics
22    ///
23    /// Panics if the identifier is in the reserved range 0-127.
24    ///
25    /// # Arguments
26    ///
27    /// * id - Unique identifier for the key algorithm.
28    pub const fn new(id: u8) -> Self {
29        assert!(id >= 128, "key algorithm id range 0-127 is reserved");
30
31        Self(id)
32    }
33
34    /// Returns the id as a `u8`.
35    pub const fn as_u8(&self) -> u8 {
36        self.0
37    }
38}
39
40impl std::fmt::Display for KeyAlgId {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        match *self {
43            KeyAlgId::K256 => write!(f, "k256"),
44            KeyAlgId::P256 => write!(f, "p256"),
45            _ => write!(f, "custom({:02x})", self.0),
46        }
47    }
48}
49
50/// Signature algorithm identifier.
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
52pub struct SignatureAlgId(u8);
53
54impl SignatureAlgId {
55    /// secp256k1 signature algorithm with SHA-256 hashing.
56    pub const SECP256K1: Self = Self(1);
57    /// secp256r1 signature algorithm with SHA-256 hashing.
58    pub const SECP256R1: Self = Self(2);
59    /// Ethereum-compatible signature algorithm.
60    ///
61    /// Uses secp256k1 with Keccak-256 hashing. The signature is a concatenation
62    /// of `r || s || v` as defined in Solidity's ecrecover().
63    pub const SECP256K1ETH: Self = Self(3);
64
65    /// Creates a new signature algorithm identifier.
66    ///
67    /// # Panics
68    ///
69    /// Panics if the identifier is in the reserved range 0-127.
70    ///
71    /// # Arguments
72    ///
73    /// * id - Unique identifier for the signature algorithm.
74    pub const fn new(id: u8) -> Self {
75        assert!(id >= 128, "signature algorithm id range 0-127 is reserved");
76
77        Self(id)
78    }
79
80    /// Returns the id as a `u8`.
81    pub const fn as_u8(&self) -> u8 {
82        self.0
83    }
84}
85
86impl std::fmt::Display for SignatureAlgId {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        match *self {
89            SignatureAlgId::SECP256K1 => write!(f, "secp256k1"),
90            SignatureAlgId::SECP256R1 => write!(f, "secp256r1"),
91            SignatureAlgId::SECP256K1ETH => write!(f, "secp256k1eth"),
92            _ => write!(f, "custom({:02x})", self.0),
93        }
94    }
95}
96
97/// Unknown signature algorithm error.
98#[derive(Debug, thiserror::Error)]
99#[error("unknown signature algorithm id: {0:?}")]
100pub struct UnknownSignatureAlgId(SignatureAlgId);
101
102/// Provider of signers.
103#[derive(Default)]
104pub struct SignerProvider {
105    signers: HashMap<SignatureAlgId, Box<dyn Signer + Send + Sync>>,
106}
107
108impl SignerProvider {
109    /// Returns the supported signature algorithms.
110    pub fn supported_algs(&self) -> impl Iterator<Item = SignatureAlgId> + '_ {
111        self.signers.keys().copied()
112    }
113
114    /// Configures a signer.
115    pub fn set_signer(&mut self, signer: Box<dyn Signer + Send + Sync>) {
116        self.signers.insert(signer.alg_id(), signer);
117    }
118
119    /// Configures a secp256k1 signer with the provided signing key.
120    pub fn set_secp256k1(&mut self, key: &[u8]) -> Result<&mut Self, SignerError> {
121        self.set_signer(Box::new(Secp256k1Signer::new(key)?));
122
123        Ok(self)
124    }
125
126    /// Configures a secp256r1 signer with the provided signing key.
127    pub fn set_secp256r1(&mut self, key: &[u8]) -> Result<&mut Self, SignerError> {
128        self.set_signer(Box::new(Secp256r1Signer::new(key)?));
129
130        Ok(self)
131    }
132
133    /// Configures a secp256k1eth signer with the provided signing key.
134    pub fn set_secp256k1eth(&mut self, key: &[u8]) -> Result<&mut Self, SignerError> {
135        self.set_signer(Box::new(Secp256k1EthSigner::new(key)?));
136
137        Ok(self)
138    }
139
140    /// Returns a signer for the given algorithm.
141    pub(crate) fn get(
142        &self,
143        alg: &SignatureAlgId,
144    ) -> Result<&(dyn Signer + Send + Sync), UnknownSignatureAlgId> {
145        self.signers
146            .get(alg)
147            .map(|s| &**s)
148            .ok_or(UnknownSignatureAlgId(*alg))
149    }
150}
151
152/// Error for [`Signer`].
153#[derive(Debug, thiserror::Error)]
154#[error("signer error: {0}")]
155pub struct SignerError(String);
156
157/// Cryptographic signer.
158pub trait Signer {
159    /// Returns the algorithm used by this signer.
160    fn alg_id(&self) -> SignatureAlgId;
161
162    /// Signs the message.
163    fn sign(&self, msg: &[u8]) -> Result<Signature, SignatureError>;
164
165    /// Returns the verifying key for this signer.
166    fn verifying_key(&self) -> VerifyingKey;
167}
168
169/// Provider of signature verifiers.
170pub struct SignatureVerifierProvider {
171    verifiers: HashMap<SignatureAlgId, Box<dyn SignatureVerifier + Send + Sync>>,
172}
173
174impl Default for SignatureVerifierProvider {
175    fn default() -> Self {
176        let mut verifiers = HashMap::new();
177
178        verifiers.insert(SignatureAlgId::SECP256K1, Box::new(Secp256k1Verifier) as _);
179        verifiers.insert(SignatureAlgId::SECP256R1, Box::new(Secp256r1Verifier) as _);
180        verifiers.insert(
181            SignatureAlgId::SECP256K1ETH,
182            Box::new(Secp256k1EthVerifier) as _,
183        );
184
185        Self { verifiers }
186    }
187}
188
189impl SignatureVerifierProvider {
190    /// Configures a signature verifier.
191    pub fn set_verifier(&mut self, verifier: Box<dyn SignatureVerifier + Send + Sync>) {
192        self.verifiers.insert(verifier.alg_id(), verifier);
193    }
194
195    /// Returns the verifier for the given algorithm.
196    pub(crate) fn get(
197        &self,
198        alg: &SignatureAlgId,
199    ) -> Result<&(dyn SignatureVerifier + Send + Sync), UnknownSignatureAlgId> {
200        self.verifiers
201            .get(alg)
202            .map(|s| &**s)
203            .ok_or(UnknownSignatureAlgId(*alg))
204    }
205}
206
207/// Signature verifier.
208pub trait SignatureVerifier {
209    /// Returns the algorithm used by this verifier.
210    fn alg_id(&self) -> SignatureAlgId;
211
212    /// Verifies the signature.
213    fn verify(&self, key: &VerifyingKey, msg: &[u8], sig: &[u8]) -> Result<(), SignatureError>;
214}
215
216/// Verifying key.
217#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
218pub struct VerifyingKey {
219    /// The key algorithm.
220    pub alg: KeyAlgId,
221    /// The key data.
222    pub data: Vec<u8>,
223}
224
225impl_domain_separator!(VerifyingKey);
226
227/// Error that can occur while verifying a signature.
228#[derive(Debug, thiserror::Error)]
229#[error("signature verification failed: {0}")]
230pub struct SignatureError(String);
231
232/// A signature.
233#[derive(Debug, Clone, Deserialize, Serialize)]
234pub struct Signature {
235    /// The algorithm used to sign the data.
236    pub alg: SignatureAlgId,
237    /// The signature data.
238    pub data: Vec<u8>,
239}
240
241mod secp256k1 {
242    use std::sync::{Arc, Mutex};
243
244    use k256::ecdsa::{
245        signature::{SignerMut, Verifier},
246        Signature as Secp256K1Signature, SigningKey,
247    };
248
249    use super::*;
250
251    /// secp256k1 signer with SHA-256 hashing.
252    pub struct Secp256k1Signer(Arc<Mutex<SigningKey>>);
253
254    impl Secp256k1Signer {
255        /// Creates a new secp256k1 signer with the provided signing key.
256        pub fn new(key: &[u8]) -> Result<Self, SignerError> {
257            SigningKey::from_slice(key)
258                .map(|key| Self(Arc::new(Mutex::new(key))))
259                .map_err(|_| SignerError("invalid key".to_string()))
260        }
261    }
262
263    impl Signer for Secp256k1Signer {
264        fn alg_id(&self) -> SignatureAlgId {
265            SignatureAlgId::SECP256K1
266        }
267
268        fn sign(&self, msg: &[u8]) -> Result<Signature, SignatureError> {
269            let sig: Secp256K1Signature = self.0.lock().unwrap().sign(msg);
270
271            Ok(Signature {
272                alg: SignatureAlgId::SECP256K1,
273                data: sig.to_vec(),
274            })
275        }
276
277        fn verifying_key(&self) -> VerifyingKey {
278            let key = self.0.lock().unwrap().verifying_key().to_sec1_bytes();
279
280            VerifyingKey {
281                alg: KeyAlgId::K256,
282                data: key.to_vec(),
283            }
284        }
285    }
286
287    /// secp256k1 verifier with SHA-256 hashing.
288    pub struct Secp256k1Verifier;
289
290    impl SignatureVerifier for Secp256k1Verifier {
291        fn alg_id(&self) -> SignatureAlgId {
292            SignatureAlgId::SECP256K1
293        }
294
295        fn verify(&self, key: &VerifyingKey, msg: &[u8], sig: &[u8]) -> Result<(), SignatureError> {
296            if key.alg != KeyAlgId::K256 {
297                return Err(SignatureError("key algorithm is not k256".to_string()));
298            }
299
300            let key = k256::ecdsa::VerifyingKey::from_sec1_bytes(&key.data)
301                .map_err(|_| SignatureError("invalid k256 key".to_string()))?;
302
303            let sig = Secp256K1Signature::from_slice(sig)
304                .map_err(|_| SignatureError("invalid secp256k1 signature".to_string()))?;
305
306            key.verify(msg, &sig).map_err(|_| {
307                SignatureError("secp256k1 signature verification failed".to_string())
308            })?;
309
310            Ok(())
311        }
312    }
313}
314
315pub use secp256k1::{Secp256k1Signer, Secp256k1Verifier};
316
317mod secp256r1 {
318    use std::sync::{Arc, Mutex};
319
320    use p256::ecdsa::{
321        signature::{SignerMut, Verifier},
322        Signature as Secp256R1Signature, SigningKey,
323    };
324
325    use super::*;
326
327    /// secp256r1 signer with SHA-256 hashing.
328    pub struct Secp256r1Signer(Arc<Mutex<SigningKey>>);
329
330    impl Secp256r1Signer {
331        /// Creates a new secp256r1 signer with the provided signing key.
332        pub fn new(key: &[u8]) -> Result<Self, SignerError> {
333            SigningKey::from_slice(key)
334                .map(|key| Self(Arc::new(Mutex::new(key))))
335                .map_err(|_| SignerError("invalid key".to_string()))
336        }
337    }
338
339    impl Signer for Secp256r1Signer {
340        fn alg_id(&self) -> SignatureAlgId {
341            SignatureAlgId::SECP256R1
342        }
343
344        fn sign(&self, msg: &[u8]) -> Result<Signature, SignatureError> {
345            let sig: Secp256R1Signature = self.0.lock().unwrap().sign(msg);
346
347            Ok(Signature {
348                alg: SignatureAlgId::SECP256R1,
349                data: sig.to_vec(),
350            })
351        }
352
353        fn verifying_key(&self) -> VerifyingKey {
354            let key = self.0.lock().unwrap().verifying_key().to_sec1_bytes();
355
356            VerifyingKey {
357                alg: KeyAlgId::P256,
358                data: key.to_vec(),
359            }
360        }
361    }
362
363    /// secp256r1 verifier with SHA-256 hashing.
364    pub struct Secp256r1Verifier;
365
366    impl SignatureVerifier for Secp256r1Verifier {
367        fn alg_id(&self) -> SignatureAlgId {
368            SignatureAlgId::SECP256R1
369        }
370
371        fn verify(&self, key: &VerifyingKey, msg: &[u8], sig: &[u8]) -> Result<(), SignatureError> {
372            if key.alg != KeyAlgId::P256 {
373                return Err(SignatureError("key algorithm is not p256".to_string()));
374            }
375
376            let key = p256::ecdsa::VerifyingKey::from_sec1_bytes(&key.data)
377                .map_err(|_| SignatureError("invalid p256 key".to_string()))?;
378
379            let sig = Secp256R1Signature::from_slice(sig)
380                .map_err(|_| SignatureError("invalid secp256r1 signature".to_string()))?;
381
382            key.verify(msg, &sig).map_err(|_| {
383                SignatureError("secp256r1 signature verification failed".to_string())
384            })?;
385
386            Ok(())
387        }
388    }
389}
390
391pub use secp256r1::{Secp256r1Signer, Secp256r1Verifier};
392
393mod secp256k1eth {
394    use std::sync::{Arc, Mutex};
395
396    use k256::ecdsa::{
397        signature::hazmat::PrehashVerifier, Signature as Secp256K1Signature, SigningKey,
398    };
399    use tiny_keccak::{Hasher, Keccak};
400
401    use super::*;
402
403    /// secp256k1eth signer.
404    pub struct Secp256k1EthSigner(Arc<Mutex<SigningKey>>);
405
406    impl Secp256k1EthSigner {
407        /// Creates a new secp256k1eth signer with the provided signing key.
408        pub fn new(key: &[u8]) -> Result<Self, SignerError> {
409            SigningKey::from_slice(key)
410                .map(|key| Self(Arc::new(Mutex::new(key))))
411                .map_err(|_| SignerError("invalid key".to_string()))
412        }
413    }
414
415    impl Signer for Secp256k1EthSigner {
416        fn alg_id(&self) -> SignatureAlgId {
417            SignatureAlgId::SECP256K1ETH
418        }
419
420        fn sign(&self, msg: &[u8]) -> Result<Signature, SignatureError> {
421            // Pre-hash the message.
422            let mut hasher = Keccak::v256();
423            hasher.update(msg);
424            let mut output = vec![0; 32];
425            hasher.finalize(&mut output);
426
427            let (signature, recid) = self
428                .0
429                .lock()
430                .unwrap()
431                .sign_prehash_recoverable(&output)
432                .map_err(|_| SignatureError("error in sign_prehash_recoverable".to_string()))?;
433
434            let mut sig = signature.to_vec();
435            let recid = recid.to_byte();
436
437            // Based on Ethereum Yellow Paper Appendix F, only values 0 and 1 are valid.
438            if recid > 1 {
439                return Err(SignatureError(format!(
440                    "expected recovery id 0 or 1, got {:?}",
441                    recid
442                )));
443            }
444            // `ecrecover` expects that 0 and 1 are mapped to 27 and 28.
445            sig.push(recid + 27);
446
447            Ok(Signature {
448                alg: SignatureAlgId::SECP256K1ETH,
449                data: sig,
450            })
451        }
452
453        fn verifying_key(&self) -> VerifyingKey {
454            let key = self.0.lock().unwrap().verifying_key().to_sec1_bytes();
455
456            VerifyingKey {
457                alg: KeyAlgId::K256,
458                data: key.to_vec(),
459            }
460        }
461    }
462
463    /// secp256k1eth verifier.
464    pub struct Secp256k1EthVerifier;
465
466    impl SignatureVerifier for Secp256k1EthVerifier {
467        fn alg_id(&self) -> SignatureAlgId {
468            SignatureAlgId::SECP256K1ETH
469        }
470
471        fn verify(&self, key: &VerifyingKey, msg: &[u8], sig: &[u8]) -> Result<(), SignatureError> {
472            if key.alg != KeyAlgId::K256 {
473                return Err(SignatureError("key algorithm is not k256".to_string()));
474            }
475
476            if sig.len() != 65 {
477                return Err(SignatureError(
478                    "ethereum signature length must be 65 bytes".to_string(),
479                ));
480            }
481
482            let key = k256::ecdsa::VerifyingKey::from_sec1_bytes(&key.data)
483                .map_err(|_| SignatureError("invalid k256 key".to_string()))?;
484
485            // `sig` is a concatenation of `r || s || v`. We ignore `v` since it is only
486            // useful when recovering the verifying key.
487            let sig = Secp256K1Signature::from_slice(&sig[..64])
488                .map_err(|_| SignatureError("invalid secp256k1 signature".to_string()))?;
489
490            // Pre-hash the message.
491            let mut hasher = Keccak::v256();
492            hasher.update(msg);
493            let mut output = vec![0; 32];
494            hasher.finalize(&mut output);
495
496            key.verify_prehash(&output, &sig).map_err(|_| {
497                SignatureError("secp256k1 signature verification failed".to_string())
498            })?;
499
500            Ok(())
501        }
502    }
503}
504
505pub use secp256k1eth::{Secp256k1EthSigner, Secp256k1EthVerifier};
506
507#[cfg(test)]
508mod test {
509    use alloy_primitives::utils::eip191_message;
510    use alloy_signer::SignerSync;
511    use alloy_signer_local::PrivateKeySigner;
512    use rand06_compat::Rand0_6CompatExt;
513    use rstest::{fixture, rstest};
514
515    use super::*;
516
517    #[fixture]
518    #[once]
519    fn secp256k1_pair() -> (Box<dyn Signer>, Box<dyn SignatureVerifier>) {
520        let signing_key = k256::ecdsa::SigningKey::random(&mut rand::rng().compat());
521        (
522            Box::new(Secp256k1Signer::new(&signing_key.to_bytes()).unwrap()),
523            Box::new(Secp256k1Verifier {}),
524        )
525    }
526
527    #[fixture]
528    #[once]
529    fn secp256r1_pair() -> (Box<dyn Signer>, Box<dyn SignatureVerifier>) {
530        let signing_key = p256::ecdsa::SigningKey::random(&mut rand::rng().compat());
531        (
532            Box::new(Secp256r1Signer::new(&signing_key.to_bytes()).unwrap()),
533            Box::new(Secp256r1Verifier {}),
534        )
535    }
536
537    #[fixture]
538    #[once]
539    fn secp256k1eth_pair() -> (Box<dyn Signer>, Box<dyn SignatureVerifier>) {
540        let signing_key = k256::ecdsa::SigningKey::random(&mut rand::rng().compat());
541        (
542            Box::new(Secp256k1EthSigner::new(&signing_key.to_bytes()).unwrap()),
543            Box::new(Secp256k1EthVerifier {}),
544        )
545    }
546
547    #[rstest]
548    #[case::r1(secp256r1_pair(), SignatureAlgId::SECP256R1)]
549    #[case::k1(secp256k1_pair(), SignatureAlgId::SECP256K1)]
550    #[case::k1eth(secp256k1eth_pair(), SignatureAlgId::SECP256K1ETH)]
551    fn test_success(
552        #[case] pair: (Box<dyn Signer>, Box<dyn SignatureVerifier>),
553        #[case] alg: SignatureAlgId,
554    ) {
555        let (signer, verifier) = pair;
556        assert_eq!(signer.alg_id(), alg);
557
558        let msg = "test payload";
559        let signature = signer.sign(msg.as_bytes()).unwrap();
560        let verifying_key = signer.verifying_key();
561
562        assert_eq!(verifier.alg_id(), alg);
563        let result = verifier.verify(&verifying_key, msg.as_bytes(), &signature.data);
564        assert!(result.is_ok());
565    }
566
567    #[rstest]
568    #[case::r1(secp256r1_pair())]
569    #[case::k1eth(secp256k1eth_pair())]
570    fn test_wrong_signer(#[case] pair: (Box<dyn Signer>, Box<dyn SignatureVerifier>)) {
571        let (signer, _) = pair;
572
573        let msg = "test payload";
574        let signature = signer.sign(msg.as_bytes()).unwrap();
575        let verifying_key = signer.verifying_key();
576
577        let verifier = Secp256k1Verifier {};
578        let result = verifier.verify(&verifying_key, msg.as_bytes(), &signature.data);
579        assert!(result.is_err());
580    }
581
582    #[rstest]
583    #[case::corrupted_signature_r1(secp256r1_pair(), true, false)]
584    #[case::corrupted_signature_k1(secp256k1_pair(), true, false)]
585    #[case::corrupted_signature_k1eth(secp256k1eth_pair(), true, false)]
586    #[case::wrong_signature_r1(secp256r1_pair(), false, true)]
587    #[case::wrong_signature_k1(secp256k1_pair(), false, true)]
588    #[case::wrong_signature_k1eth(secp256k1eth_pair(), false, true)]
589    fn test_failure(
590        #[case] pair: (Box<dyn Signer>, Box<dyn SignatureVerifier>),
591        #[case] corrupted_signature: bool,
592        #[case] wrong_signature: bool,
593    ) {
594        let (signer, verifier) = pair;
595
596        let msg = "test payload";
597        let mut signature = signer.sign(msg.as_bytes()).unwrap();
598        let verifying_key = signer.verifying_key();
599
600        if corrupted_signature {
601            signature.data.push(0);
602        }
603
604        if wrong_signature {
605            signature = signer.sign("different payload".as_bytes()).unwrap();
606        }
607
608        let result = verifier.verify(&verifying_key, msg.as_bytes(), &signature.data);
609        assert!(result.is_err());
610    }
611
612    #[test]
613    // Tests secp256k1eth signatures against a reference implementation.
614    fn test_secp256k1eth_sig() {
615        // An arbitrary signing key.
616        let sk = vec![1; 32];
617        let mut msg = "test message".as_bytes().to_vec();
618
619        let signer: Secp256k1EthSigner = Secp256k1EthSigner::new(&sk).unwrap();
620
621        // Testing multiple signatures.
622        for i in 0..10 {
623            msg.push(i);
624            // Convert to EIP-191 since the reference signer can't sign raw bytes.
625            let sig = signer.sign(&eip191_message(&msg)).unwrap().data;
626
627            assert_eq!(sig, reference_eth_signature(&sk, &msg));
628        }
629    }
630
631    // Returns a reference Ethereum signature.
632    fn reference_eth_signature(sk: &[u8], msg: &[u8]) -> Vec<u8> {
633        let signer = PrivateKeySigner::from_slice(sk).unwrap();
634        signer.sign_message_sync(msg).unwrap().as_bytes().to_vec()
635    }
636}