Adds the Tier A bridge endpoint submission package:
- SUBMISSION.md cover sheet, headline claims, scope
- SPEC.md bridge state machine, custody MPC,
oracle attestation, relay protocol
- PROOF-CLAIMS.md P1-P6 proved, N1-N6 not proved
- TRUSTED-COMPUTING-BASE.md TCB inventory (HW/OS, primitives, quorums)
- PATENTS.md royalty-free patent grant
- CRYPTOGRAPHER-SIGN-OFF.md APPROVED WITH GATES, 5 gates listed
- DEPLOYMENT-RUNBOOK.md operator playbook (build / deploy / MPC
ceremony bootstrap / profile transition /
LSS rotation / pause / monitoring)
- LEGACY-CLASSICAL.md LUX_PROFILE=classical-compat opt-in docs
- CHANGELOG.md per-release changes (incl. Tier A pass)
Also strips the deprecated privacy-layer section from LLM.md (the
contracts it described were removed in commit 78e2dd7). The privacy
section is replaced with a brief pointer to git history and to the
Warp 2.0 envelope path which is the canonical surface today.
No code changes in this commit. The strict-PQ profile gate, six-
scheme threshold-signer bus, and EXTCODEHASH allow-list were all
landed in prior commits (b0ff75e, 5c64d64, bdfc56c, ddc5547). This
commit closes the documentation gap.
The cryptographer sign-off is APPROVED WITH GATES (5 gates listed,
all docs / runbook / interop deliverables, none algorithmic).
10 KiB
LEGACY-CLASSICAL — opt-in classical-compat profile
This document explains the LUX_PROFILE=classical-compat opt-in
profile, when to use it, what its security tradeoffs are, and how to
transition from it to LUX_PROFILE=quasar-strict-pq.
TL;DR
The default for Teleport deployments going forward is the strict-PQ profile:
export LUX_PROFILE=quasar-strict-pq
# MPC_SCHEME defaults to double-lattice (Pulsar ⊕ Corona)
# On-chain strict-PQ slot must hold a STARK/FRI/SHA-3-PQ or ML-DSA-65 verifier
The classical-compat profile is an opt-in for two narrow deployment contexts:
-
Bridging to a classical L1 EVM (Ethereum mainnet, Base, Arbitrum, Optimism) where there is no PQ verifier precompile and the destination chain expects EIP-712 oracle signatures.
-
Migration / interop testing where a deployment is mid-transition between Phases 1 and 5 of the Warp 2.0 rollout (see
WARP2_BRIDGE.md§"Migration path") and needs the legacy ECDSA path live for back-compat.
For any new deployment that does NOT fall into one of these two buckets, the strict-PQ profile is the right choice.
How the profile resolves
The profile is set via the LUX_PROFILE environment variable:
| Value | Meaning |
|---|---|
quasar-strict-pq |
PQ everywhere. MPC defaults to double-lattice. On-chain strict-PQ slot must hold a PQ verifier. |
classical-compat |
Legacy ECDSA / GG18 path. MPC defaults to ecdsa. On-chain strict-PQ slot accepts any verifier (including BN254 / BLS12-381). |
hybrid |
Reserved. Permissive on scheme; emits WARN; today behaves like classical-compat on the on-chain gate (refused under strict-PQ profile). |
| unset | THROWS. Fail-closed — no implicit default. |
There is no fourth option. The off-chain resolver
(mpc/src/signers/index.ts) and the on-chain gate
(StrictPQProfileGate.sol via @luxfi/pq-profile-ids) read the same
profile constants from the same canonical package, so the two sides
cannot drift.
Legacy STRICT_PQ=1 is still honored with a one-time deprecation
warning — it is equivalent to LUX_PROFILE=quasar-strict-pq. New
deployments should use the canonical variable name.
What classical-compat means for the off-chain pipeline
| Component | Classical-compat behaviour |
|---|---|
| MPC service default | MPC_SCHEME=ecdsa (GG18 spawn) |
| Admissible MPC schemes | {ecdsa, cggmp21, frost} |
| Forbidden MPC schemes | {pulsar, corona, double-lattice} — throws "incompatible" error |
| API signing path | ECDSA EIP-712 via bridge.ts (legacy) |
| PQ envelope path | Not used (isStrictPQ() returns false) |
| Wire format | Identical to v1 EIP-712 oracle signatures (no Warp 2.0 envelope) |
The classical-compat profile preserves the legacy v1 wire format byte-for-byte. A deployment running classical-compat is indistinguishable from a pre-2026 Teleport deployment on the wire.
What classical-compat means for the on-chain endpoint
| Component | Classical-compat behaviour |
|---|---|
BridgeV2.activeProfile |
PROFILE_CLASSICAL_COMPAT |
BridgeV2.activeVerifier slot |
Any verifier (BN254 / BLS12-381 / STARK / ML-DSA all admissible) |
BridgeV2.p3qVerifier slot |
Same — any verifier admissible (still restricted to POLICY_STARK_FRI_SHA3_PQ for the P3Q slot specifically, by the setP3QVerifier install-time check, which is profile-independent) |
StrictPQProfileGate.refuseUnderStrictPQ |
No-op — returns immediately under classical-compat |
Bridge.sol (v1) |
Still operational; same EIP-712 path as pre-Tier-A |
The classical-compat profile is the back-compat surface for Phase
1 deployments (Bridge.sol only) and for destination chains that
have no PQ precompile.
When to opt in
Use case 1: Bridging to a classical L1 EVM
If the destination chain is Ethereum mainnet, Base, Arbitrum, Optimism, or any other EVM L1 that does NOT have:
- BN254 pairing precompile (
0x06,0x07,0x08) — needed for classical Groth16/PLONK/KZG verifier, OR - STARK/FRI precompile (LP-2517 equivalent) — needed for strict-PQ verifier, OR
- ML-DSA-65 precompile (LP-2517) — needed for strict-PQ verifier
…then the destination chain cannot run the strict-PQ verifier on-chain. The bridge falls back to a classical envelope verifier (Beam BLS only) on those chains, and the off-chain pipeline runs in classical-compat profile.
This is expected and acceptable: the classical-compat profile is the migration surface for chains that have not yet shipped PQ precompiles. The bridge inherits whatever the destination chain provides; it does not force the destination chain to be PQ-capable.
Note that on Ethereum mainnet specifically, the BLS12-381 precompile
(EIP-2537, addresses 0x0b-0x11) is available from the Prague
hardfork; on Lux EVM chains it is available from genesis. The
classical-compat profile uses the BLS12-381 Beam lane only.
Use case 2: Migration testing
During the Warp 2.0 rollout (Phases 2-5 in WARP2_BRIDGE.md),
operators may need to keep the v1 EIP-712 oracle path live while the
v2 envelope path warms up. The classical-compat profile keeps the v1
path operational for this transition.
The recommended sequence:
- Deploy
BridgeV2alongsideBridgewithactiveProfile = PROFILE_CLASSICAL_COMPAT. - Configure
BridgeV2with the same token allowlist asBridge. - Migrate TVL gradually from
BridgetoBridgeV2(user-driven, no forced migration). - Once Warp 2.0 envelope path is battle-tested:
- Switch
BridgeV2.activeProfile = PROFILE_QUASAR_STRICT_PQ. - Install a PQ verifier in the strict-PQ slot.
- Deprecate
Bridge(pause + emergency-withdraw).
- Switch
The classical-compat profile is the back-compat handle that lets this sequence run without downtime.
Security tradeoffs
A classical-compat deployment carries classical security properties:
| Property | Classical-compat | Strict-PQ |
|---|---|---|
| Quantum break of secp256k1 | Forges bridge claims | Does not forge |
| Quantum break of BLS12-381 | Forges Beam-lane envelopes | Does not forge if Pulse + cert set also active |
| Quantum break of M-LWE | N/A | Pulsar lane fails, but Beam + ML-DSA still required if all three are mandatory |
| Quantum break of R-LWE | N/A | Corona lane fails, Pulsar lane still required |
| Verifier downgrade attack | Possible by ADMIN_ROLE (no gate refusal) |
Refused by StrictPQProfileGate at install + EXTCODEHASH allow-list |
| Operations key compromise | Can swap verifiers freely | Limited to verifiers in allowedVerifierCodeHashes (set by DEFAULT_ADMIN_ROLE) |
For deployments that secure value at risk of quantum advance, strict-PQ is the right choice. For deployments that secure value already at classical risk anyway (because the destination chain is classical, e.g. an Ethereum mainnet bridge), classical-compat is the right choice — adding PQ to a strict-classical bridge would not improve the residual.
Hybrid profile (reserved)
LUX_PROFILE=hybrid is reserved for a future deployment model where
the bridge signs with BOTH classical AND PQ in parallel and the
destination chain verifies BOTH:
- Beam BLS (Beam-lane fallback for back-compat)
- ML-DSA-65 cert set (per-validator PQ identity proof)
- Pulse Pulsar threshold (per-round PQ threshold proof)
…and admits a claim only if all three verify. This is stronger than strict-PQ because it requires both a classical AND a PQ break to forge.
The hybrid profile is implemented in the off-chain resolver (permits
any MPC scheme with a WARN log) but is not yet wired in the
on-chain gate — under PROFILE_QUASAR_STRICT_PQ only the PQ schemes
are admissible; classical schemes are refused. A future revision will
add PROFILE_HYBRID to StrictPQProfileGate with a "Beam-required +
any-PQ-lane-required" predicate.
For now, treat hybrid as "classical-compat with the off-chain freedom to also produce PQ signatures for testing".
Migration to strict-PQ
To migrate a live deployment from classical-compat to strict-PQ:
- Deploy a PQ verifier contract that implements
IVerifier(andIPolicyId) and returnsPOLICY_MLDSA65_FIPS204orPOLICY_STARK_FRI_SHA3_PQfrompolicyId(). - Verify the bytecode of the PQ verifier on-chain (Etherscan verify or equivalent).
DEFAULT_ADMIN_ROLE(multi-sig + timelock) callssetAllowedVerifierCodeHash(extcodehash(verifier), true)to extend the allow-list.ADMIN_ROLEcallssetActiveProfile(PROFILE_QUASAR_STRICT_PQ, verifier). The call reverts if (a) the verifier isaddress(0), (b) the verifier'spolicyIdis not in the PQ allow-list, or (c) the verifier's bytecode hash is not allow-listed.- Off-chain: update the API / MPC service config to
LUX_PROFILE=quasar-strict-pq. The MPC default flips todouble-lattice; classical schemes (ecdsa,cggmp21,frost) are refused.
Both sides MUST be migrated in the same maintenance window. A
deployment with LUX_PROFILE=quasar-strict-pq on the off-chain side
and PROFILE_CLASSICAL_COMPAT on the on-chain side will fail the
KAT (the off-chain double-lattice signature is not a valid input to
the classical verifier) — the test suite catches this in
mpc/__tests__/signers.test.ts (case "LUX_PROFILE=classical-compat
- PQ MPC_SCHEME throws clear error (symmetric)").
Rollback
If a strict-PQ deployment hits a verifier bug or an operational issue, the rollback path is:
PAUSER_ROLEcallspause()to stop new claims.ADMIN_ROLEinvestigates: is the issue in the PQ verifier (e.g. a precompile bug), in the off-chain signer (e.g. anmpcdcrash), or in the envelope verifier?- If safe to do so,
ADMIN_ROLEcallssetActiveProfile(PROFILE_CLASSICAL_COMPAT, anyVerifier)to fall back to classical-compat. The off-chain config must also flip toLUX_PROFILE=classical-compat. PAUSER_ROLEcallsunpause()once the rollback is verified.
Rollback to classical-compat does NOT bypass the EXTCODEHASH allow-list (the allow-list is profile-independent for the strict-PQ slot — once allow-listed, a verifier can be installed under either profile). It DOES allow a wider set of verifiers in the slot (including BN254 / BLS12-381 ones), which is the back-compat handle.
References
WARP2_BRIDGE.md— Phase 1-5 migration planSPEC.md§3 — Strict-PQ profile gateSPEC.md§4.2 — MPC profile resolutionCRYPTOGRAPHER-SIGN-OFF.md— Gate analysis@luxfi/pq-profile-ids— Canonical profile / policy ID constants