HIP-79: Q-Chain — Quasar Finality Block Standard. Status Draft. Hanzo's own standard — read this before implementing against it.
Q-Chain is the compact finality-block log for the Quasar consensus engine. Each Q-Block carries the minimum information needed for finality: roots of the validator / DKG / identity state held in Z-Chain (HIP-0078) plus a single Pulsar-M-65 threshold signature (HIP-0084) that proves the current epoch's committee finalised the block. Q-Chain does not carry raw ML-DSA validator pubkeys, raw ML-DSA per-validator signatures, raw DKG transcript messages, or raw attestation blobs — those live in Z-Chain.
The result: a finality lane whose per-block size is bounded and small (a few hundred bytes plus one ~3.3 KB Pulsar-M-65 signature), independent of validator-set size. Adding validators makes Z-Chain heavier, not Q-Chain.
QBlock {
version uint16
network_id uint32
chain_id uint32
height uint64
round_or_view uint32
parent_qblock_hash [32]byte
// State roots — Z-Chain anchors. Each MUST equal the latest
// accepted EpochCommitment field for the current epoch.
lux_state_root [32]byte // Lux primary state at this height
zchain_state_root [32]byte // anchors EpochCommitment.zchain_state_root
validator_set_root [32]byte // anchors EpochCommitment.validator_registry_root
committee_root [32]byte // anchors EpochCommitment.committee_root
dkg_transcript_root [32]byte // anchors EpochCommitment.dkg_transcript_root
group_public_key_hash [32]byte // anchors EpochCommitment.group_public_key_hash
// Payload anchors — block-specific data lives elsewhere.
payload_root [32]byte // application transactions
da_root [32]byte // data-availability commitment
// Cert envelope.
proof_system_id ProofSystemID // = 0x10 STARK_FRI_SHA3_PQ canonical (0x80/0x81 refused)
hash_suite_id HashSuiteID // = 0x01 SHA3_NIST canonical
sig_scheme_id SigSchemeID // = 0x52 Pulsar-M-65 default; 0x53 for high-value roots
// Signature.
signer_bitmap_or_weight_commitment []byte // who attested (committee bitmap or weight Merkle root)
pulsar_m_threshold_signature []byte // single threshold sig over the canonical transcript
}
Hard exclusions:
identity_root).dkg_transcript_root). references zchain_state_root by hash; the proof itself only ships at epoch boundaries).
A Q-Block that carries any of these violates the spec and MUST be rejected. The wire format does not have fields to hold them; this is an enforcement-by-construction guarantee.
The transcript Pulsar-M signs over for a Q-Block is computed as:
TranscriptHash = TupleHash256(
[ "Q-Chain/v1",
version, // 2 bytes BE
network_id, // 4
chain_id, // 4
height, // 8
round_or_view, // 4
parent_qblock_hash,
lux_state_root,
zchain_state_root,
validator_set_root,
committee_root,
dkg_transcript_root,
group_public_key_hash,
payload_root,
da_root,
[proof_system_id], // 1
[hash_suite_id], // 1
[sig_scheme_id], // 1
signer_bitmap_or_weight_commitment ],
customization = "PULSAR-M-Q-BLOCK-V1")
TupleHash256 per NIST SP 800-185 is used for unambiguous length-prefixed tuple hashing. Customisation tags pin the protocol version; bumping "v1" → "v2" is the only way to reuse the same transcript bytes for a breaking change. Hash family is HashSuiteID = 0x01 SHA3_NIST only — HashSuite-mismatched Q-Blocks are not produceable on Lux primary network.
A full node accepts a Q-Block at height H iff every of the following holds:
parent_qblock_hash matches the chain tip.zchain_state_root matches the latest accepted Z-Chain epoch root.validator_set_root matches the latest accepted Z-Chain validator_registry_root (per EpochCommitment).
committee_root matches the latest accepted Z-Chain committee_root.
dkg_transcript_root matches the latest accepted Z-Chain dkg_transcript_root.
group_public_key_hash matches the latest accepted Z-Chain group_public_key_hash.
proof_system_id is NOT in the forbidden set (IsForbiddenInPQMode() == false); strict-PQ networks require 0x10 STARK_FRI_SHA3_PQ.
hash_suite_id == 0x01 SHA3_NIST.sig_scheme_id ∈ {0x52 Pulsar-M-65, 0x53 Pulsar-M-87} for mainnet; testnet may also accept 0x51 Pulsar-M-44.
signer_bitmap_or_weight_commitment satisfies the configuredthreshold (43-of-64 default per HIP-0084).
pulsar_m_threshold_signature verifies under unmodified FIPS 204 ML-DSA.Verify against the canonical transcript hash and the group public key derived from group_public_key_hash.
If any check fails, the block is rejected and a slashing-evidence record is produced per HIP-0084 §"Identifiable abort".
| parameter | value | |----------------------|--------------------------------| | version | 0x0001 | | proof_system_id | 0x10 (STARK_FRI_SHA3_PQ) | | hash_suite_id | 0x01 (SHA3_NIST) | | sig_scheme_id | 0x52 (Pulsar-M-65) | | committee size | 64 | | BFT fault bound | f = 21 | | threshold | 43-of-64 | | epoch length | network-configurable; start 1 hour | | DKG cadence | once per epoch (HIP-0084) | | online signing | preprocessing-enabled | | abort handling | identifiable abort required |
High-value roots (governance, bridges, slashing, archival) MAY upgrade sig_scheme_id to 0x53 Pulsar-M-87 for the duration of the operation. Block consumers MUST accept either.
PQModeQuasar (consensus/config/pq_mode.go) maps to:
proof_system_id = 0x10 STARK_FRI_SHA3_PQhash_suite_id = 0x01 SHA3_NISTsig_scheme_id = 0x52 Pulsar-M-65 (default) or 0x53 Pulsar-M-87 (high-value)The legacy "Pulsar.R + Groth16/BN254 Z-Chain rollup" wire shape from the prior HIP-0077 is retired with the migration to Z-Chain v1 (HIP-0078 Phase 3 flag day).
proof_system_id = 0x80 or 0x81 is refused before signature verification. The forbidden markers exist on the wire so a misconfigured operator's block is named, not silently accepted.
(per-validator BLS + ML-DSA, classical/PQ hybrid) are NOT in this HIP. A future variant MAY add hybrid-cert support but it lives in a follow-up HIP, not here.
flipping any one breaks signature verification.
validated against committee_root; an attacker who flips a bit must produce a valid Pulsar-M sig over the modified transcript, which reduces to forging Pulsar-M.
network_id and chain_id are boundinto the transcript; a Q-Block valid on Lux mainnet is not valid on a tenant network.
consensus/pkg/wire/qblock.go reference encoder/decoder.~/work/lux/consensus/qblock-vectors/ coveringacceptance, refusal-on-forbidden-proof-system, transcript binding.
consensus/protocol/quasar/) consumes Q-Blocks from WitnessSet.Run outputs.
chains/quasarvm (planned location) implementsacceptance rule.
proof_system_id = 0x10requirement on Lux primary network.