hip-0077

HIP-77: Mesh Identity, Gossip & Payments (PQ). Status Draft. Hanzo's own standard — read this before implementing against it.

HIP-0077: Mesh Identity, Gossip & Payments (PQ)

Abstract

HIP-0069 made every Hanzo service discoverable on the LAN via one mDNS type. HIP-0077 layers three things on top so the mesh extends past the broadcast domain and becomes a settlement substrate, end-to-end post-quantum:

  1. Identity. Every device, MCP, container, browser and node derives

its keypair from a single HD mnemonic. The signing key is ML-DSA-65 (NIST FIPS 204, the same primitive Lux consensus already uses for per-validator identity signatures). The ML-DSA-derived address rides in the mDNS TXT record; the ZAP handshake carries the full pubkey + a fresh signature over a server-supplied nonce; peers verify before accepting traffic.

  1. Gossip. For cross-LAN propagation peers publish the same

identity + capability record to the Lux consensus mesh on network 1337 (primary / dev) or whichever network the tenant pins. One read of the gossip set is equivalent to an mDNS browse, but globally.

  1. Payments. The same identity is a Lux account. Any tool call on

the mesh can carry a price; the consumer signs a promise; the provider signs a receipt; settlement happens on chain. The first 200 device indices derived from the LIGHT_MNEMONIC are pre-funded in the network 1337 genesis from the P/X-chain LIGHT_MNEMONIC balance, so a fresh laptop or container joining the local mesh has working credit immediately — no manual top-up.

Net effect: one mnemonic in your environment, a hundred-plus devices each with unique PQ identity and a balance, all discoverable and billable across the LAN via mDNS and across the WAN via Lux consensus, without any config file.

Motivation

HIP-0069 solved discovery; it stopped there deliberately. After shipping it four needs surfaced immediately:

a laptop on home wifi never sees the Hanzo Desktop on the office LAN or the bare-metal node in a datacentre. A small overlay is needed to relay records.

advertise role=kms with a forged server_id. The TXT auth=iam field tells consumers what to expect, but does not bind the record itself to a key. A signed handshake fixes this.

(HIP-0008) both presuppose a way for one peer to pay another for work. The mesh already exposes the work as MCP tool calls; the missing piece is per-call billing keyed to the same device identity used for discovery.

network needs an account with balance before it can pay for inference, storage or any other priced call. Manual funding for every laptop / container / phone is friction we can remove with a genesis pre-allocation tied to the well-known dev mnemonic.

The cleanest answer reuses infrastructure that already exists:

github.com/luxfi/pulsar/sign and already wired into Lux consensus via config.PQMode.

focus, prism, ray, field, quasar) for cross-LAN gossip with BFT finality. Five PQ modes are available (see table below); the Hanzo mesh defaults to the strongest.

No new chains, no new crypto, no new naming.

Lux consensus PQ modes

lux/consensus/config/pq_mode.go exposes the full PQ design space as five orthogonal modes. Every mode keeps BLS-12-381 as the classical fast path; PQ layers stack on top. The names are picked so each canonical mode is the sub-protocol that defines its post-quantum surface.

The matrix

| PQMode | env | classical | threshold lattice | per-validator PQ | rollup | DKG required | suitable for open public chain? | |------------------|------------|-----------|--------------------------------------|-----------------------|-------------------|-----------------------------------------|---------------------------------| | PQModeBLS | bls | BLS | — | — | — | none | no (no PQ) | | PQModeCorona | corona | BLS | Corona / BLAKE3 (academic) | — | — | trusted dealer | no (no DKG-with-rotation) | | PQModePulsar | pulsar | BLS | Pulsar / SHA-3 cSHAKE256 (prod) | — | — | Pedersen DKG over R\_q + proactive resharing | yes | | PQModeQuasar | quasar | BLS | Pulsar / SHA-3 | ML-DSA-65 (rolled) | Groth16 / Z-Chain | Pedersen DKG over R\_q + proactive resharing | yes (default) | | PQModeMLDSA | mldsa | BLS | — | ML-DSA-65 raw | — | none | yes (audit-grade fallback) |

Two production progressions:

public chains, open validator set:    BLS → Pulsar → Quasar
fixed federations / bridge MPC:       BLS → Corona

MLDSA is an audit-grade side path: every validator's raw ML-DSA-65 sig in every cert (~N·3309 B). Use it transitionally if the Z-Chain Groth16 witness isn't wired yet, or when an external auditor needs the per-validator log.

Pulsar vs Corona — what's actually different

Both implement the same 2-round LWE threshold-signature core algorithm. They diverge on the hash family and the production lifecycle:

| dimension | Corona (github.com/luxfi/corona) | Pulsar (github.com/luxfi/pulsar) | |--------------------|----------------------------------------|--------------------------------------------------------------| | canonical hash | BLAKE3 (academic upstream) | SHA-3 (cSHAKE256 / KMAC256 / TupleHash256, FIPS 202 + SP 800-185) | | DKG | trusted dealer (fixed federation) | Pedersen DKG over R\_q with proper hiding | | validator rotation | none (re-run trusted dealer) | proactive secret resharing (pulsar/reshare/) | | target deployment | bridge MPC, audit, KATs | open public chains (Lux primary network, Hanzo mesh) | | NIST profile? | no (BLAKE3 not in FIPS 202 family) | yes (every primitive in the FIPS 202 / SP 800-185 family) | | fork history | upstream academic port | production fork that will keep diverging as protocol matures |

The modes are kept distinct on purpose: an open public chain that reused Corona's trusted-dealer DKG would be unable to rotate its validator set without a manual ceremony, and an audit fixture that wanted byte-identical KATs against the academic spec needs the BLAKE3 path. We treat them as first-class siblings, not as "old vs new" — the helpers PQMode.HashProfile(), PQMode.DKGRequired() and PQMode.SuitableForPublicChain() make the distinction queryable.

NIST submission posture. The Pulsar SHA-3 profile is the only hash configuration eligible for any NIST-track submission (MPTC IR 8214C §4.6 lists the approved symmetric primitives: AES, Ascon, SHA-2, SHA-3, SHAKE/cSHAKE, HMAC/KMAC/CMAC/GMAC). BLAKE3 deltas, including Pulsar-BLAKE3 legacy and Corona's BLAKE3 academic profile, are product/experimental profiles only. Pulsar keeps the BLAKE3 suite non-normative and marked "NOT for production"; Corona's BLAKE3 profile is fixed-federation only and never intended for the Lux primary network.

Canonical HashSuiteID encoding

There is one canonical wire representation of the hash-suite identifier across the Lux + Hanzo tree: a uint8 byte, defined in lux/consensus/config/pq_mode.go (and mirrored on the cert wire in lux/consensus/pkg/wire/candidate.go). The currently-assigned values are:

| byte | name | meaning | |--------|-------------------------|------------------------------------------------------------------| | 0x00 | HashSuiteNone | no hash-family commitment (BLS-only certs) | | 0x01 | HashSuiteSHA3NIST | FIPS 202 + SP 800-185 family (SHAKE256 / cSHAKE256 / KMAC256 / TupleHash256) — the normative production suite | | 0x02 | HashSuiteBLAKE3Legacy | academic / federation-MPC profile; non-normative for NIST |

consensus/config.HashSuiteID is the single source of truth. The wire copy in consensus/pkg/wire.HashSuiteID is a structural mirror for cert-envelope serialisation; downstream code MUST NOT define a third encoding. The byte is bound into the cert transcript (see Certificate.TranscriptHash and quasar.computeRoundDigest) so that flipping the byte post-signing breaks signature verification, not just a string-equality check.

The Warp 2.0 envelope (lux/warp/envelope.go) currently carries a HashSuiteID string field defaulting to "Pulsar-SHA3". This is a deprecated parallel encoding inherited from the pre-pin era. It MUST migrate to the canonical uint8 form by the 2026-Aug-31 encoding-freeze gate:

(HashSuiteID uint8) in parallel during the transition window.

envelopes that disagree across the two forms.

