feat(fof-layer1): publish path embeds VouchGrantBatch
Wires the publish side of FoF Layer 1 vouch distribution: - VouchGrantBatch gains bio_pub_nonce (32B random per batch). Replaces the spec's circular "bio_post_id in HKDF info" — BLAKE3(post) depends on vouch_grants, so we need a content-independent binder. Recipient-free per HPKE key-privacy; serves the same anti-replay purpose as bio_post_id would have. - profile::build_vouch_grant_batch reads current_own_vouch_key + list_current_vouch_targets, generates eph keypair + bio_pub_nonce, seals V_me for each target, bucket-pads with random 48B dummies, and shuffles. Returns None when there are no targets. - next_vouch_batch_bucket implements the FoF Layer 3 padding rule: minimum bucket 8, power-of-2 up to 256, then linear +128 steps. Bucket-padding-tests verifies all boundaries. - Storage gains next_bio_epoch_for(persona_id): monotonic counter per persona, used by receivers' scan cache. Stored in settings. - build_profile_post signature extended to take Option<VouchGrantBatch> + bio_epoch: u32. Both publish_profile_post_as (initial post) and set_profile (subsequent edits) build the batch and bump the epoch on every publish. - Test sites updated to pass None/0 for the new args. Receive-side scan (next commit) reads VouchGrantBatch + bio_pub_nonce to trial-decrypt wrappers and populate vouch_keys_received. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bc008c5049
commit
3ee5c30ad2
4 changed files with 156 additions and 6 deletions
|
|
@ -735,12 +735,22 @@ impl Node {
|
|||
bio: &str,
|
||||
avatar_cid: Option<[u8; 32]>,
|
||||
) -> anyhow::Result<()> {
|
||||
// FoF Layer 1: build the vouch-grant batch (if this persona has
|
||||
// any current vouch targets) + bump the bio_epoch.
|
||||
let (vouch_grants, bio_epoch) = {
|
||||
let storage = self.storage.get().await;
|
||||
let batch = crate::profile::build_vouch_grant_batch(&*storage, posting_id)?;
|
||||
let epoch = storage.next_bio_epoch_for(posting_id)?;
|
||||
(batch, epoch)
|
||||
};
|
||||
let profile_post = crate::profile::build_profile_post(
|
||||
posting_id,
|
||||
posting_secret,
|
||||
display_name,
|
||||
bio,
|
||||
avatar_cid,
|
||||
vouch_grants,
|
||||
bio_epoch,
|
||||
);
|
||||
let profile_post_id = crate::content::compute_post_id(&profile_post);
|
||||
let timestamp_ms = profile_post.timestamp_ms;
|
||||
|
|
@ -1542,12 +1552,22 @@ impl Node {
|
|||
storage.get_profile(&posting_id).ok().flatten().and_then(|p| p.avatar_cid)
|
||||
};
|
||||
|
||||
// FoF Layer 1: build the vouch-grant batch (if this persona has
|
||||
// any current vouch targets) + bump bio_epoch.
|
||||
let (vouch_grants, bio_epoch) = {
|
||||
let storage = self.storage.get().await;
|
||||
let batch = crate::profile::build_vouch_grant_batch(&*storage, &posting_id)?;
|
||||
let epoch = storage.next_bio_epoch_for(&posting_id)?;
|
||||
(batch, epoch)
|
||||
};
|
||||
let profile_post = crate::profile::build_profile_post(
|
||||
&posting_id,
|
||||
&posting_secret,
|
||||
&display_name,
|
||||
&bio,
|
||||
avatar_cid,
|
||||
vouch_grants,
|
||||
bio_epoch,
|
||||
);
|
||||
let profile_post_id = crate::content::compute_post_id(&profile_post);
|
||||
let timestamp_ms = profile_post.timestamp_ms;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue