Skip to content

CC 5.4 scope-native privacy WIRE profile (record_id + RaptorQ symbol envelopes + fixed-size cover framing) is not on any content path — chunks ride sha-addressed; FSD then implement #651

Description

@emooreatx

Filed from the "when do we use RaptorQ?" review (persist#888 thread / CIRISServer). The answer for files is settled and needs no change: shape is chosen by access pattern (FSD/GROUP_CONTENT_ON_BLOBS.md §4), the only size threshold is the CC 2.6.1.3 1 MiB envelope bound (= persist DEFAULT_INLINE_BYTES_CAP), and RaptorQ is a retention-class mechanism (CC 6.1.5 durability/degradation per layer), never a size one — self/family files never fountain (CC 6.1.5 suppresses FountainHoldingClaim under CC 5.2; a 2–5-node collective cannot place N+K=26 symbols). This issue is the other place CC puts RaptorQ, which edge has not implemented: the scope-native privacy wire profile.

CC 5.4 — what is implemented and what is not

clause rule edge
5.4.1 record-id K_record_id/K_symbol from the MLS exporter; record_id = HMAC-SHA3-256(K_record_id, CBOR_dCE({v, epc, iid, typ})) primitives ✓ — scope_privacy.rs re-exports verify's derive_record_id / derive_symbol_key with KAT vectors; no producer or consumer calls them on any content path
5.4.2 symbol every fragment of a below-federation record is a RaptorQ symbol sealed under symbol_key = HKDF-SHA3-256(salt=record_id, ikm=K_symbol, info="ciris-edge/scope-privacy/symbol/v1"‖u16_be(i)), XChaCha20-Poly1305; fragment set rebinds on Add/Remove; reassembly opens ≥ K valid symbols or ContentMiss ✗ — community/self/family bytes ride the chunk DAG (CC 5.3.3.1 SFrame seal), content-addressed by ciphertext sha
5.4.3 fragmentation fixed 1.4 KB envelope, padded; uniform AEAD framing across real and cover; type=cover inside the AEAD; Poisson cover emission ✗ — scope_privacy.rs lists "§3.1 Poisson emission discipline" as DEFERRED since v6.0.0
5.4.4 welcome-wrap HPKE mode_base under X-Wing + ML-DSA-65 over the encapsulation ✓ mls::welcome_wrap
5.4.5 witness-content federation witness chain commits only to federation record_ids + one rate-smoothed counter; per-community chain member-only ✗ — "§3.4 per-community witness chain split" DEFERRED since v6.0.0
5.4.6 announce-suppress no announce for group-scoped destinations; directory-cached + per-group HKDF resolution ✓ #499 ScopeAddressTable / announce_suppression.rs

What the gap costs today

Confidentiality holds (per-chunk AEAD; a relay never holds a DEK). What CC 5.4 closes and the chunk DAG does not: a holder or on-path observer can (a) link every chunk of one blob to one record (sha-addressed, ChunkManifest pins them), (b) read plaintext-proportional sizes and chunk counts (v2 manifest sizes are plaintext by design), and (c) time the publication (no cover, no fixed envelope). CC 1.13.3.1 concedes comm-graph/traffic-analysis privacy as a base non-goal, but CC 5.4 is the normative profile a conformant substrate uses below federation, and CC 1.13.3.4 makes anonymity-to-outsiders the default — so this is a conformance gap to state, not a threat-model surprise.

Ask

FSD first (FSD/CIRIS_EDGE_TRANSPORT.md, a §5.4-profile section under the link-state / round / content tables), then code:

  1. Objects: ScopeRecord { record_id, epc, iid, typ } over the MLS exporter (5.4.1); SymbolEnvelope (5.4.2); the cover envelope and the emission scheduler (5.4.3). Reuse: verify's helpers, raptorq (already the AV wrap in realtime_av_codec/fountain.rs), leviculum Channel for reliable symbol delivery — the machinery we already pay for, not a new plane.
  2. Where it sits vs the chunk DAG: the DAG stays the storage shape (persist stores exact-payload chunks, sha-pinned); the 5.4 profile is the wire shape between members — chunks are symbol-coded per record on the send side and decoded on the receive side before put_blob_chunk. State that boundary explicitly so persist's "links zero codec crates" stays true.
  3. Rows: the rung table in FSD/CONTENT_TRANSFER.md gains a wire column at R5–R8 (community/self/family) naming the envelope shape, with ContentMiss as the honest reassembly refusal.
  4. Witness: a holder-side test that two symbols of one record are unlinkable without K_record_id, and a cover envelope is indistinguishable from a real one under the AEAD; a KAT against verify's vectors for symbol_key.

Open question for the Constitution (not edge's to decide)

CC 5.4.3 fixes the envelope at 1.4 KB, "one MTU" — an Ethernet assumption. Reticulum's MTU is 500 bytes and leviculum's link MDU is smaller still; a 1.4 KB fixed envelope would be fragmented by the transport it rides, re-exposing the size/count channel one layer down. Either the profile pins a Reticulum-native envelope (≤ link MDU) or it states that the fixed size binds at the substrate envelope and the transport's own fragmentation is in-model. I will raise it on CIRISConstitution when this FSD is drafted; until ruled, the FSD parameterizes the envelope size and pins the AEAD shape.

Not blocking any current cut (v29.3.0 / CIRISServer 0.5.214); sequenced after FSD/CONTENT_TRANSFER.md §6.2/§6.3 (#646).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions