ndn_security/zone.rs
1//! Self-certifying namespace primitives for the Named Data Architecture (NDA).
2//!
3//! A **zone** is a namespace whose root name is derived directly from its
4//! signing key — no CA required. Anyone who holds the private key owns the
5//! zone; anyone who knows the zone root name can verify zone-signed content.
6//!
7//! ## Zone root encoding
8//!
9//! ```text
10//! zone_root = Name[ BLAKE3_DIGEST(blake3(public_key_bytes)) ]
11//! ```
12//!
13//! The single name component has TLV type 0x03 (`BLAKE3_DIGEST`) and a
14//! 32-byte value that is the BLAKE3 hash of the raw Ed25519 verifying key.
15//!
16//! **Experimental / NDA extension** — type 0x03 is not yet in the NDN spec.
17
18use std::sync::Arc;
19
20use ndn_packet::Name;
21
22use crate::{Ed25519Signer, Signer};
23
24/// A zone signing key: an Ed25519 key bound to its self-certifying zone root name.
25///
26/// The zone root is computed deterministically from the public key, so this
27/// struct owns both the signing capability and the canonical zone namespace.
28pub struct ZoneKey {
29 signer: Ed25519Signer,
30 zone_root: Name,
31 pub_key_bytes: [u8; 32],
32}
33
34impl ZoneKey {
35 /// Derive a `ZoneKey` from a raw 32-byte Ed25519 seed.
36 ///
37 /// The zone root name is computed as `blake3(verifying_key_bytes)`.
38 pub fn from_seed(seed: &[u8; 32]) -> Self {
39 use ed25519_dalek::SigningKey;
40 let sk = SigningKey::from_bytes(seed);
41 let pub_key_bytes = sk.verifying_key().to_bytes();
42 let zone_root = zone_root_from_pubkey(&pub_key_bytes);
43 let signer = Ed25519Signer::from_seed(seed, zone_root.clone());
44 Self {
45 signer,
46 zone_root,
47 pub_key_bytes,
48 }
49 }
50
51 /// Derive a `ZoneKey` from raw Ed25519 signing-key bytes (32-byte seed).
52 pub fn from_signing_key_bytes(bytes: &[u8; 32]) -> Self {
53 Self::from_seed(bytes)
54 }
55
56 /// The self-certifying zone root name derived from this key.
57 ///
58 /// This is a single-component name containing the BLAKE3 digest of the
59 /// Ed25519 verifying key bytes.
60 pub fn zone_root_name(&self) -> &Name {
61 &self.zone_root
62 }
63
64 /// The raw 32-byte Ed25519 verifying (public) key.
65 pub fn public_key_bytes(&self) -> &[u8; 32] {
66 &self.pub_key_bytes
67 }
68
69 /// The signer — can be used with `DataBuilder::sign()` or `SignWith`.
70 pub fn signer(&self) -> &Ed25519Signer {
71 &self.signer
72 }
73
74 /// Returns an `Arc<dyn Signer>` suitable for storage in a `KeyStore`.
75 pub fn into_arc_signer(self) -> Arc<dyn Signer> {
76 Arc::new(self.signer)
77 }
78
79 /// Derive a child name under this zone root.
80 ///
81 /// Example: if zone root is `/[blake3:abcd…]`, then
82 /// `zone.child_name("/sensor/temp")` returns `/[blake3:abcd…]/sensor/temp`.
83 pub fn child_name(&self, suffix: &str) -> Result<Name, ndn_packet::PacketError> {
84 let suffix: Name = suffix.parse()?;
85 let mut components = self.zone_root.components().to_vec();
86 components.extend_from_slice(suffix.components());
87 Ok(Name::from_components(components))
88 }
89
90 /// The `did:ndn` DID string for this zone root.
91 ///
92 /// Returns `did:ndn:<base64url(Name-TLV)>` — the unified binary encoding.
93 pub fn zone_root_did(&self) -> String {
94 zone_root_to_did(&self.zone_root)
95 }
96
97 /// Verify that a name is a direct child of this zone (has zone root as prefix).
98 pub fn is_zone_child(&self, name: &Name) -> bool {
99 let zc = self.zone_root.components();
100 let nc = name.components();
101 nc.len() > zc.len() && nc[..zc.len()] == *zc
102 }
103}
104
105/// Compute the zone root name for a given Ed25519 verifying key.
106///
107/// The name is a single BLAKE3_DIGEST component containing
108/// `blake3(public_key_bytes)`.
109pub fn zone_root_from_pubkey(public_key_bytes: &[u8]) -> Name {
110 let hash = blake3::hash(public_key_bytes);
111 Name::zone_root_from_hash(*hash.as_bytes())
112}
113
114/// Convert a zone root name to its `did:ndn` DID string representation.
115pub fn zone_root_to_did(zone_root: &Name) -> String {
116 crate::did::name_to_did(zone_root)
117}
118
119/// Verify that a given zone root name matches the expected public key.
120pub fn verify_zone_root(zone_root: &Name, public_key_bytes: &[u8]) -> bool {
121 let expected = zone_root_from_pubkey(public_key_bytes);
122 zone_root == &expected
123}