Releases: wienerlabs/mosaic
v0.2.0-phase2 — PLONK + Groth16 batch production
Phase 2 technical scope frozen. Two production verifier additions plus infrastructure work that unblocks Phase 3.
Headline: two new verifier paths on Solana L1
| Mode | Measured CU | vs Phase 1 |
|---|---|---|
| Groth16 BN254 single | 80,296 | baseline |
| Groth16 BN254 batch N=5 | 230,626 (46K/proof) | -42.6% |
| KZG-PLONK BN254 | 747,666 | new |
Groth16 batch beats the loop path at N≥2. PLONK is the first non-Groth16 production verifier in the Solana ecosystem — byte-for-byte compatible with snarkjs 0.7.x, verified end-to-end against a real snarkjs fixture.
What's new
Verifiers
mosaic-plonk— full KZG-PLONK BN254 verifier. Six rounds of Fiat-Shamir via Keccak-256 transcript, linearization polynomial reconstruction (MSM over VK + proof commitments), KZG batched opening pairing. Six library modules:canonical,fr,field,transcript,challenges,linearization.mosaic-groth16::batch— Bowe-Gabizon randomized aggregation. N proofs sharing a VK → onealt_bn128_pairingsyscall with N+3 pairs. Independent SHA-256 challenges keep derivation free of on-chain Fr multiplication.VerifyProofBatchinstruction (0x02) exposes batch verification to on-chain callers and CPI.
Infrastructure
sol_poseidonsyscall wired viasolana-poseidon 2.3(#8) — unblocks Circom-compatible transcripts for Phase 3 KZG-based systems.- Real snarkjs 0.7.6 PLONK fixture +
SnarkjsPlonkCodec— decoder for snarkjs JSON → canonical wire bytes. cargo-vetattestation baseline (#59): 74 audited / 2 partial / 689 exempted.- Threat model expanded with 4 scope-boundary axes: under-constrained circuits, malleable proofs, validator determinism, replay safety (#63).
- Audit-readiness pass (#60): SECURITY.md, AUDIT.md, disclosure timeline, supply-chain README, pre-audit RFQ/outreach templates.
- bpf-bench now tracks three regression gates: Groth16 single, Groth16 batch N=5, PLONK single.
Stats
- 119 tests passing (was 36 at
v0.1.0-phase1). - SBF ELF 557 KB (was 112 KB, growth owed to arkworks Fr + PLONK linearization + batch path). Well under Solana's 1 MB program size limit.
- Clippy strict green (correctness + suspicious + todo + unimplemented hard-deny).
Bugs caught along the way
- PLONK u-challenge absorb order was missing — snarkjs only absorbs
Wxi + Wxiωfor u, notv. Pre-fix would have silently failed all valid PLONK proofs. - Host G1 decode rejected
(0, 0)as off-curve. Solana alt_bn128 treats all-zero bytes as identity; snarkjs emits this for zero-polynomial selector commitments (e.g. Qr in our mul-circuit). - SBF stack-frame overflow in PLONK linearization (>10 KB at worst). Resolved by splitting monolithic functions into many
#[inline(never)]sub-helpers.
Closed issues
#1 PLONK verifier · #5 batch_verify · #8 Poseidon · #33 devnet integration · #59 cargo-vet · #60 audit-readiness · #63 threat model
Compatibility
- Host: Rust 1.85.0 stable (unchanged)
- SBF:
cargo build-sbf --tools-version v1.52(unchanged) - Solana program SDK:
^2.1(unchanged, tested against 2.3.0) - Wire format: Phase-1 canonical byte layouts stable; PLONK adds its own 768 B proof / 744 B VK layout
OnChainErrordiscriminants: all Phase-1 values unchanged; no new variants
Phase 3 preview
Next freeze targets HyperPlonk-KZG, Halo2-KZG, gnark adapter, FRI-STARK, Nova/HyperNova folding. See the [Unreleased] section of CHANGELOG.md for the full list.
Full changelog
v0.1.0-phase1 — Phase 1 freeze
Phase 1 technical scope frozen. This pre-release is the reference point for audit-readiness conversations; subsequent commits land documentation, supply-chain attestation, and outreach artifacts without changing the runtime surface.
What's in
mosaic-core:ProofSystem,ProofCodec,TranscriptHash,SyscallBackend, two-layer error taxonomy (29OnChainErrorvariants pinned at stable discriminants), bump arena.mosaic-groth16: BN254 Groth16 verifier withLE_INPUTSconst generic for SIMD-0204 forward-compat. Host backend viaark-bn254, SBF backend viasolana-bn254syscalls.mosaic-serde: snarkjs JSON + arkworks canonical adapters producing byte-equal canonical output. gnark/halo2/plonky3/risc0 are stubs.mosaic-chunked: 48-hour session PDA protocol with rolling SHA-256 commitment. PDA seeds bound to(session_id, payer)to defend front-running griefing.mosaic-program: 112 KB SBF ELF dispatching single-txVerifyProof+ chunked-upload instructions.mosaic-sdk: instruction builder + host-sidepreflight.mosaic-bench:bpf-benchmeasures real on-chain CU (80,296 CU Groth16 mul-circuit, 44.6% of the 180K ADR-0005 cap).mosaic-fuzz: three libFuzzer harnesses.
Verification
cargo test --workspace --all-features: 36 passed, 0 failedcargo clippystrict: 0 errorscargo build-sbf --tools-version v1.52: 112 KBmosaic_program.so- Round-trip: snarkjs + arkworks + canonical paths byte-equal
- Differential (proptest): arkworks reference vs Mosaic host backend, 16 cases
Fixture corpus
Deterministic Groth16 mul-circuit (proves a * b == c with a=7, b=6) committed in three formats under tests/fixtures/groth16/mul-circuit/.
Documentation
5 ADRs + 1 design doc (chunked-upload implementation contract) + threat model + CU budget + lint policy + SECURITY/AUDIT/CONTRIBUTING.
Known limitations
- No external audit yet (issue #19)
- Fixtures are programmatic, not Circom-sourced (#24)
- Poseidon syscall path for Solana 2.x not wired (#8)
- Only Groth16 implemented; PLONK/STARK/Nova stubs (#1, #3, #4)
Compatibility
- Host: Rust 1.85.0 stable
- SBF:
cargo-build-sbf --tools-version v1.52mandatory - Solana program SDK:
^2.1(tested against 2.3.0)