Files
zooqueen e6be5f13a5 papers: retire Pulsar-M -> Pulsar, dead pulsar-m/-mptc repo refs -> luxfi/pulsar, drop subnet terminology
- Pulsar-M qualifier retired (Pulsar is the Module-LWE family; LP-180 rename
  af3d669). Pulsar-M-65/-87 -> Pulsar-65/-87; sec rename 07-pulsar-m -> 07-pulsar.
- Dead repos luxfi/[email protected], luxfi/pulsar-mptc (both 404) -> luxfi/pulsar.
- subnet -> chain/L1, Subnet-EVM -> Lux EVM, subnet VM -> L1 VM.
- PULSAR-MAC-v1 and other domain-sep constants left intact (lookahead-protected).
2026-06-19 21:31:17 -07:00

170 lines
7.3 KiB
TeX

\section{Q-Chain finality: the 23-axis binding}
\label{sec:qchain-finality}
\subsection{What Q-Chain binds}
Q-Chain is the chain that produces finality certificates over every other
chain in the Lux ecosystem. HIP-0079 defines Q-Chain as the
``post-quantum finality plane'': it consumes EpochCommitments from every
execution chain (C-Chain, P-Chain, X-Chain, Z-Chain), folds them into a
canonical QBlock, and produces a Pulsar finality certificate over the
QBlock digest.
The QBlock digest is the single 48-byte commitment that says ``this is the
state of the Lux Network at epoch $N$ under LUX\_STRICT\_E2E\_PQ.''
Everything else --- the bridge admission, the cross-chain Warp envelope, the
Z-Chain commitment binding into a \texttt{TxAuthEnvelope} verification ---
ultimately points back to this digest.
\subsection{The 23 axes}
\texttt{ComputeRoundDigest} (\texttt{luxfi/consensus@12097034},
\texttt{protocol/qchain/round\_digest.go}) binds 23 axes into the QBlock
hash. The axes are the security-relevant inputs to consensus at this round:
\begin{table}[H]
\centering
\caption{ComputeRoundDigest axes. The 23 axes are the inputs to consensus
at a single round. Adding an axis bumps the customization
\texttt{LUX\_QBLOCK\_V1 $\to$ V2} and is a hard fork.}
\label{tab:qblock-axes}
\begin{tabular}{rlp{8cm}}
\toprule
\# & Axis & Role \\
\midrule
1 & \texttt{ProfileHash} & ChainSecurityProfile digest. \\
2 & \texttt{Version} & QBlock version. \\
3 & \texttt{NetworkID} & destination network. \\
4 & \texttt{Epoch} & monotonic epoch counter. \\
5 & \texttt{Height} & Q-Chain height. \\
6 & \texttt{PrevBlockHash} & parent QBlock digest. \\
7 & \texttt{CChainCommitment} & C-Chain EpochCommitment digest. \\
8 & \texttt{PChainCommitment} & P-Chain EpochCommitment digest. \\
9 & \texttt{XChainCommitment} & X-Chain EpochCommitment digest. \\
10 & \texttt{ZChainCommitment} & Z-Chain EpochCommitment digest (\texttt{ZRegistryRoots.Hash()}). \\
11 & \texttt{ValidatorSetRoot} & active validator set Merkle root. \\
12 & \texttt{ValidatorStakeRoot} & per-validator stake commitment. \\
13 & \texttt{BridgeAdmissionRoot} & bridge admission state root. \\
14 & \texttt{TxAuthBatchRoot} & accepted \texttt{TxAuthEnvelope} root for epoch. \\
15 & \texttt{PermitBatchRoot} & accepted \texttt{PQPermit} root for epoch. \\
16 & \texttt{ZIdentityRoot} & shortcut into \texttt{ZRegistryRoots.IdentityRoot}. \\
17 & \texttt{P3qProofRoot} & p3q STARK proof aggregator root for this epoch. \\
18 & \texttt{RandomnessSeed} & DRBG seed for this epoch. \\
19 & \texttt{PrevFinalityCert} & previous epoch's Pulsar cert digest. \\
20 & \texttt{Timestamp} & uint64 epoch timestamp (UTC seconds). \\
21 & \texttt{LineageRoot} & lineage chain digest (HIP-0079 ยง5). \\
22 & \texttt{GovernanceRoot} & active governance state root. \\
23 & \texttt{ExtraHash} & 48-byte HIP-future-reserved digest. \\
\bottomrule
\end{tabular}
\end{table}
Every axis except \texttt{ExtraHash} is consumed by some downstream
verifier. \texttt{ExtraHash} is reserved for future HIP additions: future
proposals will bind new axes into the \texttt{ExtraHash} preimage so the
QBlock layout itself stays stable across the migration window.
\subsection{ComputeRoundDigest}
The construction:
\begin{lstlisting}[language=Go,caption={\texttt{ComputeRoundDigest} for
QBlock. Source: \texttt{luxfi/consensus@12097034},
\texttt{protocol/qchain/round\_digest.go}.}]
func (q *QBlock) ComputeRoundDigest() [48]byte {
parts := [][]byte{
[]byte("Lux/QBlock/v1"),
q.ProfileHash[:],
u16BE(q.Version),
u32BE(q.NetworkID),
u64BE(q.Epoch),
u64BE(q.Height),
q.PrevBlockHash[:],
q.CChainCommitment[:], q.PChainCommitment[:],
q.XChainCommitment[:], q.ZChainCommitment[:],
q.ValidatorSetRoot[:], q.ValidatorStakeRoot[:],
q.BridgeAdmissionRoot[:],
q.TxAuthBatchRoot[:], q.PermitBatchRoot[:],
q.ZIdentityRoot[:], q.P3qProofRoot[:],
q.RandomnessSeed[:],
q.PrevFinalityCert[:],
u64BE(q.Timestamp),
q.LineageRoot[:],
q.GovernanceRoot[:],
q.ExtraHash[:],
}
return tupleHash48(parts, "LUX_QBLOCK_V1")
}
\end{lstlisting}
The Pulsar finality lane (Section~\ref{sec:pulsar}) signs over this
digest. The signature, together with the QBlock body, is the finality
certificate.
\subsection{Canonical QBlock layout}
The QBlock body is the wire-serialised form of the struct above plus the
finality certificate. The wire layout is deterministic big-endian, fixed-width
except for the certificate trailer:
\begin{table}[H]
\centering
\caption{QBlock wire layout. The fixed header is 1{,}080 bytes; the
certificate trailer is the Pulsar aggregate plus committee bitmap, sized
per the active committee (typically $\approx 33$ KB).}
\begin{tabular}{lll}
\toprule
Offset & Size & Field \\
\midrule
0 & 48 & \texttt{profile\_hash} \\
48 & 2 & \texttt{version} \\
50 & 4 & \texttt{network\_id} \\
54 & 8 & \texttt{epoch} \\
62 & 8 & \texttt{height} \\
70 & 48 & \texttt{prev\_block\_hash} \\
118 & 48 & \texttt{cchain\_commitment} \\
$\vdots$ & $\vdots$ & $\vdots$ (per Table~\ref{tab:qblock-axes}) \\
1{,}072 & 8 & \texttt{timestamp} \\
1{,}080 & varies & \texttt{finality\_cert} (Pulsar-65 aggregate + bitmap) \\
\bottomrule
\end{tabular}
\end{table}
\subsection{Finality cert binding to Pulsar}
The Pulsar finality lane (Section~\ref{sec:pulsar}) operates as a
two-round threshold signature scheme over the 43-of-64 active committee.
Round 1 commitments hash the QBlock digest as their session id. Round 2
opens partial signatures that aggregate linearly into a single 33-KB
certificate. The verifier:
\begin{enumerate}[leftmargin=2em,nosep]
\item Recomputes the QBlock digest from the body.
\item Looks up the active committee against
\texttt{ValidatorSetRoot}.
\item Verifies the Pulsar aggregate signature over the digest under the
committee's group public key (which is itself anchored in
\texttt{ZRegistryRoots.IdentityRoot} from the Z-Chain).
\item Confirms the committee bitmap has at least 43 set bits.
\end{enumerate}
Step 2 binds the certificate's committee to the consensus state \emph{at
this epoch}. Step 3 verifies the lattice math. Step 4 enforces the
threshold. The certificate is binding under MLWE.
\subsection{Why 23 axes specifically}
The 23-axis count is the minimum closure of the dependency graph between
the Lux chains. Each axis is the only commitment from \emph{one} subsystem
the verifier needs to confirm that subsystem's state matches what the QBlock
claims. Dropping any axis would force a downstream verifier to consult the
subsystem's own state instead of the QBlock, breaking the ``QBlock is the
single binding'' invariant.
Adding axes is forward-compatible via the \texttt{ExtraHash} reservation;
the next HIP that adds axes binds them into the \texttt{ExtraHash} preimage
and ships an \texttt{ExtraHashV2} struct with the customization
\texttt{LUX\_QBLOCK\_EXTRA\_V2}. The QBlock layout itself does not change
until the migration window closes and a hard-fork to \texttt{LUX\_QBLOCK\_V2}
absorbs the new fields directly.