only the legacy string field are rejected with ErrEnvelopeBadSuiteID. The default value "Pulsar-SHA3" maps exactly to HashSuiteSHA3NIST (0x01); the legacy "Pulsar-BLAKE3" maps to HashSuiteBLAKE3Legacy (0x02).

The migration MUST NOT change the value bound into the transcript hash of any cert produced before the freeze; the wire layout changes, the signed bytes do not.

Configuration

Three equivalent ways:

// Explicit (any of the five modes):
params := config.DefaultParams().WithPQMode(config.PQModeQuasar)

// Boolean shorthand (collapses to extremes):
params := config.DefaultParams().WithPostQuantum(true)
// true  -> PQModeQuasar   (strongest available)
// false -> PQModeBLS      (classical)
// for the middle three (corona / pulsar / mldsa) call WithPQMode.

// Env override (highest priority, no rebuild needed):
//   LUX_CONSENSUS_PQ_MODE=quasar
mode, _ := config.PQModeFromEnv(config.PQModeQuasar)

config.PQModeFromEnv parses any canonical name or alias.

PQ defaults for Hanzo mesh networks

Network 1337 (primary local / dev) and any tenant network minted under HIP-0077 MUST default to PostQuantum = true (= PQModeQuasar). Rationale:

layer running anything less than Pulsar would be a strictly weaker link in the same chain of trust.

to Quasar is one extra threshold signature per finality round — well inside the budget for a mesh that expects ms-grade finality on a few-dozen-validator quorum.

(lattice cryptanalysis advance) does not lose the mesh; Quasar is the only mode that survives loss of one lattice primitive.

Operators with a hard latency budget MAY opt down to Pulsar (threshold lattice only, no Z-Chain witness). Those needing every validator's raw ML-DSA signature in the cert (auditor flow) MAY opt sideways to MLDSA — at the price of N·3309 B per cert. They MUST NOT opt down to BLS (no PQ surface) or Corona (trusted-dealer DKG, unsuitable for an open validator set) while participating in any production Hanzo mesh.

Decision tree for operators:

open public chain (epoch rotation, no trusted dealer)?
   no — fixed federation / bridge MPC
        → corona                  (academic BLAKE3, trusted dealer)
   yes ↓
   need any PQ?
     no  → bls                      (benchmark only; rejected on prod meshes)
     yes ↓
     need defense-in-depth (two lattice constructions)?
        yes → quasar                (Hanzo mesh default; degrades to mldsa if Z-Chain not wired)
        no  ↓
        need every validator's raw sig in the cert for audit?
          yes → mldsa               (per-validator ML-DSA, N*3309 B)
          no  → pulsar              (production threshold lattice, SHA-3, O(1) cert)

Pulsar-M-65 production profile

Pulsar-M (the M-LWE / ML-DSA-compatible threshold variant) is parameterised at the three FIPS 204 levels: Pulsar-M-44, Pulsar-M-65, Pulsar-M-87. The per-use-case mapping is fixed:

| use case | profile | rationale | |-----------------------------------------|----------------|------------------------------------| | Mainnet finality (per-block) | Pulsar-M-65 | NIST PQ Cat 3, balanced | | High-value roots (governance, bridges) | Pulsar-M-87 | NIST PQ Cat 5, low frequency | | Devnet / testnet / CI | Pulsar-M-44 | NIST PQ Cat 2, fast | | Audit / FIPS-only fallback | raw ML-DSA-65 | single-party, FIPS 204 module | | Federation / bridge MPC | Corona | trusted dealer, no DKG cost |

Pulsar-M-65 is the public-chain default. Pulsar-M-87 is reserved for roots that ship at epoch / governance / bridge cadence (low TPS, high value). Pulsar-M-44 is forbidden on the Lux primary network and any production Hanzo mesh — devnet / CI only — because Category 2 is below the floor Hanzo commits to for any chain that anchors real balances.

The fallback profiles (raw ML-DSA-65 and Corona) MUST NOT be silently substituted for the Pulsar-M production profile on a public chain. They are explicit operator opt-ins, gated through the existing PQMode selection (mldsa and corona respectively).

Specification

Identity

Every device in the mesh derives its key material from one mnemonic in priority order: MNEMONIC > LUX_MNEMONIC > LIGHT_MNEMONIC. The last is the public dev fallback ("light light light light light light light light light light light energy") used on network-id >= 1337. Production deployments MUST set MNEMONIC.

The mnemonic produces a master seed via BIP-39 → BIP-32. From that seed two parallel keypairs exist for each device index n:

| derived | path | curve / scheme | use | |----------------------|-----------------------------------|------------------|----------------------------------------------------------| | device_pq_key[n] | m / 44' / 9000' / nid' / 0 / n | ML-DSA-65 | Mesh identity: TXT address, handshake & receipt signing | | device_lux_key[n] | m / 44' / 9000' / nid' / 1 / n | secp256k1 | Lux account: AI Coin balance, on-chain settlement |

mesh; other values for tenant clusters).

separate from spend keys.

child seed via SHAKE-256(seed) → ML-DSA keygen RNG, per the procedure in lux/crypto/mldsa (single source of truth).

Per device:

| value | derivation | |-------------------|-----------------------------------------------------------------| | mldsa_pubkey | verify key of device_pq_key[n] (~1952 B) | | mldsa_address | RIPEMD-160(SHA-256(mldsa_pubkey)) → 20 bytes, hex-encoded | | lux_address | standard Lux account derivation from device_lux_key[n] |

The 20-byte mldsa_address is the short identifier carried in mDNS; the full pubkey is exchanged at handshake time where size doesn't matter.

mDNS TXT changes

HIP-0069's TXT record gains ONE REQUIRED key for auth != none roles and OPTIONAL for auth=none:

| key | example | |-----------|--------------------------------------| | mldsa | <40-hex-char address> |

