Phase 2g: GroupKeyDistribute \u2192 encrypted post
Removes the last persona-signed direct push on the wire. Group/circle
seeds no longer travel via the 0xA0 `GroupKeyDistribute` uni-stream from
admin to member. Instead the admin publishes an encrypted post containing
the seed + metadata; each member is a recipient; the post propagates via
the normal CDN. Members decrypt with their posting secret to recover the
seed.
Eliminates the wire-level coordination signal between an admin endpoint
and each member endpoint when a group is created, a member is added, or
a key is rotated.
Core pieces:
- New `VisibilityIntent::GroupKeyDistribute` variant.
- New `types::GroupKeyDistributionContent` — JSON payload inside the
encrypted post: group_id, circle_name, epoch, group_public_key, admin,
canonical_root_post_id, group_seed.
- New `group_key_distribution` module:
- `build_distribution_post(admin, admin_secret, record, group_seed, members)`
returns `(PostId, Post, PostVisibility::Encrypted)` — wraps the CEK
per member using standard `crypto::encrypt_post`.
- `try_apply_distribution_post(s, post, visibility, our_personas)`
iterates every posting identity's secret trying to decrypt; on
success stores `group_key` + `group_seed` and returns true.
- `process_pending(s, our_personas)` scans stored
GroupKeyDistribute-intent posts and applies any we can decrypt.
Node API:
- `add_to_circle`: builds a distribution post wrapping the current seed
to just the new member, stores with intent=GroupKeyDistribute, and
propagates via `update_neighbor_manifests_as` (no direct push).
- `create_group_key_inner`: at group creation, after wrapping keys for
every non-self member, builds one distribution post addressed to all
of them and propagates through the CDN.
- `rotate_group_key`: same pattern at epoch rotation.
- New `Node::process_group_key_distributions` — scans and applies.
`sync_all` now calls it automatically so seeds take effect right after
a pull cycle.
Removals (wire-breaking; v0.6.2 already forked):
- MessageType 0xA0 (`GroupKeyDistribute`), its payload struct, the
handler in connection.rs, and `Network::push_group_key` all deleted.
ConnectionManager's `secret_seed` (network secret) is no longer used for
group-key unwrapping — that shifted to posting secrets in the apply
pass, matching the v0.6.1+ identity split where group keys are wrapped
to posting NodeIds.
Tests: new `member_decrypts_and_applies` covers a recipient decrypting +
storing the seed and a non-recipient failing to apply. Workspace
compiles clean; 118 / 118 core tests pass on a stable run (pre-existing
flaky `relay_cooldown` test with a 1ms timing window is unrelated).
This commit is contained in:
parent
2cb211eb11
commit
f88618bb6f
8 changed files with 385 additions and 132 deletions
|
|
@ -50,7 +50,8 @@ pub enum MessageType {
|
|||
ManifestRefreshResponse = 0x93,
|
||||
ManifestPush = 0x94,
|
||||
// 0x95 (BlobDeleteNotice) retired in v0.6.2 — remote holders evict via LRU.
|
||||
GroupKeyDistribute = 0xA0,
|
||||
// 0xA0 (GroupKeyDistribute) retired in v0.6.2 — group seeds now travel
|
||||
// as encrypted posts via the CDN. See `group_key_distribution` module.
|
||||
GroupKeyRequest = 0xA1,
|
||||
GroupKeyResponse = 0xA2,
|
||||
RelayIntroduce = 0xB0,
|
||||
|
|
@ -102,7 +103,6 @@ impl MessageType {
|
|||
0x92 => Some(Self::ManifestRefreshRequest),
|
||||
0x93 => Some(Self::ManifestRefreshResponse),
|
||||
0x94 => Some(Self::ManifestPush),
|
||||
0xA0 => Some(Self::GroupKeyDistribute),
|
||||
0xA1 => Some(Self::GroupKeyRequest),
|
||||
0xA2 => Some(Self::GroupKeyResponse),
|
||||
0xB0 => Some(Self::RelayIntroduce),
|
||||
|
|
@ -386,21 +386,9 @@ pub struct ManifestPushEntry {
|
|||
|
||||
// --- Group key distribution payloads ---
|
||||
|
||||
/// Admin pushes wrapped group key to a member (uni-stream)
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GroupKeyDistributePayload {
|
||||
pub group_id: GroupId,
|
||||
pub circle_name: String,
|
||||
pub epoch: GroupEpoch,
|
||||
pub group_public_key: [u8; 32],
|
||||
pub admin: NodeId,
|
||||
pub member_keys: Vec<GroupMemberKey>,
|
||||
/// v0.6.2: when set, this record is a group rooted at the given public
|
||||
/// post. Absent on v0.6.1 nodes — deserializes to `None` and behaves
|
||||
/// like a traditional circle.
|
||||
#[serde(default)]
|
||||
pub canonical_root_post_id: Option<PostId>,
|
||||
}
|
||||
// GroupKeyDistributePayload (v0.6.1) retired: group seeds now travel as
|
||||
// encrypted posts (`VisibilityIntent::GroupKeyDistribute`). See
|
||||
// `crate::group_key_distribution` and `types::GroupKeyDistributionContent`.
|
||||
|
||||
/// Member requests current group key (bi-stream request)
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
|
|
@ -757,7 +745,6 @@ mod tests {
|
|||
MessageType::ManifestRefreshRequest,
|
||||
MessageType::ManifestRefreshResponse,
|
||||
MessageType::ManifestPush,
|
||||
MessageType::GroupKeyDistribute,
|
||||
MessageType::GroupKeyRequest,
|
||||
MessageType::GroupKeyResponse,
|
||||
MessageType::RelayIntroduce,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue