Build the post-quantum migration layer before it becomes urgent
QLSA aggregates thousands of post-quantum signatures into a single constant-size proof, targeting scalable blockchain verification without trusted setup and without forcing a hard fork.
QLSA (Quantum-Layered Signature Aggregation) is an open deep-tech project exploring how ML-DSA, Merkle commitments, and STARK proofs can make post-quantum blockchain systems operationally viable.
What's been built
Phase 6 complete — live on Ethereum Sepolia (2026-05-05). The V23 production pipeline proves 8 ML-DSA circuits in a single STARK (3,505 trace columns), and BatchRegistryV6 + QLSAVerifierVFRI10 finalize a batch on-chain within the per-transaction gas cap.
Milestones since then:
- VFRI11 — Poseidon2 t=8 backend (2026-06-16): 4-word/124-bit nodes → ~262 node collision. Full-V23
verify()at depth-10 exceeds 100M gas — which is what motivated recursion. - Path decision (2026-06-17): skip a standalone t=16 verifier (~4× worse gas) and go straight to proof recursion — a STARK proving “I verified a VFRI11 STARK”, where the inner hash can be any width for free.
- Recursion gadget set + soundness closure (R0.1–R3.12): QM31 arithmetic, FRI fold/OODS, inner-hash Merkle path, Fiat-Shamir absorb/draw, per-query composition. Two-expert audits closed every composition-level gap — C1 (outputs pinned in-circuit), C2 (every preprocessed-column verifier pins Tree 0 via a canonical recomputed root), 1a (all verifier-fixed FRI challenges pinned), and Merkle root binding.
- 128-bit inner-hash ladder complete (R3.13–R3.18): t=2 → t=8 → t=16 (8-word/248-bit nodes, ~2124 ≈ 128-bit), each rung a pure hash-backend swap with compression AIR, Merkle-path AIR and single-/N-query composition.
- The recursion verifies the real pipeline (R4.1): per-query inputs are extracted from a genuine VFRI11 FRI chain and proven against the committed last-FRI-layer root.
- On-chain half assembled (R4.2–R4.5): the cheap Poseidon2 channel replay runs on-chain —
RecursiveChannelReplay.solreproduces the Rust reference byte-for-byte, andQLSAVerifierRecursive.solbinds an outer proof to the inner publics viakeccak(traceRoot‖lastLayerRoot). - Measured limit (R4.6): the channel replay and the binding root verify on-chain today; driving the outer proof through the deployed VFRI11 exceeds a 29M-gas call even with a compacted outer trace. Next: a cheaper outer backend (t=4) or a per-transaction split, exactly as
BatchRegistryV6already does for V23.
poseidon2_t{8,16}_air verify_compress bound (left,right,node) only via Fiat-Shamir → a false compress(FAKE)=node claim could verify (latent, test-only, not production); now pinned in-circuit (raw_pin/node_pin + gated equality, regressions test_forged_input_cannot_prove). + t=16 matrix naive cross-checks + stale-doc/capacity fixes. All else clean. 152 recursive tests, 513 total.vfri11_fri_chain (byte-identical to the ABI hint generator) + gen_vfri11_recursion_inputs: the t=8 composition proves the inner proof's per-query decommitments against the genuine committed last-FRI-layer root. "Root vs committed FRI-layer root" closed at the Rust level; index-oriented twiddle-inverse trick + hard extraction invariant.leaf = hash(finalFold) end-to-end in-circuit. 150→152 recursive tests.root pinned in-circuit (is_root/root preproc columns, is_root·(s0 − root_pinned)=0); before, a malicious prover could prove a FALSE root claim with adversarial siblings (only reuse was blocked). depth is an explicit public input, matching on-chain MerkleVerifier.verify. Regression test_forged_root_cannot_prove. [Code — fixed] MAX_QUERIES/MAX_NUM_FOLDS/MAX_DEPTH/log_size/capacity caps close panic/OOM paths (div-by-zero at depth 0, OOB preproc writes, 2^40 allocs). 104 recursive tests, 453 total.QueryChallenges bundle (alpha, z_x, px, inv) pinned via 17 preprocessed columns + in-circuit equality constraints; threaded through single/multi/composition. test_forged_alpha_cannot_prove, test_forged_zx_inv_px_cannot_prove.composition.rs: recursive_verifier + merkle_path in ONE multi-component STARK — fold chain → hashLeaf → Merkle path, value-bound end-to-end; N-query (VFRI11 shape) via multi-path merkle (N paths in one component, AIR unchanged).fin preproc columns + is_output-gated constraint; [C2] canonical Tree-0 pinning (canonical_preproc_root) in ALL preprocessed-column verifiers: 4 recursion sub-gadgets + 5 production V23 is_init_uh verifiers + Poseidon2 hash-chain. Forged selectors no longer verify.root/finalFold/digest) bound only via Fiat-Shamir, no in-circuit constraint; [C2, reproduced] preprocessed selectors/constants prover-supplied & unpinned (forged is_step verifies). Same pattern in mature V23/VFRI — per-circuit follow-up. Robustness fixes applied (caps, guards, asserts). Must close C1/C2 before production wiring (R3.7). Resolved: see R3.7–R3.12 above.transcript_draw_air.rs: proves the Poseidon2 t=2 duplex-sponge squeeze chain (drawSecureFelt/drawQueries core) — the dual of channel_air absorb. 8 main + 7 preproc cols; matches P2Channel::draw_pair. 11 Rust tests. Full recursion gadget set complete: 88 tests.prove_recursive_queries: N per-query FRI chains in ONE STARK — N blocks of (1+K) rows, the same AIR (per-row selectors gate each block), all finalFolds bound. 5 Rust tests.recursive_verifier.rs: OODS± + circle fold + K line folds in ONE AIR, data flow enforced by a cross-row constraint (42 main + 2 preproc). integration.rs: recursive_verifier → qm31_leaf_hash → merkle_path_air — full per-query FRI verification value-bound across 3 sub-proofs. 9+3 Rust tests.fri_fold_chain_air.rs: K line-fold rounds chained via a cross-row constraint input[k]=output[k−1] (21 main + 1 preproc). 9 Rust tests.recursive/query_step_air.rs: first composition gadget — chains OODS± + circle fold in one row per query. 42 cols, 16 degree-2 constraints; step_ref() cross-checks against oods_air + fold_air references; generic qmul<F> deduplicates QM31-mul expansion. 7 Rust tests.merkle_path_air.rs: proves leaf@index+siblings→root via Poseidon2 t=2 compression (10 main + 4 preproc cols; index-bit child selection; cross-row cur chaining). channel_air.rs: proves Poseidon2 duplex sponge absorption — mixU32s core (7 main + 4 preproc cols). 10+9 Rust tests.fold_air.rs: proves folded=(f₊+f₋)+α·(f₊−f₋)·inv (21 cols; helper column p lowers degree to 2). oods_air.rs: proves fₚ·(px−z_x)=compValue−oodsCombo (17 cols; multiplicative form avoids QM31 inverse). 8+8 Rust tests.z limb). Fixed: deploy_v6.sh --network flag (silently ignored → wrong-network deploy risk), CLI arg validation, web3 HTTP timeouts, .env.deployed 0600, t=8 sponge % P input reduction (Rust parity), QM31 limb-canonicity precondition.recursive/qm31_mul_air.rs proves z = x·y in QM31 = CM31[u]/(u²−R), R = 2+i. 12 cols, 4 degree-2 constraints, no preproc; full Stwo prove/verify roundtrip + cross-check against the u128 reference (u²=R, 1·y=y). The load-bearing primitive for circleFold/lineFold/OODS. Decision: skip the standalone t=16 verifier — t=16 becomes the recursion's inner hash AIR (constant on-chain cost).poseidon2_t8.rs + Poseidon2M31T8.sol / Poseidon2MerkleVerifierT8 (4-word/124-bit nodes → ~2^62 collision) / Poseidon2ChannelT8 (217-bit capacity), cross-checked bit-exact. QLSAVerifierVFRI11 = VFRI10 protocol on t=8 (identical ABI, version marker 5); generic verify()==true at ~13.1M gas. Gas finding: full-V23 t=8 verify >100M gas → production needs recursion.ReplayedTxError — a batched tx can no longer be re-batched), submit error-text hardening, /stats overflow metric, #[cfg(test)] gating test fixtures out of the release library, and an FRI tree_depth ∈ 2..=30 guard. 6 fixed, 1 false-positive, 2 documented research-defaults.QLSAVerifierVFRI10 wires the t=4 wide Merkle (Poseidon2MerkleVerifierT4) + t=4 Fiat-Shamir channel (Poseidon2ChannelT4) into the VFRI9 proof path (byte-identical ABI, version marker 4). V23 cross-bound Rust/PyO3/Python pipeline + dual-group on-chain E2E via BatchRegistryV5. Each V23 group verify() ≤16.7M gas; lifts the node/transcript collision wall above the t=2 ceiling (~2^31).BatchResult.has_vfri9 + vfri9 proof/commitment/hints fields; Batcher._try_prove calls prove_mldsa_sig_vfri9_stark; API /batch/run, /batch/{id}/witness, /batches expose has_vfri9; Python SDK WitnessStatus/BatchStatus extended; JS SDK WitnessStatus/BatchStatus gain hasVfri9 + RawBatchStatus deduplication. pyo3 0.24→0.29: RUSTSEC-2026-0176/0177 fixed.(s0<<32)|s1) and asserts root == friLayerRoots[K] — closes bounded-degree soundness gap in VFRI5–VFRI8. Full-root Fiat-Shamir: mixRootFull absorbs all 32 bytes. BatchRegistryV5 dual-VFRI9.HttpClient._decode_json() guards all 7 JSON call-sites — proxy HTML responses (nginx 2xx) no longer crash the SDK. testnet/e2e.py sender_key recomputation eliminated; unused import hashlib removed. 239 Python tests green.boundRoot10 = keccak256(batchRoot ‖ traceRoot8) — mixing proofs from different witnesses fails Merkle verificationThe Problem
Direct migration from classical signatures to post-quantum signatures can severely inflate block payloads. That turns protocol safety progress into an operational scaling problem.
| Signature | Size | 3000 tx block | Operational impact |
|---|---|---|---|
| ECDSA (current) | ~70 bytes | ~220 KB | Fits today's assumptions |
| ML-DSA-65 (FIPS 204) | ~2,420 bytes | ~7.2 MB | Severe throughput penalty |
The Solution
QLSA is not a new signature scheme. It is a post-quantum aggregation layer that aims to make large signature sets proof-friendly, compact, and verifiable at fixed on-chain cost.
What QLSA does
- Aggregates
NML-DSA signatures into one batch commitment - Uses Merkle commitments to structure batch data
- Generates a STARK proof for batch correctness
- Allows fixed-cost on-chain verification independent of batch size
Why the architecture matters
- Heavy proving remains off-chain
- Public inputs can be kept minimal with commitment roots
- MVP can ship before full ML-DSA-inside-AIR is solved
- The system remains crypto-agile across future upgrades
Architecture
The system is split into three layers so that user flows stay familiar, proving stays off-chain, and on-chain verification remains lean.
Signing
Wallet-level signing using post-quantum keys.
- ML-DSA-65 for signatures
- Address derived from
SHA3-256(pubkey) - Intended to preserve a familiar wallet-style UX
Aggregation
Batch formation and proving pipeline.
- Collect transactions off-chain
- Verify ML-DSA signatures off-chain; V23 proves arithmetic witness (8 circuits) inside STARK
- Build Merkle tree with
SHA3-512; root bound into Fiat-Shamir channel (V22+) - Generate STARK proof — c̃ + merkle_root mixed; RangeQBatch proves az_hat ∈ [0,Q)
Verification
Constant-cost contract-side validation.
- Verify proof in Solidity verifier contract
- Store
merkle_rootand finalize the batch onchain_commitment = Blake2s(proof[:32] ∥ c_tilde[:32])[:16]— 128-bit binding- MVP-6: VFRI8 — Poseidon2 Merkle + Fiat-Shamir channel; 20-query verification ≤15M gas. Both LOG=10 and LOG=8 trace groups verified on-chain with 130-bit soundness.
MVP Strategy
The project intentionally separates realistic implementation milestones from the hardest research component.
| Stage | What STARK proves | ML-DSA in STARK | Status |
|---|---|---|---|
| MVP-1 | Core crypto & Merkle | No | ✓ Done |
| MVP-2 | Hash-chain + Poseidon2 AIR (Stwo) | No | ✓ Done |
| MVP-2b | ML-DSA batch proof (Rust + STARK) | Off-chain | ✓ Done |
| MVP-3+ | All 8 circuits inside AIR + RangeQBatch (V23) | Yes (V23) | ✓ Complete |
| MVP-4 | VFRI4/5/6 — O(1)-gas on-chain FRI verifier; BatchRegistryV4 | Yes | ✓ Done (2026-05-22) |
| MVP-5 | VFRI7 cross-proof binding; security audit round 2; code quality hardening | Yes | ✓ Done (2026-05-30) |
| VFRI8/9 | Poseidon2 Merkle+channel; last-layer FRI check; wide nodes (62-bit); aggregator liveness; API auth | Yes | ✓ Done (2026-06-10) |
| MVP-6 groundwork | Poseidon2 t=4 Rust+Solidity; VFRI9 pipeline; pyo3 CVE fix; JS SDK parity | Yes | ✓ Done (2026-06-12) |
| MVP-6 VFRI10 | t=4 verifier + V23 pipeline + dual-group E2E; security/code audit | Yes | ✓ Done (2026-06-14) |
| MVP-6 t=8 | BatchRegistryV6 per-group split; Poseidon2 t=8 backend; VFRI11 (~2^62 nodes) | Yes | ✓ Done (2026-06-16) |
| Recursion R0.1 | QM31-mul AIR gadget; path decision: skip standalone t=16, t=16 → inner hash of recursion | Yes | ✓ Done (2026-06-17) |
| Recursion R1 | FRI fold AIR + OODS quotient AIR — 8+8 Rust tests | Yes | ✓ Done (2026-06-17) |
| Recursion R2 | Poseidon2 Merkle auth-path AIR + Fiat-Shamir sponge-transcript AIR — 10+9 Rust tests | Yes | ✓ Done (2026-06-17) |
| Recursion R3.1 | Per-query FRI step (first composition gadget: OODS± + circle fold) — 7 Rust tests | Yes | ✓ Done (2026-06-17) |
| Recursion R3.2–R3.6 | FRI fold chain, per-query verifier, integration, N-query aggregation, Fiat-Shamir draw — full gadget set (88 tests) | Yes | ✓ Done (2026-06-17) |
| Recursion audit | C1/C2 codebase-wide (R3.7), 1a (R3.10–11), Merkle root binding (R3.12), compression input/output binding (R3.13–R4.1) | Yes | ✓ Done (2026-07-16) |
| Recursion R3.13–R4.1 | 128-bit inner-hash ladder (t=8/t=16 compression + path + composition) + verifies real VFRI11 pipeline — 152 recursive tests | Yes | ✓ Done (2026-07-16) |
| Recursion R3.7–R3.12 | Composition (single + N-query, VFRI11 shape), QueryChallenges pinning, root binding — 104 recursive tests | Yes | ✓ Done (2026-07-10) |
| Recursion R3–R4 | Full recursive verifier composition → QLSAVerifierRecursive (~5M gas constant) | Yes | ⏳ In Progress |
| MVP-6 | VFRI8: Poseidon2 Merkle + channel; 20-query ≤15M gas; BatchRegistryV5; security & code audit | Yes | ✓ Done (2026-06-10) |
Key risks
- ML-DSA inside STARK: All 8 circuits complete in V23 (NttBatch + AzFull + Ct1Full + InttBatch + WPrimeFull + NormCheckBatch + UseHintBatchV2 + RangeQBatch), 3,505 trace columns, 1 FRI commitment. c̃ + Merkle root Fiat-Shamir bound; RangeQBatch closes AzFull multiplication soundness gap.
- Aggregator trust model: the MVP relies on off-chain verification before challenge systems exist.
- Adoption timing: the need is real, but mainstream migration may still take years.
Tech Stack
The technical stack reflects a staged path: fast iteration now, stronger proving infrastructure later.
Cryptographic core
- ML-DSA-65
- SHA3-512 for Merkle hashing
- SHA3-256 for address derivation
- Python 3.10+
liboqs-python >= 0.14.0
STARK layer
- Stwo 2.2.0 — Circle STARK over M31 field
- Poseidon2-over-M31 AIR (t=2, α=5, 8 full rounds, 7 columns, 6 constraints ≤ deg 3)
- V23 single STARK: 8 ML-DSA circuits, 3,505 trace columns, 1 FRI commitment
- ML-DSA-65 FIPS 204 verifier in Rust; c̃ + Merkle root Fiat-Shamir binding
- FRI blowup ×64, N_FRI_QUERIES=20, POW_BITS=10 — 130-bit soundness; zeroize crate for secure key wipe
- nightly-2025-07-01 Rust toolchain
Contracts & infra
- Solidity + Hardhat 2.28
- VFRI8 verifier stack: CM31 · QM31 · Blake2s · Poseidon2M31 · Poseidon2MerkleVerifier · Poseidon2Channel · CirclePoint · QLSAVerifierVFRI8
- BatchRegistryV5 — dual-VFRI8 with cross-proof binding
- FastAPI aggregator + rate limiting (proxy-aware, stale eviction)
- Python SDK (Wallet, LocalClient, WitnessStatus) + TypeScript SDK
Performance targets
| Batch size | 3,000 tx |
| Proof size | 90–200 KB |
| On-chain verification | O(1) |
| ML-DSA-65 sign (avg) | 0.12 ms / tx |
| Merkle build N=3000 | 7.1 ms |
| Full pipeline N=3000 | 354 ms |
| V23 STARK columns | 3,505 (649+1523+295+649+24+15+61+288+1 preproc) |
| 20-query VFRI9 gas | ≤15M gas (wide Poseidon2 Merkle, last-layer check) |
| Solidity tests | 1,011 passing |
| Python tests | ~560 passing (with PyO3) / ~350 without |
| Rust tests | 516 passing (152 recursive) |
| TS tests | 71 passing |
| CI pipeline | 6 / 6 jobs green |
Repository snapshot
QLSA/
├── core/ # ML-DSA, Merkle, batch
├── aggregator/ # Mempool, batcher, FastAPI
├── stark/ # Python prover/verifier wrappers
├── stark_stwo/ # Stwo STARK + ML-DSA AIR circuits
├── contracts/
│ └── src/verifier/
│ ├── CM31.sol # GF((2³¹−1)[i])
│ ├── QM31.sol # quartic extension
│ ├── Blake2s.sol # pure-Solidity
│ ├── Poseidon2M31.sol # t=2 over M31
│ ├── Poseidon2M31T4.sol # t=4 over M31 (VFRI10)
│ ├── Poseidon2MerkleVerifier{,W,T4}.sol # t=2 / wide / t=4 nodes
│ ├── Poseidon2Channel{,T4}.sol # Fiat-Shamir (t=2 / t=4)
│ ├── MerkleVerifier.sol
│ ├── TwoChannel.sol # Fiat-Shamir (Blake2s)
│ └── CirclePoint.sol # CanonicCoset + FRI fold
├── sdk/python/ # Wallet, LocalClient
├── sdk/js/ # TypeScript AggregatorClient
├── testnet/ # E2E demo, deploy, submit
└── tests/ # 1011 Sol + ~560 Py + 516 Rust + 71 TSRoadmap
The roadmap prioritizes a credible implementation path before expanding into the hardest proving research.
Phase 1 — Core
✓ CompleteML-DSA-65/44/87 keys, signing, transaction model, SHA3-512 Merkle tree, batch aggregation.
Phase 2 — STARK Prototype
✓ CompleteStwo 2.2.0 Circle STARK — Poseidon2-over-M31 AIR (t=2, α=5, 8 full rounds, 7 main columns, 4 preproc columns, 6 constraints ≤ deg 3), ML-DSA-65 batch verifier in Rust (FIPS 204), FRI blowup ×4. 128-bit Blake2s commitment. 210 Rust tests green.
Phase 3 — Smart Contracts
✓ CompleteQLSAVerifierFull, QLSAVerifierBound (Merkle-root-bound Blake2s, bytes16 128-bit commitment), BatchRegistry, BatchRegistryV2 — all deployed (Hardhat). Contract tests green.
Phase 4 — Aggregator Node
✓ CompleteIn-memory mempool (thread-safe, atomic drain), auto-batcher with transaction recovery, FastAPI REST endpoint. Full STARK prove→submit pipeline via PyO3 native FFI.
Phase 5 — SDK
✓ CompletePython SDK (wallet + async client) and TypeScript/JavaScript SDK with full input validation and typed API. wipe_key() backed by Rust zeroize crate (volatile writes) for secure key wipe.
Phase 6 — Testnet
✓ CompleteLive on Ethereum Sepolia (2026-05-05). QLSAVerifierBound: 0xF2dcad845F0fb4a11106E4c4cF23D260a3CB65Dd · BatchRegistryV2: 0xF44A51CF1d7620e070ecaf611685418DE4679879. First batch: tx 0x5a9215d2aeb4…bd82, 3234 bytes, finalized in 9.16 s. Security hardening: nonce registry, rate limiting, pubkey validation.
MVP-3+ — ML-DSA Native in AIR (V22/V23)
✓ CompleteAll 8 ML-DSA-65 arithmetic circuits unified in one FRI commitment (V23, 3,505 trace columns): NttBatch (LOG=10, 649 cols) + AzFull (LOG=8, 1523 cols) + Ct1Full (LOG=8, 295 cols) + InttBatch (LOG=10, 649 cols) + WPrimeFull (LOG=8, 24 cols) + NormCheckBatch (LOG=8, 15 cols) + UseHintBatchV2 (LOG=8, 61 cols + 1 preproc) + RangeQBatch (LOG=8, 288 cols). Fiat-Shamir transcript: c̃ → merkle_root → Tree0 → Tree1. RangeQBatch closes AzFull multiplication soundness gap.
MVP-4 — Mainnet-grade On-chain Verifier
✓ Complete (2026-05-22)Full on-chain Circle STARK FRI verifier (Solidity). Verifier library stack: CM31 · QM31 · Blake2sYul · MerkleVerifier · TwoChannel · CirclePoint · QLSAVerifierV4–V13 · VFRI–VFRI6. QLSAVerifierVFRI6: O(1)-gas off-chain OODS combo — 649, 1298 and 2206-column traces all verified within 15M gas. BatchRegistryV4: dual-VFRI6 registry.
MVP-5 — Cross-Proof Binding & Security Hardening
✓ Complete (2026-05-30)QLSAVerifierVFRI7: adds mixRoot(merkleRoot) before drawQueries — FRI query indices depend on the batch Merkle root, preventing proof-mixing attacks. BatchRegistryV4: boundRoot10 = keccak256(batchRoot ‖ traceRoot8) — cross-binding both LOG groups. Security audit round 2: 24 findings resolved. Code audit 2026-06-03.
VFRI8 + VFRI9 — Poseidon2 + Last-layer FRI (2026-06-10)
✓ CompleteVFRI8: Poseidon2 Merkle trees + Poseidon2Channel — 20-query on-chain FRI ≤15M gas. VFRI9: last-layer bounded-degree check (prover supplies all 2^(treeDepth−K) final evaluations; verifier rebuilds tree with wide 62-bit nodes and asserts root match) — closes the FRI soundness gap in VFRI5–VFRI8. Full-root Fiat-Shamir (mixRootFull: all 32 bytes). Aggregator liveness: prover-crash recovery (≤3 retries), prepend_batch overflow accounting, Bearer-token API auth. Security & code audit: 21 findings, 18 fixed. BatchRegistryV5: dual-VFRI9. 917 Solidity + 552 Python + 315 Rust + 71 TS.
MVP-6 — VFRI10 (Poseidon2 t=4 backend) + audit (2026-06-14)
✓ CompleteThe Poseidon2 t=4 permutation (poseidon2_t4.rs + Poseidon2M31T4.sol, cross-checked bit-exact, 124-bit compress, collision ~2^62) is wired into the full proof path: QLSAVerifierVFRI10 swaps the t=2 Merkle/channel for Poseidon2MerkleVerifierT4 + Poseidon2ChannelT4 (byte-identical VFRI9 ABI, version marker 4). V23 cross-bound Rust bridges + PyO3 + Python (prove_mldsa_sig_vfri10_stark) + on-chain dual-group E2E via BatchRegistryV5 — each V23 group verify() ≤16.7M gas (dual-group submitBatch needs a per-group registry or mainnet's 30M). Security + code audit: off-chain replay guard, submit error-text hardening, /stats overflow metric, release-build test-fixture gating, FRI tree_depth guard. 950 Solidity + ~560 Python + 323 Rust + 71 TS.
FAQ
Short answers to the questions most people will ask when they first encounter the project.
Is QLSA a new signature algorithm?
No. QLSA is an aggregation and verification architecture built around post-quantum signatures such as ML-DSA.
Why not just replace ECDSA directly?
Because the size increase of post-quantum signatures can cause major throughput and cost problems if deployed naively.
Does QLSA already prove ML-DSA inside STARK?
Yes — V23 is the production pipeline. All 8 ML-DSA-65 arithmetic circuits are unified in one FRI commitment (3,505 trace columns): NttBatch + AzFull + Ct1Full + InttBatch + WPrimeFull + NormCheckBatch + UseHintBatchV2 + RangeQBatch. c̃ and batch Merkle root are both mixed into Fiat-Shamir, binding each proof to one specific witness and batch.
What on-chain verifier exists?
The latest is QLSAVerifierVFRI10 + BatchRegistryV5 (2026-06-14): the VFRI9 proof protocol (last-layer FRI check + full-root Fiat-Shamir) on the Poseidon2 t=4 hash backend, lifting the node/transcript collision wall above the t=2 ceiling (~2^31) toward 128-bit. Each V23 trace group (LOG=10 / LOG=8) verify() fits within 16.7M gas; the dual-group call needs a per-group registry or mainnet's 30M block limit. Off-chain FRI soundness: LOG_BLOWUP=6 × 20 queries + POW_BITS=10 = 130-bit.
Is this production-ready?
No. QLSA is research-stage software (not audited by external parties; an internal two-expert audit ran 2026-06-14). Infrastructure is fully implemented and tested (950 Solidity + ~560 Python + 323 Rust + 71 TS tests). Not recommended for production use or real funds.
Interested in PQC, ZK proofs, or blockchain infrastructure?
QLSA is an open research and engineering effort. Contributions, technical feedback, research discussion, and collaboration are welcome.