1use std::future::Future;
2use std::pin::Pin;
3
4use crate::TrustError;
5
6type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum VerifyOutcome {
11 Valid,
12 Invalid,
14}
15
16pub trait Verifier: Send + Sync + 'static {
18 fn verify<'a>(
19 &'a self,
20 region: &'a [u8],
21 sig_value: &'a [u8],
22 public_key: &'a [u8],
23 ) -> BoxFuture<'a, Result<VerifyOutcome, TrustError>>;
24}
25
26pub struct Ed25519Verifier;
28
29impl Ed25519Verifier {
30 pub fn verify_sync(&self, region: &[u8], sig_value: &[u8], public_key: &[u8]) -> VerifyOutcome {
32 use ed25519_dalek::{Signature, Verifier as _, VerifyingKey};
33
34 let Ok(vk) = VerifyingKey::from_bytes(public_key.try_into().unwrap_or(&[0u8; 32])) else {
35 return VerifyOutcome::Invalid;
36 };
37
38 let Ok(sig_bytes): Result<&[u8; 64], _> = sig_value.try_into() else {
39 return VerifyOutcome::Invalid;
40 };
41 let sig = Signature::from_bytes(sig_bytes);
42
43 match vk.verify(region, &sig) {
44 Ok(()) => VerifyOutcome::Valid,
45 Err(_) => VerifyOutcome::Invalid,
46 }
47 }
48}
49
50impl Verifier for Ed25519Verifier {
51 fn verify<'a>(
52 &'a self,
53 region: &'a [u8],
54 sig_value: &'a [u8],
55 public_key: &'a [u8],
56 ) -> BoxFuture<'a, Result<VerifyOutcome, TrustError>> {
57 Box::pin(async move {
58 use ed25519_dalek::{Signature, Verifier as _, VerifyingKey};
59
60 let vk = VerifyingKey::from_bytes(
61 public_key.try_into().map_err(|_| TrustError::InvalidKey)?,
62 )
63 .map_err(|_| TrustError::InvalidKey)?;
64
65 let sig_bytes: &[u8; 64] = sig_value
66 .try_into()
67 .map_err(|_| TrustError::InvalidSignature)?;
68 let sig = Signature::from_bytes(sig_bytes);
69
70 match vk.verify(region, &sig) {
71 Ok(()) => Ok(VerifyOutcome::Valid),
72 Err(_) => Ok(VerifyOutcome::Invalid),
73 }
74 })
75 }
76}
77
78pub fn ed25519_verify_batch(
103 messages: &[&[u8]],
104 signatures: &[&[u8; 64]],
105 public_keys: &[&[u8; 32]],
106) -> Result<VerifyOutcome, TrustError> {
107 use ed25519_dalek::{Signature, VerifyingKey, verify_batch};
108
109 let n = messages.len();
110 if signatures.len() != n || public_keys.len() != n {
111 return Err(TrustError::InvalidSignature);
112 }
113 if n == 0 {
114 return Ok(VerifyOutcome::Valid); }
116
117 let sigs: Vec<Signature> = signatures
120 .iter()
121 .map(|s| Signature::from_bytes(s))
122 .collect();
123
124 let mut keys: Vec<VerifyingKey> = Vec::with_capacity(n);
128 for pk in public_keys {
129 match VerifyingKey::from_bytes(pk) {
130 Ok(vk) => keys.push(vk),
131 Err(_) => return Err(TrustError::InvalidKey),
132 }
133 }
134
135 match verify_batch(messages, &sigs, &keys) {
140 Ok(()) => Ok(VerifyOutcome::Valid),
141 Err(_) => Ok(VerifyOutcome::Invalid),
142 }
143}
144
145pub struct Blake3DigestVerifier;
154
155impl Verifier for Blake3DigestVerifier {
156 fn verify<'a>(
157 &'a self,
158 region: &'a [u8],
159 sig_value: &'a [u8],
160 _public_key: &'a [u8],
161 ) -> BoxFuture<'a, Result<VerifyOutcome, TrustError>> {
162 Box::pin(async move {
163 let Ok(expected): Result<&[u8; 32], _> = sig_value.try_into() else {
164 return Ok(VerifyOutcome::Invalid);
165 };
166 let hash = crate::signer::blake3_hash_auto(region);
167 if hash.as_bytes() == expected {
168 Ok(VerifyOutcome::Valid)
169 } else {
170 Ok(VerifyOutcome::Invalid)
171 }
172 })
173 }
174}
175
176pub struct Blake3KeyedVerifier;
181
182impl Verifier for Blake3KeyedVerifier {
183 fn verify<'a>(
184 &'a self,
185 region: &'a [u8],
186 sig_value: &'a [u8],
187 public_key: &'a [u8],
188 ) -> BoxFuture<'a, Result<VerifyOutcome, TrustError>> {
189 Box::pin(async move {
190 let key: &[u8; 32] = public_key.try_into().map_err(|_| TrustError::InvalidKey)?;
191 let Ok(expected): Result<&[u8; 32], _> = sig_value.try_into() else {
192 return Ok(VerifyOutcome::Invalid);
193 };
194 let hash = crate::signer::blake3_keyed_hash_auto(key, region);
195 if hash.as_bytes() == expected {
196 Ok(VerifyOutcome::Valid)
197 } else {
198 Ok(VerifyOutcome::Invalid)
199 }
200 })
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207 use ed25519_dalek::{Signer as _, SigningKey};
208
209 fn keypair(seed: &[u8; 32]) -> (SigningKey, [u8; 32]) {
210 let sk = SigningKey::from_bytes(seed);
211 let pk = sk.verifying_key().to_bytes();
212 (sk, pk)
213 }
214
215 #[tokio::test]
216 async fn valid_signature_returns_valid() {
217 let (sk, pk) = keypair(&[1u8; 32]);
218 let region = b"signed region";
219 let sig = sk.sign(region).to_bytes();
220 let outcome = Ed25519Verifier.verify(region, &sig, &pk).await.unwrap();
221 assert_eq!(outcome, VerifyOutcome::Valid);
222 }
223
224 #[tokio::test]
225 async fn wrong_signature_returns_invalid() {
226 let (_sk, pk) = keypair(&[1u8; 32]);
227 let region = b"signed region";
228 let bad_sig = [0u8; 64];
229 let outcome = Ed25519Verifier.verify(region, &bad_sig, &pk).await.unwrap();
230 assert_eq!(outcome, VerifyOutcome::Invalid);
231 }
232
233 #[tokio::test]
234 async fn wrong_key_returns_invalid() {
235 let (sk, _) = keypair(&[1u8; 32]);
236 let (_, pk2) = keypair(&[2u8; 32]); let region = b"signed region";
238 let sig = sk.sign(region).to_bytes();
239 let outcome = Ed25519Verifier.verify(region, &sig, &pk2).await.unwrap();
240 assert_eq!(outcome, VerifyOutcome::Invalid);
241 }
242
243 #[tokio::test]
244 async fn short_public_key_returns_err() {
245 let sig = [0u8; 64];
246 let result = Ed25519Verifier.verify(b"region", &sig, &[0u8; 16]).await;
247 assert!(matches!(result, Err(TrustError::InvalidKey)));
248 }
249
250 #[tokio::test]
251 async fn short_signature_returns_err() {
252 let (_, pk) = keypair(&[1u8; 32]);
253 let result = Ed25519Verifier.verify(b"region", &[0u8; 32], &pk).await;
254 assert!(matches!(result, Err(TrustError::InvalidSignature)));
255 }
256
257 #[test]
261 fn batch_all_valid_returns_valid() {
262 let ns: Vec<(SigningKey, [u8; 32], Vec<u8>, [u8; 64])> = (0u8..10)
265 .map(|i| {
266 let (sk, pk) = keypair(&[i; 32]);
267 let msg = format!("message {i}").into_bytes();
268 let sig = sk.sign(&msg).to_bytes();
269 (sk, pk, msg, sig)
270 })
271 .collect();
272 let messages: Vec<&[u8]> = ns.iter().map(|(_, _, m, _)| m.as_slice()).collect();
273 let signatures: Vec<&[u8; 64]> = ns.iter().map(|(_, _, _, s)| s).collect();
274 let public_keys: Vec<&[u8; 32]> = ns.iter().map(|(_, pk, _, _)| pk).collect();
275 let out = ed25519_verify_batch(&messages, &signatures, &public_keys).unwrap();
276 assert_eq!(out, VerifyOutcome::Valid);
277 }
278
279 #[test]
283 fn batch_one_bad_sig_returns_invalid() {
284 let ns: Vec<(SigningKey, [u8; 32], Vec<u8>, [u8; 64])> = (0u8..10)
285 .map(|i| {
286 let (sk, pk) = keypair(&[i; 32]);
287 let msg = format!("message {i}").into_bytes();
288 let sig = sk.sign(&msg).to_bytes();
289 (sk, pk, msg, sig)
290 })
291 .collect();
292 let messages: Vec<&[u8]> = ns.iter().map(|(_, _, m, _)| m.as_slice()).collect();
293 let mut signatures: Vec<[u8; 64]> = ns.iter().map(|(_, _, _, s)| *s).collect();
294 signatures[4][0] ^= 0x80;
296 let sig_refs: Vec<&[u8; 64]> = signatures.iter().collect();
297 let public_keys: Vec<&[u8; 32]> = ns.iter().map(|(_, pk, _, _)| pk).collect();
298 let out = ed25519_verify_batch(&messages, &sig_refs, &public_keys).unwrap();
299 assert_eq!(out, VerifyOutcome::Invalid);
300 }
301
302 #[test]
303 fn batch_length_mismatch_returns_err() {
304 let (sk, pk) = keypair(&[1u8; 32]);
305 let msg: &[u8] = b"a message";
306 let sig = sk.sign(msg).to_bytes();
307 let messages: &[&[u8]] = &[msg, msg];
308 let sigs = [&sig];
309 let keys = [&pk, &pk];
310 let out = ed25519_verify_batch(messages, &sigs, &keys);
311 assert!(matches!(out, Err(TrustError::InvalidSignature)));
312 }
313
314 #[test]
315 fn batch_empty_is_vacuously_valid() {
316 let out = ed25519_verify_batch(&[], &[], &[]).unwrap();
317 assert_eq!(out, VerifyOutcome::Valid);
318 }
319
320 }