feat(fof-layer1): wire types + V_me auto-gen on persona creation
Adds VouchGrantBatch type to types.rs and extends ProfilePostContent with optional vouch_grants + bio_epoch fields (back-compat via #[serde(default)]). VouchGrantBatch carries one shared batch_eph_pub + a Vec<Vec<u8>> of 48-byte wrappers; receivers identify their wrapper by AEAD success, not position. Wires V_me auto-generation into both persona-creation paths: - Node::open first-run auto-persona block now seeds vouch_keys_own epoch=1 alongside upsert_posting_identity. - create_posting_identity calls ensure_initial_v_me after the new persona is stored. Helpers live as private free functions at module scope so both the sync (Node::open holds a Storage guard) and async (create_posting holds a StoragePool) sites can share them. Idempotent — re-running on a persona that already has a current key is a no-op. Two existing ProfilePostContent construction sites updated to set the new fields to defaults (None / 0); they'll get real values when the publish path is wired up in the next commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8a53d83306
commit
bc008c5049
3 changed files with 79 additions and 0 deletions
|
|
@ -63,6 +63,35 @@ pub struct Node {
|
|||
budget_last_reset_ms: Arc<AtomicU64>,
|
||||
}
|
||||
|
||||
/// FoF Layer 1: generate a fresh 32B `V_me` and insert it as the
|
||||
/// persona's current epoch (epoch=1). Idempotent if the persona already
|
||||
/// has a current key — does nothing in that case.
|
||||
fn generate_and_store_initial_v_me(
|
||||
storage: &crate::storage::Storage,
|
||||
persona_id: &NodeId,
|
||||
now_ms: u64,
|
||||
) -> anyhow::Result<()> {
|
||||
use rand::RngCore;
|
||||
if storage.current_own_vouch_key(persona_id)?.is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
let mut key = [0u8; 32];
|
||||
rand::rng().fill_bytes(&mut key);
|
||||
storage.insert_own_vouch_key(persona_id, 1, &key, now_ms)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Async wrapper used by `Node::create_posting_identity`. Acquires the
|
||||
/// storage handle and delegates to the sync helper.
|
||||
async fn ensure_initial_v_me(
|
||||
storage: &StoragePool,
|
||||
persona_id: &NodeId,
|
||||
now_ms: u64,
|
||||
) -> anyhow::Result<()> {
|
||||
let s = storage.get().await;
|
||||
generate_and_store_initial_v_me(&s, persona_id, now_ms)
|
||||
}
|
||||
|
||||
impl Node {
|
||||
/// Create or open a node in the given data directory (Desktop profile)
|
||||
pub async fn open(data_dir: impl AsRef<Path>) -> anyhow::Result<Self> {
|
||||
|
|
@ -133,6 +162,8 @@ impl Node {
|
|||
created_at: now,
|
||||
})?;
|
||||
s.set_default_posting_id(&nid)?;
|
||||
// FoF Layer 1: auto-gen V_me epoch 1 for this fresh persona.
|
||||
generate_and_store_initial_v_me(&s, &nid, now)?;
|
||||
// Mark this as the disposable auto-gen persona from the
|
||||
// fresh-install flow. If the user subsequently imports, we
|
||||
// prune this id iff it's still pristine (no name, no posts,
|
||||
|
|
@ -684,6 +715,12 @@ impl Node {
|
|||
}
|
||||
}
|
||||
|
||||
// FoF Layer 1: every persona owns its own V_me (symmetric 32B key).
|
||||
// Auto-generate epoch 1 at creation. Stored in vouch_keys_own with
|
||||
// is_current=1. Per Layer 4, rotations append new epochs; this row
|
||||
// is never deleted automatically.
|
||||
ensure_initial_v_me(&self.storage, &node_id, now).await?;
|
||||
|
||||
Ok(identity)
|
||||
}
|
||||
|
||||
|
|
@ -772,6 +809,8 @@ impl Node {
|
|||
avatar_cid: None,
|
||||
timestamp_ms: pi.created_at,
|
||||
signature,
|
||||
vouch_grants: None,
|
||||
bio_epoch: 0,
|
||||
};
|
||||
let post = Post {
|
||||
author: pi.node_id,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue