Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

zipnet — anonymous submission

audience: contributors

Proposed source: not in this repo. The lattice consumes the existing flashbots/zipnet crate unchanged at whatever version the lattice pins. This page documents only the lattice-specific wrapping.

What the lattice consumes

  • zipnet::Zipnet::<D> as the external SDK surface for wallets and searchers submitting into the lattice.
  • zipnet::UNIVERSE which is identical to builder::UNIVERSE (both resolve to unique_id!("mosaik.universe")).
  • zipnet::Config as one field of the LatticeConfig.
  • zipnet::Broadcasts as the only upstream input to unseal (see unseal).

Authoritative docs for everything above live in the zipnet book:

Lattice wrapping

Three wrapping facts that matter at the builder level and do not appear in the zipnet book because zipnet does not know it is in a lattice.

1. Instance name derivation

A zipnet deployment that is part of a lattice takes its zipnet::Config.name directly from the lattice’s instance name. The builder meta-crate’s LatticeConfig constructor enforces this:

impl LatticeConfig {
    pub const fn new(name: &'static str, chain_id: u64) -> Self {
        Self {
            name,
            chain_id,
            // zipnet's own content + intent addressing folds the
            // lattice name in as the zipnet instance name.
            zipnet:  zipnet::Config::new(name),
            unseal:  unseal::Config::new(name),
            offer:   offer::Config::new(name),
            atelier: atelier::Config::new(name),
            relay:   relay::Config::new(name),
            tally:   tally::Config::new(name),
        }
    }
}

Two lattices under different names get disjoint zipnet GroupIds by the zipnet content + intent addressing rules, exactly as intended. A lattice cannot share a zipnet committee with another lattice; a zipnet committee belongs to exactly one lattice.

2. Sealed payload convention

Zipnet shuffles opaque D: ShuffleDatum values. The lattice’s convention is that D carries an unseal-sealed payload: the application-level transaction (e.g. an EIP-2718 RLP) is first encrypted to the unseal committee’s threshold public key, then right-padded to D::WIRE_SIZE, then submitted.

The reference datum is Tx2718; its WIRE_SIZE is set by the lattice such that unseal::seal(max_app_payload).len() <= Tx2718::WIRE_SIZE with enough slack for the AEAD overhead. The exact constant ships in the lattice’s datum crate.

This convention is enforced at the integrator layer (see integrators/submitting.md); zipnet itself does not know or care what is inside D. A lattice that fails to seal payloads before submission is still a valid zipnet deployment; it is just not a lattice whose anonymity holds beyond zipnet’s own guarantee.

3. Consumer: the unseal organism

The lattice’s only downstream consumer of zipnet::Broadcasts is the unseal organism. Every other organism reads from unseal::UnsealedPool instead — the cleartext side — because they need to reason about the actual transactions, not the ciphertext.

This means in operational terms: if unseal is down but zipnet is up, zipnet continues to commit Broadcasts (no back-pressure from unseal); those broadcasts simply accumulate without producing downstream effect until unseal recovers. See composition.md — failure table.

State machine

Unchanged from zipnet. CommitteeMachine as specified in the zipnet book’s committee state machine page. signature() folds in the zipnet wire version plus its round parameters; the lattice does not add further inputs.

Cryptography

Unchanged from zipnet. X25519 ECDH + HKDF-SHA256 + AES-128-CTR for pads, keyed blake3 for the falsification tag. See Cryptography — zipnet in this book for the summary and zipnet cryptography for the full derivation.

ACL composition

zipnet::Config carries its own TicketValidator composition. In a TDX-gated lattice it stacks with the lattice-level tee-tdx feature:

// In the integrator agent's Cargo.toml, when tee-tdx is enabled:
zipnet = { version = "...", features = ["tee-tdx"] }

The validator chain pins atelier’s MR_TD for committee admission (so zipnet committee members are TDX-attested peers). Writer-side admission of external submitters is gated by the lattice operator’s JWT issuer key — same mechanism zipnet ships.

Trust shape

Any-trust on anonymity; crash-fault on liveness. See threat-model.md — zipnet. No change from the zipnet book.

Open questions specific to the lattice

  • v2 receipts stream. Zipnet defers Receipts<D> to its v2. The lattice’s tally organism is a partial replacement at the attribution layer but does not restore the per-submitter receipt shape zipnet’s design contemplates. Does the lattice want to push for zipnet’s receipts to land, or is tally enough? Open.
  • Cover traffic rate. Lattices targeting public L1 PBS have different anonymity-set cadences from lattices targeting a fast L2 sequencer. The zipnet ShuffleWindow preset (interactive, archival) covers the common cases; lattices with unusual chain cadences ship a custom window, which folds into the zipnet fingerprint as usual.
  • Multi-lattice zipnet sharing? Not supported. A zipnet committee belongs to exactly one lattice. Proposals to share one zipnet across lattices would need a new zipnet shape (higher-dimensional Config) and are out of scope.

Cross-references