Skip to content

fuzz

fuzz #37

Workflow file for this run

name: fuzz
on:
pull_request:
paths:
- "crates/mosaic-core/**"
- "crates/mosaic-groth16/**"
- "crates/mosaic-plonk/**"
- "crates/mosaic-hyperplonk/**"
- "crates/mosaic-halo2/**"
- "crates/mosaic-nova/**"
- "crates/mosaic-stark/**"
- "crates/mosaic-zk-primitives/**"
- "crates/mosaic-fuzz/**"
- ".github/workflows/fuzz.yml"
schedule:
- cron: "23 4 * * *" # nightly 04:23 UTC
workflow_dispatch:
jobs:
# ─────────────────────────────────────────────────────────────────
# PR mode — runs a representative subset for ~5 minutes each. Keeps
# PR CI under ~90 minutes wall-clock while still exercising every
# system at least once and every Phase-3 audit gate + compression
# surface directly. The full 33-target sweep runs nightly.
#
# PR matrix at session 114 (22 harnesses × 5 min ≈ 110 min wall):
# - 3 original Groth16 outer-surface harnesses
# - 5 combined-slot fuzzers (one per Phase-2/Phase-3 system)
# - 4 audit-gate algebraic-surface harnesses (session 95)
# - 6 compressed wire-format harnesses for Phase-2 (session 111)
# - 4 compressed wire-format harnesses for Phase-3 (session 114)
# ─────────────────────────────────────────────────────────────────
fuzz-pr:
name: PR fuzz (5 min per harness, representative subset)
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
# Phase-1 Groth16 (3 originals)
- fuzz_groth16_proof_bytes
- fuzz_vk_bytes
- fuzz_public_inputs
# Phase-2 + Phase-3 representative subset (1 per system,
# combined-slot variant which exercises every parser path)
- fuzz_plonk_combined
- fuzz_hyperplonk_combined
- fuzz_halo2_combined
- fuzz_nova_combined
- fuzz_stark_combined
# Session 95 — audit-gate algebraic-surface harnesses.
# All four run in PR mode because they exercise the
# ADR-0006 soundness boundaries directly; a regression in
# an audit gate is a soundness regression and should fail
# PR CI, not wait for nightly.
- fuzz_nova_consistency_gate
- fuzz_halo2_lookup_gate
- fuzz_stark_fri_query_gate
- fuzz_hyperplonk_claim_reduction_gate
# Session 111 — compressed wire format harnesses
# (sessions 106-110 added Halo2/Groth16/PLONK compressed
# proof + VK paths). Fuzzing the decompression entry
# points catches panics on hostile compressed bytes.
- fuzz_groth16_compressed_proof
- fuzz_groth16_compressed_vk
- fuzz_plonk_compressed_proof
- fuzz_plonk_compressed_vk
- fuzz_halo2_compressed_proof
- fuzz_halo2_compressed_vk
# Session 114 — Phase-3 compressed wire format harnesses.
# Mirrors session 111's Phase-2 sweep for HyperPlonk + Nova.
# STARK has no BN254 curve points so alt_bn128 compression
# is not applicable.
- fuzz_hyperplonk_compressed_proof
- fuzz_hyperplonk_compressed_vk
- fuzz_nova_compressed_proof
- fuzz_nova_compressed_vk
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- uses: Swatinem/rust-cache@v2
- run: cargo install cargo-fuzz --locked
- run: cargo +nightly fuzz run ${{ matrix.target }} -- -max_total_time=300
working-directory: crates/mosaic-fuzz
# ─────────────────────────────────────────────────────────────────
# Nightly mode — full 33-target sweep, 1 hour per harness. Total
# wall-clock ≈ 33 hours across the matrix (parallel runners cap
# at GitHub's free-tier limit of 20 concurrent jobs, so the matrix
# finishes in ~2 batches).
# ─────────────────────────────────────────────────────────────────
fuzz-nightly:
name: Nightly fuzz (60 min per harness, full inventory)
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
# Phase-1 Groth16 (3 originals)
- fuzz_groth16_proof_bytes
- fuzz_vk_bytes
- fuzz_public_inputs
# Per-system proof-bytes (5)
- fuzz_plonk_proof_bytes
- fuzz_hyperplonk_proof_bytes
- fuzz_halo2_proof_bytes
- fuzz_nova_proof_bytes
- fuzz_stark_proof_bytes
# Per-system vk-bytes (5)
- fuzz_plonk_vk_bytes
- fuzz_hyperplonk_vk_bytes
- fuzz_halo2_vk_bytes
- fuzz_nova_vk_bytes
- fuzz_stark_vk_bytes
# Per-system public-inputs (5)
- fuzz_plonk_public_inputs
- fuzz_hyperplonk_public_inputs
- fuzz_halo2_public_inputs
- fuzz_nova_public_inputs
- fuzz_stark_public_inputs
# Combined-slot fuzzers (5)
- fuzz_plonk_combined
- fuzz_hyperplonk_combined
- fuzz_halo2_combined
- fuzz_nova_combined
- fuzz_stark_combined
# Session 95 — audit-gate algebraic-surface harnesses (4).
# See ADR-0006 for the audit-gate extraction pattern.
- fuzz_nova_consistency_gate
- fuzz_halo2_lookup_gate
- fuzz_stark_fri_query_gate
- fuzz_hyperplonk_claim_reduction_gate
# Session 111 — compressed wire format harnesses (6).
- fuzz_groth16_compressed_proof
- fuzz_groth16_compressed_vk
- fuzz_plonk_compressed_proof
- fuzz_plonk_compressed_vk
- fuzz_halo2_compressed_proof
- fuzz_halo2_compressed_vk
# Session 114 — Phase-3 compressed wire format harnesses (4).
- fuzz_hyperplonk_compressed_proof
- fuzz_hyperplonk_compressed_vk
- fuzz_nova_compressed_proof
- fuzz_nova_compressed_vk
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- uses: Swatinem/rust-cache@v2
- run: cargo install cargo-fuzz --locked
- run: cargo +nightly fuzz run ${{ matrix.target }} -- -max_total_time=3600
working-directory: crates/mosaic-fuzz
- name: Upload corpus on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: fuzz-corpus-${{ matrix.target }}
path: crates/mosaic-fuzz/fuzz/corpus/${{ matrix.target }}/