Major feature addition. For full details read `./docs/development_history/DISTRIBUTION.md`
84 lines
2.8 KiB
Rust
84 lines
2.8 KiB
Rust
use ed25519_dalek::{Signer, Verifier};
|
|
|
|
use crate::types::{DirectoryEntry, DirectoryEntryPayload, NodeId, Signature};
|
|
|
|
// ─── Keypair ────────────────────────────────────────────────────────────────
|
|
|
|
/// Node identity keypair — wraps ed25519-dalek.
|
|
pub struct Keypair {
|
|
inner: ed25519_dalek::SigningKey,
|
|
}
|
|
|
|
impl Keypair {
|
|
/// Generate a new random keypair.
|
|
pub fn generate() -> Self {
|
|
let mut csprng = rand_core::OsRng;
|
|
Self {
|
|
inner: ed25519_dalek::SigningKey::generate(&mut csprng),
|
|
}
|
|
}
|
|
|
|
/// Reconstruct from raw secret key bytes (32 bytes).
|
|
pub fn from_bytes(secret: &[u8; 32]) -> Self {
|
|
Self {
|
|
inner: ed25519_dalek::SigningKey::from_bytes(secret),
|
|
}
|
|
}
|
|
|
|
/// The public key as a `NodeId`.
|
|
pub fn node_id(&self) -> NodeId {
|
|
NodeId(self.inner.verifying_key().to_bytes())
|
|
}
|
|
|
|
/// Raw secret key bytes.
|
|
pub fn secret_bytes(&self) -> [u8; 32] {
|
|
self.inner.to_bytes()
|
|
}
|
|
|
|
/// Sign arbitrary bytes.
|
|
pub fn sign(&self, msg: &[u8]) -> Signature {
|
|
let sig = self.inner.sign(msg);
|
|
Signature(sig.to_bytes())
|
|
}
|
|
|
|
/// Sign a directory entry payload, returning a complete `DirectoryEntry`.
|
|
pub fn sign_directory_entry(
|
|
&self,
|
|
actor_addr: swactor::actor::ActorAddress,
|
|
generation: u64,
|
|
) -> DirectoryEntry {
|
|
let payload = DirectoryEntryPayload {
|
|
actor_addr,
|
|
node_id: self.node_id(),
|
|
generation,
|
|
};
|
|
let bytes = serde_json::to_vec(&payload).expect("DirectoryEntryPayload is always serializable");
|
|
let signature = self.sign(&bytes);
|
|
DirectoryEntry {
|
|
actor_addr,
|
|
node_id: self.node_id(),
|
|
generation,
|
|
signature,
|
|
}
|
|
}
|
|
}
|
|
|
|
// ─── Verification ───────────────────────────────────────────────────────────
|
|
|
|
/// Verify a signature against a `NodeId` (public key) and message bytes.
|
|
pub fn verify(node_id: &NodeId, msg: &[u8], sig: &Signature) -> bool {
|
|
let Ok(vk) = ed25519_dalek::VerifyingKey::from_bytes(&node_id.0) else {
|
|
return false;
|
|
};
|
|
let signature = ed25519_dalek::Signature::from_bytes(&sig.0);
|
|
vk.verify(msg, &signature).is_ok()
|
|
}
|
|
|
|
/// Verify a `DirectoryEntry`'s signature against its embedded `node_id`.
|
|
pub fn verify_directory_entry(entry: &DirectoryEntry) -> bool {
|
|
let payload = entry.payload();
|
|
let Ok(bytes) = serde_json::to_vec(&payload) else {
|
|
return false;
|
|
};
|
|
verify(&entry.node_id, &bytes, &entry.signature)
|
|
}
|