We deliberately do NOT put a per-record ML-DSA signature in TXT — ML-DSA-65 signatures are ~3309 bytes, hostile to multicast. Binding is established at handshake time instead (next section). The TXT mldsa field is a public commitment: a server forging a stranger's address can't complete the handshake (doesn't have the private key); a server using its own address is just a regular new peer.

ZAP handshake

MSG_HANDSHAKE_OK from the server now carries a 32-byte random nonce. The client follows with a new message:

MSG_AUTH = 0x03
payload = {
  pubkey:  <ML-DSA-65 verify key, base64>,
  sig:     <ML-DSA.Sign(device_pq_key, server_id || nonce || client_role)>,
}

Server verifies:

  1. RIPEMD-160(SHA-256(pubkey)) == TXT.mldsa (or, for inbound peers

discovered via gossip, against the gossip record's address).

  1. ML-DSA.Verify(pubkey, server_id || nonce || client_role, sig).

Either check failing → server closes the socket. For roles with auth=none (static, gateway brochures) the auth round is SKIPPED entirely and any anonymous client is accepted.

This adds one round-trip on connect and one ~3.3 KB frame; for a long-lived ZAP session that's negligible.

Gossip — Lux consensus overlay

Every device that wants to be reachable beyond its LAN runs a Lux consensus light client and publishes one record per role into a well-known namespace on network <nid>:

namespace:  hanzo/mesh/v1/<nid>/<org>
key:        <mldsa_address>/<role>/<server_id>
value:      {
    addrs:        ["wss://hostname:port/", "..."],
    proto:        "zap/1",
    capabilities: ["mcp","browser-bridge","..."],
    version:      "1.2.3",
    pubkey:       <ML-DSA-65 verify key>,
    expires_at:   <unix-seconds>,
    sig:          <ML-DSA.Sign over canonical fields>,
}

Discovery rule:

for deltas (Lux consensus's standard subscription path — wave deltas committed under the field driver).

LAN and gossip, prefer the LAN address (lower latency, smaller billed bytes).

expires_at MUST be ≤ 5 minutes from publish; a peer refreshes its record well before expiry. The consensus pruner drops expired entries so the namespace stays bounded.

Use of consensus is intentional: the records are state that we want ordered, verifiable, and resistant to partition. We are not building a new gossip layer.

Auto-funding the first 200 devices

The Lux node genesis builder for network 1337 (and any other mesh network that opts in) MUST pre-allocate balance to the first 200 addresses derived from LIGHT_MNEMONIC on the Lux branch (device_lux_key[0..199]). Allocation tables:

| chain | source | per-address allocation | |-------|---------------------------------------------------|----------------------------| | P | LIGHT_MNEMONIC P-chain genesis balance × 0.001 | 1 000 LUX (testnet units) | | X | LIGHT_MNEMONIC X-chain genesis balance × 0.001 | 1 000 LUX (testnet units) | | C | LIGHT_MNEMONIC C-chain (EVM) balance × 0.001 | 1 000 LUX (testnet units) |

Numbers are per-network parameters; the table above is the network 1337 default. Real production networks pick their own.

Why 200: empirically covers "one developer's fleet" — laptop, desktop, phone, ~10 dev containers, ~10 browsers, plus headroom for short-lived ephemeral containers. Past 200, devices fund themselves from one of the funded principal accounts via standard Lux transfers — still automatic, but on-chain.

Implementation lives in lux/genesis and is invoked once at network boot. Sibling tooling in hanzo-cli:

$ hanzo dev fund-status
device  lux_address                                  balance
0       lux1qzv...3kx                                1000.0 LUX
1       lux1qd9...8mq                                1000.0 LUX
…
199     lux1qy7...0aw                                1000.0 LUX

A device pulls its index from HANZO_DEVICE_INDEX (default 0, distinct per machine via container UUID hash mod 200). On first boot it queries its own balance; if zero, it transfers from a sibling-funded device or surfaces a clear "you've exceeded the auto-funded set, top up" error.

Payments

Each MCP tool MAY advertise a price in its description object:

{
  "name": "engine.completion",
  "description": "...",
  "inputSchema": {...},
  "price": { "unit": "1_token_in_out", "currency": "AI", "amount": "0.0001" }
}

Currency is HIP-0001 AI Coin by default; tenant clusters MAY use other Lux-native assets.

Call protocol:

  1. Consumer issues tools/call with a payment field carrying a

signed promise{ from_lux, to_lux, max_cost, nonce, mldsa_sig } — payable on settlement.

  1. Provider runs the tool, computes actual cost (within max_cost),

returns the result plus a receipt{ promise_hash, actual_cost, mldsa_sig } signed by device_pq_key.

  1. Either party MAY submit the (promise, receipt) pair to the

payments contract on network <nid>. The contract verifies both ML-DSA signatures and transfers actual_cost from from_lux to to_lux.

For sub-cent calls the receipt sits in a buffer; the provider batches receipts and submits one settlement transaction per epoch (amortising the on-chain cost across thousands of calls). HIP-0018 defines the wider payments surface; this section pins the receipt shape to MCP tool calls specifically.

Refunds, disputes, and slashing for forged receipts: see HIP-0018.

AI mining

A device that wants to monetise spare compute publishes an MCP role (role=engine, role=node, etc.) advertising prices below market. HMM (HIP-0008) reads the gossip namespace and routes inference jobs to the cheapest verified peer matching the request's capability set. Verification is via the same receipt mechanism: the provider's ML-DSA signature on the (input, output) pair is sufficient for honest clients; clients suspecting a Byzantine provider may run a quorum of three peers and slash any minority answer.

Containers as the compute unit

Zoo/Hanzo Container runtime (hanzoai/container) MUST, at boot:

  1. Derive its device_pq_key and device_lux_key using

<device_index> = the container's stable UUID hashed to a u32 (mod 200 for the auto-funded slot; or > 200 if the orchestrator pre-allocated).

  1. Publish via _hanzo._tcp.local. on the host network and (if the

network policy allows) gossip.

  1. Sign every tools/call receipt with device_pq_key.

When the container exits cleanly, it withdraws its gossip record; when it crashes, the expires_at window evicts it within 5 minutes.

Backwards compatibility

A peer advertising HIP-0069 TXT without mldsa SHALL be accepted by HIP-0077 consumers when auth=none, refused when auth is anything else. By 2027-Q1 unsigned (in the handshake sense) peers SHOULD be refused for every role.

The on-chain gossip namespace and the auto-funding pre-allocation are pure additions; no breaking change to existing Lux clients. Devices opting out of gossip remain visible on their own LAN only — degraded but functional.

Reference implementation

Per language, one new module sits beside the HIP-0069 binding:

| layer | package | |--------------|---------------------------------------------------------------| | Identity | hanzo-zap-identity (Python, TS, Go, Rust, Swift) | | Gossip | hanzo-zap-gossip (thin client over luxfi/consensus) | | Payments | hanzo-zap-pay (consumer + provider helpers) |

Genesis tooling: lux/genesis gains a --hanzo-auto-fund flag for network builders that pre-allocates the first 200 device addresses.

hanzo-mcp MUST import all three runtime bindings; non-MCP roles MAY import only the subset they use (a static-asset server doesn't need payments).

Reference repos: ~/work/zap/identity, ~/work/zap/gossip, ~/work/zap/pay. ML-DSA-65 primitive is reused from ~/work/lux/crypto/mldsa — exactly one ML-DSA implementation in the Hanzo + Lux tree.

Security considerations

means total compromise. The MNEMONIC env var MUST come from KMS in production deployments; never plaintext on disk. The LIGHT_MNEMONIC is public-by-design and used only on dev / primary local networks.

TXT is not exploitable because the connecting peer must produce a fresh ML-DSA signature over the server-supplied nonce. Roles with auth=none (static, gateway brochures) skip auth because nothing sensitive is exposed.

Receipts are ML-DSA-signed by the same key that signed the discovery handshake, so the consumer can refuse and the on-chain contract rejects unsigned receipts. For high-value calls, the consumer SHOULD request a quorum.

bogus records. Lux consensus rate-limits per account at the protocol level; per-mldsa_address write-throttle is applied during the wave voting round.

tenants MUST use a network-id assigned by the Hanzo registry. Consumers SHOULD pin nid at startup; cross-network bridging requires explicit operator opt-in.

are publicly known; their balances on network 1337 are testnet-only and have no value beyond the dev mesh. Production networks MUST NOT pre-allocate from a public mnemonic.

alone) MUST NOT appear in the handshake-auth or receipt-signing path. ML-DSA-65 is the single primitive. BLS may continue to appear in consensus aggregation per Quasar PQModeBLSPlusMLDSA.

Adoption order

  1. Identity-only: hanzo_zap_mdns.publish ships ML-DSA address in

TXT (small change). Consumers log-but-accept missing addresses for one release, then enforce.

  1. Handshake: ZAP server + client gain the AUTH step. Roll out

server-side first (accept-anonymous), then client-side (always sign), then make server-side reject anonymous for auth-required roles.

  1. Genesis pre-fund: land in lux/genesis for network 1337 and any

new tenant network being launched after this date.

  1. Gossip: hanzo-mcp, hanzo-desktop, hanzo-node add the Lux

light client.

  1. Payments: hanzo-engine first (highest call volume); HMM routes

real load through receipts; remaining roles enable as priced APIs come online.

  1. Containers: hanzoai/container gains the boot-time identity step;

downstream zoo / hanzo deployments inherit automatically.

Each step is a 5-to-30-line change in the service's startup path, mirroring the HIP-0069 adoption shape. One mnemonic, three bindings, six steps.

NIST process posture

NIST does three separate things; conflating them produces wrong expectations:

| process | what it does for us | reality in 2026 | |---|---|---| | FIPS PQC standardization (FIPS 203/204/205/206/207, SP 800-208) | algorithm becomes a NIST-approved primitive | See per-standard table below. ML-DSA-65 (FIPS 204) and SLH-DSA (FIPS 205) are the two FIPS-final PQ signatures today; XMSS / LMS (SP 800-208) cover the stateful-HBS lane. | | MPTC threshold call (NIST IR 8214C) | threshold schemes submitted as reference material for public analysis | active now. IR 8214C published January 2026. First-call package deadline expected 2026-Nov-16; preview writeup deadline 2026-Jul-20. 26 first-round preview writeups already submitted from 23 teams. | | CAVP / CMVP | a specific module implementing approved algorithms is FIPS 140-3 validated | unchanged. CMVP requires an applicable approved standard + an ACVP / CAVP test path. A non-standard threshold variant cannot ride this lane until NIST creates an applicable approved threshold standard. |

NIST PQC standardisation snapshot (2026-05):

| standard | algorithm | role | status | |---|---|---|---| | FIPS 203 | ML-KEM (formerly Kyber) | KEM | final, August 2024 | | FIPS 204 | ML-DSA (formerly Dilithium) | signature | final, August 2024 | | FIPS 205 | SLH-DSA (formerly SPHINCS+) | signature, hash-based | final, August 2024 | | FIPS 206 | FN-DSA (formerly Falcon) | signature | IPD published 2025-10; public-comment period closed 2026-01; final draft pending | | FIPS 207 (planned) | HQC-KEM | KEM, code-based backup to ML-KEM | selected 2025-03; draft expected 2026-2027 | | SP 800-208 | XMSS / LMS (stateful HBS) | signature, hash-based | final; approved with stateful-key-management caveats |

Per-mode NIST positioning

| Pulsar-M (M-LWE) | target Class N1 (signing) + N4 (ML keygen / DKG) — IF the threshold-produced signature verifies under unmodified FIPS 204 ML-DSA.Verify. Output interchangeability is the headline pitch. Falls back to Class S if interchangeability cannot be achieved. | | Pulsar (R-LWE) | target Class S1/S4 — special threshold-friendly primitive. Not output-interchangeable with any NIST-approved primitive. Submitted alongside Pulsar-M but with a different framing. | | Corona (R-LWE academic) | not submitted. Federation-MPC use case only. Trusted-dealer DKG + BLAKE3 hash both rule it out of MPTC. | | ML-DSA-65 raw | already FIPS 204; we ship as the audit / FIPS-spirit fallback (the mldsa PQMode). No NIST submission needed; we just consume the standard. | | BLS-12-381 | not on any NIST track. Used for the classical fast path only; no FIPS claim. |

Pulsar-M boots as ~/work/lux/pulsar-m. The repo structure follows NIST IR 8214C §5 package requirements: technical specification, reference implementation, experimental-evaluation report, notes on patent claims, open-source license, build/test/benchmark scripts, I/O test vectors, public repository.

Calendar

NOW → 2026-Jul-20      preview writeup
2026-Jul-21 → 2026-Aug                  first reference impl + KATs
2026-Sep                                experimental-evaluation report + ePrint v0.1
2026-Oct                                external cryptanalysis engagement begins (rolling)
2026-Nov-16            MPTC package submission (NIST first call)
2027                   public-analysis response, revisions
2028+                  if NIST publishes an approved threshold standard, CMVP track opens

Related HIPs — layered architecture

The Z-Chain PQ rollup is specified in HIP-0078; the Q-Chain finality block format is in HIP-0079; the Pulsar-M threshold-signing primitive is in HIP-0084. This HIP (0077) is the umbrella; refer to the three child HIPs for the layered architecture.

References

Canonical citations (verified against ePrint and conference proceedings):

"Corona: Practical Two-Round Threshold Signatures from Learning with Errors" — Cryptology ePrint Archive 2024/1113.

Signatures from Threshold Homomorphic Encryption"* — PQCrypto 2024, ePrint 2023/1318.

n-out-of-n and Multi-Signatures and Trapdoor Commitment from Lattices"* — PKC 2021, ePrint 2020/1110.

public key and signature systems"* — ACM CCS 1997. Mobile-adversary model for proactive resharing.

Standard"* — August 2024.

TupleHash derived functions.

Schemes"* — January 2026.

Tracked in ~/work/lux/pulsar-m/spec/references.bib so the spec PDF and the HIP both cite from the same authoritative source.