swactor/crates/distribution/src/crypto.rs
zacheryasc d817ad952f feat: distributed runtime (#30)
Major feature addition. For full details read `./docs/development_history/DISTRIBUTION.md`
2026-02-12 09:13:50 +00:00

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)
}