Skip to main content

quorum_crypto_core/
verifier.rs

1//! Signature verification traits and registry.
2//!
3//! [`AuditVerifier`] is stateless — it verifies signatures given the algorithm,
4//! message, signature bytes, and public key bytes. Used for cold-start replay
5//! and cross-agent verification.
6//!
7//! [`VerifierRegistry`] maps algorithm strings to verifier implementations.
8
9use crate::CryptoError;
10use std::collections::HashMap;
11use std::fmt::Debug;
12use std::sync::Arc;
13
14/// Stateless signature verifier.
15///
16/// Unlike [`AuditSigner`] (which holds a private key), verifiers are stateless
17/// and can verify any message given the algorithm, signature, and public key.
18pub trait AuditVerifier: Send + Sync + Debug {
19    /// Algorithm this verifier handles (e.g., "ed25519", "secp256k1").
20    fn algorithm(&self) -> &str;
21
22    /// Verify a signature.
23    fn verify(
24        &self,
25        message: &[u8],
26        signature: &[u8],
27        public_key: &[u8],
28    ) -> Result<bool, CryptoError>;
29}
30
31/// Registry mapping algorithm names to verifier implementations.
32///
33/// Used to verify signatures from unknown agents during cold-start replay
34/// or cross-orchestrator verification.
35#[derive(Debug, Default)]
36pub struct VerifierRegistry {
37    verifiers: HashMap<String, Arc<dyn AuditVerifier>>,
38}
39
40impl VerifierRegistry {
41    /// Create an empty registry.
42    pub fn new() -> Self {
43        Self::default()
44    }
45
46    /// Create a registry pre-populated with Ed25519 and Secp256k1 verifiers.
47    pub fn with_defaults() -> Self {
48        let mut registry = Self::new();
49        registry.register(Arc::new(Ed25519Verifier));
50        registry.register(Arc::new(Secp256k1Verifier));
51        registry
52    }
53
54    /// Register a verifier for its algorithm.
55    pub fn register(&mut self, verifier: Arc<dyn AuditVerifier>) {
56        self.verifiers
57            .insert(verifier.algorithm().to_string(), verifier);
58    }
59
60    /// Verify a signature using the appropriate verifier.
61    pub fn verify(
62        &self,
63        algorithm: &str,
64        message: &[u8],
65        signature: &[u8],
66        public_key: &[u8],
67    ) -> Result<bool, CryptoError> {
68        let verifier = self
69            .verifiers
70            .get(algorithm)
71            .ok_or_else(|| CryptoError::UnknownAlgorithm(algorithm.to_string()))?;
72        verifier.verify(message, signature, public_key)
73    }
74
75    /// List registered algorithms.
76    pub fn algorithms(&self) -> Vec<&str> {
77        self.verifiers.keys().map(|s| s.as_str()).collect()
78    }
79}
80
81// ---------------------------------------------------------------------------
82// Built-in verifiers
83// ---------------------------------------------------------------------------
84
85/// Ed25519 signature verifier.
86#[derive(Debug)]
87pub struct Ed25519Verifier;
88
89impl AuditVerifier for Ed25519Verifier {
90    fn algorithm(&self) -> &str {
91        "ed25519"
92    }
93
94    fn verify(
95        &self,
96        message: &[u8],
97        signature: &[u8],
98        public_key: &[u8],
99    ) -> Result<bool, CryptoError> {
100        use ed25519_dalek::Verifier;
101
102        let pubkey_bytes: [u8; 32] = public_key
103            .try_into()
104            .map_err(|_| CryptoError::InvalidKey("Ed25519 public key must be 32 bytes".into()))?;
105        let sig_bytes: [u8; 64] = signature.try_into().map_err(|_| {
106            CryptoError::VerificationFailed("Ed25519 signature must be 64 bytes".into())
107        })?;
108
109        let pubkey = ed25519_dalek::VerifyingKey::from_bytes(&pubkey_bytes)
110            .map_err(|e| CryptoError::InvalidKey(format!("Invalid Ed25519 public key: {e}")))?;
111        let sig = ed25519_dalek::Signature::from_bytes(&sig_bytes);
112
113        match pubkey.verify(message, &sig) {
114            Ok(()) => Ok(true),
115            Err(_) => Ok(false),
116        }
117    }
118}
119
120/// Secp256k1 ECDSA signature verifier.
121#[derive(Debug)]
122pub struct Secp256k1Verifier;
123
124impl AuditVerifier for Secp256k1Verifier {
125    fn algorithm(&self) -> &str {
126        "secp256k1"
127    }
128
129    /// Verify a secp256k1 signature.
130    ///
131    /// Accepts both 64-byte raw ECDSA signatures (from `sign()`) and 65-byte
132    /// recoverable signatures (from `sign_typed()` — the recovery byte `v` is
133    /// stripped before verification).
134    fn verify(
135        &self,
136        message: &[u8],
137        signature: &[u8],
138        public_key: &[u8],
139    ) -> Result<bool, CryptoError> {
140        use k256::ecdsa::signature::Verifier;
141        use k256::ecdsa::VerifyingKey;
142
143        let pubkey = VerifyingKey::from_sec1_bytes(public_key)
144            .map_err(|e| CryptoError::InvalidKey(format!("Invalid secp256k1 public key: {e}")))?;
145
146        // Handle both 64-byte (raw) and 65-byte (recoverable, strip v) signatures
147        let sig_bytes = if signature.len() == 65 {
148            &signature[..64] // strip recovery byte v
149        } else {
150            signature
151        };
152        let sig = k256::ecdsa::Signature::from_slice(sig_bytes).map_err(|e| {
153            CryptoError::VerificationFailed(format!("Invalid secp256k1 signature: {e}"))
154        })?;
155
156        match pubkey.verify(message, &sig) {
157            Ok(()) => Ok(true),
158            Err(_) => Ok(false),
159        }
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166    use crate::signer::{AuditSigner, Ed25519Signer, Secp256k1Signer};
167
168    #[tokio::test]
169    async fn ed25519_verifier_roundtrip() {
170        let signer = Ed25519Signer::generate();
171        let message = b"test message";
172        let sig = signer.sign(message).await.unwrap();
173
174        let verifier = Ed25519Verifier;
175        assert!(verifier
176            .verify(message, &sig, &signer.public_key_bytes())
177            .unwrap());
178    }
179
180    #[tokio::test]
181    async fn ed25519_verifier_rejects_wrong_message() {
182        let signer = Ed25519Signer::generate();
183        let sig = signer.sign(b"correct").await.unwrap();
184
185        let verifier = Ed25519Verifier;
186        assert!(!verifier
187            .verify(b"wrong", &sig, &signer.public_key_bytes())
188            .unwrap());
189    }
190
191    #[tokio::test]
192    async fn secp256k1_verifier_roundtrip() {
193        let signer = Secp256k1Signer::generate();
194        let message = b"test message";
195        let sig = signer.sign(message).await.unwrap();
196
197        let verifier = Secp256k1Verifier;
198        assert!(verifier
199            .verify(message, &sig, &signer.public_key_bytes())
200            .unwrap());
201    }
202
203    #[tokio::test]
204    async fn secp256k1_verifier_rejects_wrong_key() {
205        let signer = Secp256k1Signer::generate();
206        let other = Secp256k1Signer::generate();
207        let sig = signer.sign(b"test").await.unwrap();
208
209        let verifier = Secp256k1Verifier;
210        assert!(!verifier
211            .verify(b"test", &sig, &other.public_key_bytes())
212            .unwrap());
213    }
214
215    #[tokio::test]
216    async fn registry_with_defaults_verifies_both() {
217        let registry = VerifierRegistry::with_defaults();
218
219        let ed = Ed25519Signer::generate();
220        let ed_sig = ed.sign(b"hello").await.unwrap();
221        assert!(registry
222            .verify("ed25519", b"hello", &ed_sig, &ed.public_key_bytes())
223            .unwrap());
224
225        let secp = Secp256k1Signer::generate();
226        let secp_sig = secp.sign(b"hello").await.unwrap();
227        assert!(registry
228            .verify("secp256k1", b"hello", &secp_sig, &secp.public_key_bytes())
229            .unwrap());
230    }
231
232    #[test]
233    fn registry_unknown_algorithm_errors() {
234        let registry = VerifierRegistry::new();
235        let result = registry.verify("unknown", b"msg", b"sig", b"key");
236        assert!(result.is_err());
237    }
238
239    #[test]
240    fn ed25519_verifier_rejects_invalid_key_size() {
241        let verifier = Ed25519Verifier;
242        let result = verifier.verify(b"msg", &[0u8; 64], &[0u8; 16]); // wrong key size
243        assert!(result.is_err());
244        assert!(matches!(result.unwrap_err(), CryptoError::InvalidKey(_)));
245    }
246
247    #[test]
248    fn ed25519_verifier_rejects_invalid_sig_size() {
249        let verifier = Ed25519Verifier;
250        let result = verifier.verify(b"msg", &[0u8; 32], &[0u8; 32]); // wrong sig size
251        assert!(result.is_err());
252    }
253
254    #[test]
255    fn secp256k1_verifier_rejects_invalid_key() {
256        let verifier = Secp256k1Verifier;
257        let result = verifier.verify(b"msg", &[0u8; 64], &[0u8; 5]); // garbage key
258        assert!(result.is_err());
259    }
260
261    #[test]
262    fn registry_algorithms_lists_registered() {
263        let registry = VerifierRegistry::with_defaults();
264        let algos = registry.algorithms();
265        assert!(algos.contains(&"ed25519"));
266        assert!(algos.contains(&"secp256k1"));
267    }
268
269    #[test]
270    fn empty_registry_has_no_algorithms() {
271        let registry = VerifierRegistry::new();
272        assert!(registry.algorithms().is_empty());
273    }
274}