4.6 KiB
Fuzzing ZKAC
This repository ships a libFuzzer harness via cargo-fuzz. You can reuse zkac_fuzz from other fuzzers (e.g. AFL++, Honggfuzz) with a small custom binary.
Prerequisites
- Rust toolchain (
rustc,cargo). cargo-fuzz:cargo install cargo-fuzz- AddressSanitizer / default
cargo fuzz: requires nightly Rust (e.g.rustup toolchain install nightly). If you use a distro Rust withoutrustup, use sanitizernone(see below).
Quick start
From the repository root:
chmod +x scripts/fuzz-libfuzzer.sh
./scripts/fuzz-libfuzzer.sh
Fuzz a single target for 5 minutes:
FUZZ_TIME=300 ./scripts/fuzz-libfuzzer.sh handshake_respond
Stable Rust (no nightly)
Default cargo fuzz enables AddressSanitizer and needs nightly. To fuzz on stable, build and run with sanitizer none:
cargo fuzz build -s none handshake_respond
cargo fuzz run -s none handshake_respond -- -max_total_time=60
The helper script sets SANITIZER=none by default for stable-toolchain usage. It also prepends ~/.cargo/bin to PATH so cargo-fuzz is found after cargo install cargo-fuzz.
Did anything crash?
After a run:
- Exit code —
0means every target finished its time/run budget without libFuzzer treating the process as a crash. Non-zero means at least one target failed (crash, abort, or libFuzzer error). - Stdout — On failure, libFuzzer prints
ERROR: libFuzzer: deadly signal(or ASan messages if you use a sanitizer), the panic/backtrace, and a reproduce command. - Artifacts — Crashes are written under
fuzz/artifacts/<target_name>/, typicallycrash-<hash>(and sometimesleak-*with leak sanitizer). Re-run with:cargo fuzz run -s none <target> fuzz/artifacts/<target>/crash-<hash> - Minimize — Shrink a crashing input with
cargo fuzz tmin -s none <target> <crash-file>.
If the script stops early, scroll up to the last === cargo-fuzz: <name> === block: the lines after it show which target failed.
Nightly + AddressSanitizer
SANITIZER=address FUZZ_TIME=120 ./scripts/fuzz-libfuzzer.sh session_decrypt
Targets (fuzz/fuzz_targets/)
| Target | Exercises |
|---|---|
handshake_respond |
X25519 responder (handshake::respond) |
handshake_initiator_complete |
Initiator complete with arbitrary response bytes |
session_decrypt |
ChaCha20-Poly1305 decrypt + replay guard |
replay_sequence |
Sliding-window replay logic |
crypto_deserialize |
Ristretto public key, Schnorr signature, BBS+ issuer key parsing |
bbs_verify_presentation |
BBS+ proof parse + verify (heavy; keep corpora small) |
Shared logic lives in fuzz/src/lib.rs (zkac_fuzz).
Crate feature fuzz-expose
Fuzz builds enable zkac’s fuzz-expose feature so harnesses can call Session::new_fuzz. Do not enable this in production binaries.
corpora / artifacts
- Inputs: seed with
mkdir -p fuzz/corpus/<target>and pass-artifact_prefix=fuzz/artifacts/if you want crash dumps. - Gitignored:
fuzz/corpus/,fuzz/artifacts/, crash files (see.gitignore).
AFL++ (optional)
- Install AFL++ and
cargo install cargo-afl. - Add a binary in
fuzz/(or a separate crate) that calls intozkac_fuzz::dispatch_allor individualzkac_fuzz::*functions. - Build with the
cargo-aflwrapper (not plaincargo build):
cd fuzz
cargo afl build --release
# then point cargo-afl at your harness binary, e.g.:
# cargo afl fuzz -i in -o out target/release/your_afl_bin
(fuzz/Cargo.toml already enables zkac’s fuzz-expose for the dependency.)
The afl crate’s fuzz! macro must be linked with AFL’s runtime; use cargo afl build as documented in cargo-afl.
Honggfuzz (optional)
Install the honggfuzz binary (distro package or source). Point it at a binary that exercises zkac_fuzz (similar to AFL). Honggfuzz does not require the cargo-fuzz project layout; you can compile a small main that loops over inputs.
CI smoke
GitHub Actions (.github/workflows/fuzz-smoke.yml) builds all targets with sanitizer none, then runs scripts/fuzz-libfuzzer.sh with FUZZ_RUNS=2000 so every target gets a short fixed-iteration smoke (same idea as below).
Locally you can match that with:
FUZZ_RUNS=2000 ./scripts/fuzz-libfuzzer.sh
Or smoke a single target with a run budget instead of time:
cargo fuzz run -s none handshake_respond -- -runs=2000 -print_final_stats=1