1use std::future::Future;
2use std::pin::Pin;
3
4use crate::TrustError;
5use bytes::Bytes;
6use ndn_packet::{Name, SignatureType};
7
8type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
9
10pub trait Signer: Send + Sync + 'static {
15 fn sig_type(&self) -> SignatureType;
16 fn key_name(&self) -> &Name;
17 fn cert_name(&self) -> Option<&Name> {
19 None
20 }
21 fn public_key(&self) -> Option<Bytes> {
23 None
24 }
25
26 fn sign<'a>(&'a self, region: &'a [u8]) -> BoxFuture<'a, Result<Bytes, TrustError>>;
27
28 fn sign_sync(&self, region: &[u8]) -> Result<Bytes, TrustError> {
32 let _ = region;
33 unimplemented!(
34 "sign_sync not implemented for this signer — override if signing is CPU-only"
35 )
36 }
37}
38
39pub struct Ed25519Signer {
41 signing_key: ed25519_dalek::SigningKey,
42 key_name: Name,
43 cert_name: Option<Name>,
44}
45
46impl Ed25519Signer {
47 pub fn new(
48 signing_key: ed25519_dalek::SigningKey,
49 key_name: Name,
50 cert_name: Option<Name>,
51 ) -> Self {
52 Self {
53 signing_key,
54 key_name,
55 cert_name,
56 }
57 }
58
59 pub fn from_seed(seed: &[u8; 32], key_name: Name) -> Self {
61 let signing_key = ed25519_dalek::SigningKey::from_bytes(seed);
62 Self::new(signing_key, key_name, None)
63 }
64
65 pub fn public_key_bytes(&self) -> [u8; 32] {
67 self.signing_key.verifying_key().to_bytes()
68 }
69}
70
71impl Signer for Ed25519Signer {
72 fn sig_type(&self) -> SignatureType {
73 SignatureType::SignatureEd25519
74 }
75
76 fn key_name(&self) -> &Name {
77 &self.key_name
78 }
79
80 fn cert_name(&self) -> Option<&Name> {
81 self.cert_name.as_ref()
82 }
83
84 fn public_key(&self) -> Option<Bytes> {
85 Some(Bytes::copy_from_slice(&self.public_key_bytes()))
86 }
87
88 fn sign<'a>(&'a self, region: &'a [u8]) -> BoxFuture<'a, Result<Bytes, TrustError>> {
89 Box::pin(async move { self.sign_sync(region) })
90 }
91
92 fn sign_sync(&self, region: &[u8]) -> Result<Bytes, TrustError> {
93 use ed25519_dalek::Signer as _;
94 let sig = self.signing_key.sign(region);
95 Ok(Bytes::copy_from_slice(&sig.to_bytes()))
96 }
97}
98
99pub struct HmacSha256Signer {
104 key: ring::hmac::Key,
105 key_name: Name,
106}
107
108impl HmacSha256Signer {
109 pub fn new(key_bytes: &[u8], key_name: Name) -> Self {
111 Self {
112 key: ring::hmac::Key::new(ring::hmac::HMAC_SHA256, key_bytes),
113 key_name,
114 }
115 }
116}
117
118impl Signer for HmacSha256Signer {
119 fn sig_type(&self) -> SignatureType {
120 SignatureType::SignatureHmacWithSha256
121 }
122
123 fn key_name(&self) -> &Name {
124 &self.key_name
125 }
126
127 fn sign<'a>(&'a self, region: &'a [u8]) -> BoxFuture<'a, Result<Bytes, TrustError>> {
128 Box::pin(async move { self.sign_sync(region) })
129 }
130
131 fn sign_sync(&self, region: &[u8]) -> Result<Bytes, TrustError> {
132 let tag = ring::hmac::sign(&self.key, region);
133 Ok(Bytes::copy_from_slice(tag.as_ref()))
134 }
135}
136
137pub const SIGNATURE_TYPE_DIGEST_BLAKE3_PLAIN: u64 = 6;
161
162pub const SIGNATURE_TYPE_DIGEST_BLAKE3_KEYED: u64 = 7;
168
169pub struct Blake3Signer {
182 key_name: Name,
183}
184
185impl Blake3Signer {
186 pub fn new(key_name: Name) -> Self {
187 Self { key_name }
188 }
189}
190
191impl Signer for Blake3Signer {
192 fn sig_type(&self) -> SignatureType {
193 SignatureType::Other(SIGNATURE_TYPE_DIGEST_BLAKE3_PLAIN)
194 }
195
196 fn key_name(&self) -> &Name {
197 &self.key_name
198 }
199
200 fn sign<'a>(&'a self, region: &'a [u8]) -> BoxFuture<'a, Result<Bytes, TrustError>> {
201 Box::pin(async move { self.sign_sync(region) })
202 }
203
204 fn sign_sync(&self, region: &[u8]) -> Result<Bytes, TrustError> {
205 let hash = blake3_hash_auto(region);
206 Ok(Bytes::copy_from_slice(hash.as_bytes()))
207 }
208}
209
210pub const BLAKE3_RAYON_THRESHOLD: usize = 128 * 1024;
219
220pub fn blake3_hash_auto(region: &[u8]) -> blake3::Hash {
227 if region.len() >= BLAKE3_RAYON_THRESHOLD {
228 let mut h = blake3::Hasher::new();
229 h.update_rayon(region);
230 h.finalize()
231 } else {
232 blake3::hash(region)
233 }
234}
235
236pub fn blake3_keyed_hash_auto(key: &[u8; 32], region: &[u8]) -> blake3::Hash {
240 if region.len() >= BLAKE3_RAYON_THRESHOLD {
241 let mut h = blake3::Hasher::new_keyed(key);
242 h.update_rayon(region);
243 h.finalize()
244 } else {
245 blake3::keyed_hash(key, region)
246 }
247}
248
249pub struct Blake3KeyedSigner {
258 key: [u8; 32],
259 key_name: Name,
260}
261
262impl Blake3KeyedSigner {
263 pub fn new(key: [u8; 32], key_name: Name) -> Self {
269 Self { key, key_name }
270 }
271}
272
273impl Signer for Blake3KeyedSigner {
274 fn sig_type(&self) -> SignatureType {
275 SignatureType::Other(SIGNATURE_TYPE_DIGEST_BLAKE3_KEYED)
276 }
277
278 fn key_name(&self) -> &Name {
279 &self.key_name
280 }
281
282 fn sign<'a>(&'a self, region: &'a [u8]) -> BoxFuture<'a, Result<Bytes, TrustError>> {
283 Box::pin(async move { self.sign_sync(region) })
284 }
285
286 fn sign_sync(&self, region: &[u8]) -> Result<Bytes, TrustError> {
287 let hash = blake3_keyed_hash_auto(&self.key, region);
288 Ok(Bytes::copy_from_slice(hash.as_bytes()))
289 }
290}
291
292#[cfg(test)]
293mod tests {
294 use super::*;
295 use ndn_packet::NameComponent;
296
297 fn test_key_name() -> Name {
298 Name::from_components([NameComponent::generic(bytes::Bytes::from_static(
299 b"testkey",
300 ))])
301 }
302
303 #[tokio::test]
304 async fn sig_type_is_ed25519() {
305 let s = Ed25519Signer::from_seed(&[1u8; 32], test_key_name());
306 assert_eq!(s.sig_type(), SignatureType::SignatureEd25519);
307 }
308
309 #[tokio::test]
310 async fn sign_produces_64_bytes() {
311 let s = Ed25519Signer::from_seed(&[2u8; 32], test_key_name());
312 let sig = s.sign(b"hello ndn").await.unwrap();
313 assert_eq!(sig.len(), 64);
314 }
315
316 #[tokio::test]
317 async fn deterministic_signature() {
318 let seed = [3u8; 32];
319 let s1 = Ed25519Signer::from_seed(&seed, test_key_name());
320 let s2 = Ed25519Signer::from_seed(&seed, test_key_name());
321 let sig1 = s1.sign(b"region").await.unwrap();
322 let sig2 = s2.sign(b"region").await.unwrap();
323 assert_eq!(sig1, sig2);
324 }
325
326 #[tokio::test]
327 async fn different_region_different_signature() {
328 let s = Ed25519Signer::from_seed(&[4u8; 32], test_key_name());
329 let sig1 = s.sign(b"region-a").await.unwrap();
330 let sig2 = s.sign(b"region-b").await.unwrap();
331 assert_ne!(sig1, sig2);
332 }
333
334 #[test]
335 fn key_name_accessor() {
336 let name = test_key_name();
337 let s = Ed25519Signer::from_seed(&[0u8; 32], name.clone());
338 assert_eq!(s.key_name(), &name);
339 }
340
341 #[test]
342 fn cert_name_defaults_to_none() {
343 let s = Ed25519Signer::from_seed(&[0u8; 32], test_key_name());
344 assert!(s.cert_name().is_none());
345 }
346
347 #[test]
350 fn hmac_sig_type() {
351 let s = HmacSha256Signer::new(b"secret", test_key_name());
352 assert_eq!(s.sig_type(), SignatureType::SignatureHmacWithSha256);
353 }
354
355 #[test]
356 fn hmac_sign_sync_produces_32_bytes() {
357 let s = HmacSha256Signer::new(b"secret", test_key_name());
358 let sig = s.sign_sync(b"hello ndn").unwrap();
359 assert_eq!(sig.len(), 32);
360 }
361
362 #[test]
363 fn hmac_deterministic() {
364 let s1 = HmacSha256Signer::new(b"key", test_key_name());
365 let s2 = HmacSha256Signer::new(b"key", test_key_name());
366 assert_eq!(
367 s1.sign_sync(b"data").unwrap(),
368 s2.sign_sync(b"data").unwrap()
369 );
370 }
371
372 #[test]
373 fn hmac_different_key_different_sig() {
374 let s1 = HmacSha256Signer::new(b"key-a", test_key_name());
375 let s2 = HmacSha256Signer::new(b"key-b", test_key_name());
376 assert_ne!(
377 s1.sign_sync(b"data").unwrap(),
378 s2.sign_sync(b"data").unwrap()
379 );
380 }
381
382 #[tokio::test]
383 async fn hmac_async_matches_sync() {
384 let s = HmacSha256Signer::new(b"key", test_key_name());
385 let async_sig = s.sign(b"data").await.unwrap();
386 let sync_sig = s.sign_sync(b"data").unwrap();
387 assert_eq!(async_sig, sync_sig);
388 }
389
390 #[test]
393 fn ed25519_sign_sync_produces_64_bytes() {
394 let s = Ed25519Signer::from_seed(&[2u8; 32], test_key_name());
395 let sig = s.sign_sync(b"hello ndn").unwrap();
396 assert_eq!(sig.len(), 64);
397 }
398
399 #[tokio::test]
400 async fn ed25519_async_matches_sync() {
401 let s = Ed25519Signer::from_seed(&[5u8; 32], test_key_name());
402 let async_sig = s.sign(b"data").await.unwrap();
403 let sync_sig = s.sign_sync(b"data").unwrap();
404 assert_eq!(async_sig, sync_sig);
405 }
406
407 #[test]
415 fn blake3_plain_and_keyed_use_distinct_sig_types() {
416 let plain = Blake3Signer::new(test_key_name());
417 let keyed = Blake3KeyedSigner::new([9u8; 32], test_key_name());
418 assert_eq!(
419 plain.sig_type(),
420 SignatureType::Other(SIGNATURE_TYPE_DIGEST_BLAKE3_PLAIN)
421 );
422 assert_eq!(
423 keyed.sig_type(),
424 SignatureType::Other(SIGNATURE_TYPE_DIGEST_BLAKE3_KEYED)
425 );
426 assert_ne!(
427 plain.sig_type(),
428 keyed.sig_type(),
429 "plain and keyed BLAKE3 must not share a type code"
430 );
431 }
432
433 #[test]
437 fn blake3_sig_type_code_values_are_pinned() {
438 assert_eq!(SIGNATURE_TYPE_DIGEST_BLAKE3_PLAIN, 6);
439 assert_eq!(SIGNATURE_TYPE_DIGEST_BLAKE3_KEYED, 7);
440 }
441
442 #[test]
443 fn blake3_plain_produces_32_bytes() {
444 let s = Blake3Signer::new(test_key_name());
445 let sig = s.sign_sync(b"hello ndn").unwrap();
446 assert_eq!(sig.len(), 32);
447 }
448
449 #[test]
450 fn blake3_keyed_produces_32_bytes() {
451 let s = Blake3KeyedSigner::new([1u8; 32], test_key_name());
452 let sig = s.sign_sync(b"hello ndn").unwrap();
453 assert_eq!(sig.len(), 32);
454 }
455
456 #[test]
460 fn blake3_keyed_different_key_different_sig() {
461 let s1 = Blake3KeyedSigner::new([1u8; 32], test_key_name());
462 let s2 = Blake3KeyedSigner::new([2u8; 32], test_key_name());
463 assert_ne!(
464 s1.sign_sync(b"data").unwrap(),
465 s2.sign_sync(b"data").unwrap()
466 );
467 }
468
469 #[test]
477 fn blake3_plain_and_keyed_with_zero_key_differ() {
478 let plain = Blake3Signer::new(test_key_name());
479 let keyed = Blake3KeyedSigner::new([0u8; 32], test_key_name());
480 assert_ne!(
481 plain.sign_sync(b"region").unwrap(),
482 keyed.sign_sync(b"region").unwrap()
483 );
484 }
485}