crates/monetize-estate-side/src/pump/key.rs
//! **This box's own Ed25519 key** — what the ONE monetize knows the box by. Minted once
//! under the data root, owner-only, and pinned by monetize on the box's first call
//! inside its pin window (TOFU).
use std::path::Path;
use ed25519_dalek::Signer as _;
use monetize_embed::fleet::{fleet_call_message, FleetCall};
/// Where the key lives under the data root (32 raw seed bytes, 0600).
pub const BOX_KEY_REL: &str = "fleet/box.ed25519";
pub struct BoxKey(ed25519_dalek::SigningKey);
impl BoxKey {
pub fn from_seed(seed: [u8; 32]) -> BoxKey {
BoxKey(ed25519_dalek::SigningKey::from_bytes(&seed))
}
/// `<root>/fleet/box.ed25519`, minted on first use. Minted ONCE whoever asks first: a
/// fresh seed is written beside and LINKED into place, which fails when another caller
/// got there first — then the one on disk is used.
pub fn load_or_mint(root: &Path) -> std::io::Result<BoxKey> {
let path = root.join(BOX_KEY_REL);
match std::fs::read(&path) {
Ok(bytes) => {
let seed: [u8; 32] = bytes.as_slice().try_into().map_err(|_| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!(
"{} holds {} bytes, not a 32-byte Ed25519 seed",
path.display(),
bytes.len()
),
)
})?;
Ok(BoxKey::from_seed(seed))
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
let mut seed = [0u8; 32];
getrandom::fill(&mut seed).map_err(|e| {
std::io::Error::other(format!("no randomness for the box key: {e}"))
})?;
let mut tag = [0u8; 8];
getrandom::fill(&mut tag)
.map_err(|e| std::io::Error::other(format!("no randomness: {e}")))?;
let fresh = path.with_extension(format!("new-{}", crate::hex(&tag)));
{
use std::io::Write as _;
if let Some(dir) = path.parent() {
std::fs::create_dir_all(dir)?;
}
let mut opts = std::fs::OpenOptions::new();
opts.write(true).create_new(true);
#[cfg(unix)]
{
use std::os::unix::fs::OpenOptionsExt;
opts.mode(0o600);
}
let mut f = opts.open(&fresh)?;
f.write_all(&seed)?;
f.sync_all()?;
}
let linked = std::fs::hard_link(&fresh, &path);
let _ = std::fs::remove_file(&fresh);
match linked {
Ok(()) => Ok(BoxKey::from_seed(seed)),
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {
BoxKey::load_or_mint(root)
}
Err(e) => Err(e),
}
}
Err(e) => Err(e),
}
}
pub fn public(&self) -> [u8; 32] {
self.0.verifying_key().to_bytes()
}
/// The 64 signature bytes over `message` (the actor ticket's canonical JSON).
pub fn sign_bytes(&self, message: &[u8]) -> Vec<u8> {
self.0.sign(message).to_bytes().to_vec()
}
/// The 64 signature bytes over monetize-embed's [`fleet_call_message`].
pub fn sign(&self, c: &FleetCall) -> Vec<u8> {
self.0.sign(&fleet_call_message(c)).to_bytes().to_vec()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_box_key_is_minted_once_owner_only_and_racing_loads_agree() {
let dir = tempfile::tempdir().unwrap();
let keys: Vec<[u8; 32]> = std::thread::scope(|s| {
let hs: Vec<_> = (0..8)
.map(|_| s.spawn(|| BoxKey::load_or_mint(dir.path()).unwrap().public()))
.collect();
hs.into_iter().map(|h| h.join().unwrap()).collect()
});
let on_disk = BoxKey::load_or_mint(dir.path()).unwrap().public();
assert!(
keys.iter().all(|k| *k == on_disk),
"every first load answers the key on disk"
);
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mode = std::fs::metadata(dir.path().join(BOX_KEY_REL))
.unwrap()
.permissions()
.mode();
assert_eq!(mode & 0o077, 0, "the box key is owner-only");
}
}
#[test]
fn a_call_verifies_under_monetize_embeds_own_verifier() {
let key = BoxKey::from_seed([3u8; 32]);
let c = FleetCall {
product: "a-product".into(),
instance: "acme".into(),
role: "main".into(),
call: "report".into(),
body: "{}".into(),
at_unix_ms: 1_000,
};
let sig = key.sign(&c);
let vk = monetize_embed::VerifyingKey::from_bytes(&key.public()).unwrap();
monetize_embed::fleet::verify_fleet_call(&c, &sig, &vk, 1_000)
.expect("monetize verifies the box's call");
}
}