Skip to content

Conversation

@ludamad
Copy link
Collaborator

@ludamad ludamad commented Jan 9, 2026

Adds a libfuzzer fuzzing harness for the bbapi API to detect memory corruption and safety issues. The harness targets a variety of inputs including proof files, ACIR bytecode for Ultrahonk, nested msgpack inputs for Chonk, multiple ACIR opcodes, and witness files. The fuzzer runs under ASAN (AddressSanitizer) to catch memory safety violations and undefined behavior. This provides comprehensive fuzz testing coverage of the bbapi attack surface.

ludamad and others added 30 commits December 15, 2025 23:13
Updates the noir submodule to noir-lang/noir#10878 which adds C++ codegen
support for msgpack-compact serialization format.

Also exports NOIR_SERIALIZATION_FORMAT=msgpack-compact in source_bootstrap.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy the foundry cache folder to a temporary location before running
forge scripts to avoid conflicts when multiple deployments run in
parallel. The cache folder is small metadata that links to the out
folder, so this is a fast operation. Also write broadcasts to the
temp cache folder.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…code

This script modifies autogenerated C++ header files to only support the
msgpack-compact format by:
- Removing bincode serialization methods
- Simplifying msgpack_pack to use array format instead of map format
- Simplifying msgpack_unpack to only support ARRAY format (compact)
- Removing unused Helpers functions for key-value map handling
- Updated Python filter to also transform enum variant msgpack_pack
  to avoid requiring msgpack::object adaptors
- Replaced deserialize_any_format with deserialize_msgpack_compact
- Added msgpack_compact_serialize helper to utils.hpp
- Updated test files to use msgpack serialization
- Removed bincode declarations and implementations from serde files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The noir serialization now defaults to msgpack-compact, so we no longer
need to set NOIR_SERIALIZATION_FORMAT in source_bootstrap.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Removed unused arguments for bulk testing.
Add comprehensive fuzzer harness targeting the bbapi API to detect memory
corruption issues via ASAN. The fuzzer exercises:

- Msgpack command deserialization and dispatch
- ACIR bytecode parsing (msgpack-compact format)
- Witness file parsing
- Circuit prove/verify operations with malformed inputs
- Chonk IVC command sequences
- Cryptographic primitive commands (Poseidon2, Blake2s, Pedersen, AES, ECC)
- Verification key parsing

Includes custom mutator for structure-aware fuzzing with:
- Format marker byte mutations
- Field element mutations
- Msgpack type marker injection
- Length field modifications

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive skill guide for writing libfuzzer harnesses covering:

- File naming conventions (*.fuzzer.cpp)
- Basic fuzzer structure with LLVMFuzzerTestOneInput
- Custom mutator patterns for structure-aware fuzzing
- Multi-mode dispatch, VM/instruction, and differential patterns
- Barretenberg-specific utilities (FastRandom, field mutations)
- Exception handling strategies for API vs circuit code
- CMakeLists.txt integration
- Msgpack format marker awareness
- Namespace ambiguity resolution
- Reference table of existing fuzzers

Based on analysis of 36 existing fuzzers in the codebase including
AVM, hash functions, field primitives, and proving system fuzzers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
ludamad and others added 6 commits January 9, 2026 19:26
…ties

- Move circuit_should_fail definition to fuzzer.cpp
- Add fuzzer_msgpack.hpp with msgpack mutation utilities
- Remove duplicate circuit_should_fail from stdlib fuzzer headers
- Simplify skill documents for fuzzer writing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove fuzzing-acir skill (too verbose)
- Move fuzzer_msgpack.hpp to bbapi/fuzzing/
- Add acir_bytecode.fuzzer.cpp - tests circuit_buf_to_acir_format
- Add witness_data.fuzzer.cpp - tests witness_buf_to_witness_vector
- Both use msgpack-aware custom mutators

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Also enhance fuzzer_msgpack.hpp with extreme length mutations to better
test memory allocation edge cases.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use msgpack::unpack_limit to set reasonable bounds on array/map/str/bin
sizes during deserialization. This prevents memory exhaustion attacks
and invalid memory access from malformed msgpack data.

Limits:
- array/map: 10M elements
- str/bin/ext: 100MB
- depth: 15 levels

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move msgpack unpack limits to msgpack_limits.hpp so they can be shared
between deserialization code and fuzzers. Update fuzzer to target
these specific limits (MAX_DEPTH, MAX_ARRAY, etc.) with 18% of mutations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Also add targeted limit mutations to fuzzer (18% of mutations).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@AztecBot AztecBot force-pushed the ad/msgpack-compact-only branch from 2c1ae99 to bddae56 Compare January 9, 2026 23:03
Base automatically changed from ad/msgpack-compact-only to next January 12, 2026 15:01
ludamad and others added 20 commits January 12, 2026 15:59
When deserializing enum variants from msgpack, the code allowed both MAP
and STR types. For non-unit variants, after extracting the tag from either
type, the code unconditionally accessed o.via.map.ptr[0].val to get the
associated data. When o.type was STR, the via union contained string data
(via.str), not map data (via.map), causing garbage pointer dereference.

This fix adds a type check before accessing via.map for non-unit variants,
throwing an error if STR encoding is used for variants that require data.

Also refactors Helpers to use msgpack's convert() API instead of manual
pointer iteration, and limits hash_index in fuzzer to avoid timeouts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add msgpack_limits.hpp with reasonable size limits for unpacking
- Apply limits to deserialize_msgpack_compact to prevent memory exhaustion
- Add type checking before o.via.map.ptr[0].val access in enum variant
  msgpack_unpack methods (71 locations) to prevent SEGV when STR type
  is incorrectly used for non-unit variants

These changes prevent SEGV crashes from malformed msgpack data where the
via union is accessed with incorrect type assumptions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Generates valid ACIR Circuit objects directly and tests the constraint
processing pipeline (circuit_serde_to_acir_format). Unlike the bytecode
fuzzer that tests msgpack deserialization, this fuzzer:

- Constructs syntactically valid ACIR structures
- Randomizes field values, witness indices, opcode parameters
- Creates sparse witness maps with gaps (1% chance 100-10000 gap)
- Tests all BlackBoxFuncCall variants
- Tests MemoryInit/MemoryOp opcodes
- Tests BrilligCall opcodes

No serialization overhead - objects go directly to processing logic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add MAX_WITNESS_INDEX limit (10M) to prevent OOM when filling sparse witness vectors
- Add safe_msgpack_unpack() utility function with security limits
- Add witness index validation in circuit_serde_to_acir_format() and witness_map_to_witness_vector()
- Update bbapi.fuzzer.cpp to use safe_msgpack_unpack()
- Update acir_gen.fuzzer.cpp to use consistent witness index limits

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add 4 new specialized fuzzers for comprehensive coverage of bbapi
deserialization attack surface:

- blackbox_opcodes.fuzzer.cpp: All 14 BlackBoxFuncCall ACIR opcodes
- crypto_commands.fuzzer.cpp: Cryptographic command inputs (Schnorr, ECDSA, etc.)
- witness_deser.fuzzer.cpp: Witness map deserialization edge cases
- verification.fuzzer.cpp: Proof/VK deserialization

These fuzzers use structure-aware generation with seed-based determinism
to test edge cases like empty inputs, max sizes, invalid bit widths,
sparse witness maps, and malformed proofs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add minimum size checks in VkAsFields, MegaVkAsFields, and
CircuitWriteSolidityVerifier execute() methods before calling
from_buffer() to deserialize verification keys.

Without this check, a malformed VK with too few bytes causes
from_buffer to read past the end of the buffer, resulting in a
SEGV (null pointer dereference).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The custom mutators were returning input unchanged, preventing
libfuzzer from effectively exploring code paths. Removing them
allows libfuzzer's default mutation strategy to work, resulting
in significantly better coverage (e.g., blackbox went from
cov:2 to cov:1962).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add minimum size check in _verify() to prevent read overflow when
deserializing verification keys. This fixes a SEGV crash when
CircuitVerify is called with a malformed VK buffer.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Malformed msgpack objects can have type MAP but a null pointer for
the map data. Add explicit check before iterating to prevent SEGV.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The null pointer check for MAP objects was unnecessary because:
1. msgpack's zone allocator always returns valid memory or throws
2. start_map() always allocates ptr when size > 0
3. The type check alone is sufficient protection

Testing confirmed crash files are handled without this check.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace hardcoded minimum VK size checks with exact size validation
computed from each Flavor's NUM_PRECOMPUTED_ENTITIES constant.

VK serialized size = 3 * sizeof(uint64_t) + NUM_PRECOMPUTED_ENTITIES * 64

This removes magic numbers and ensures the size check is accurate
for each flavor type (Ultra, Mega, UltraKeccak).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The msgpack zone allocator never returns null - it throws std::bad_alloc
on failure. Type checking alone is sufficient protection.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add two new fuzzers to target fresh areas:
- ecc_primitives.fuzzer: Tests fr/fq field elements, g1/g2/grumpkin points,
  and uint256_t/uint512_t deserialization via from_buffer
- chonk_proof.fuzzer: Tests ChonkProof msgpack deserialization

These complement the existing fuzzers to improve coverage of cryptographic
primitive parsing and proof structure handling.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fuzzer found that several ECC functions were marked noexcept but could
throw exceptions when inverting zero or converting points at infinity.

Functions fixed:
- field::invert() - throws when inverting zero
- element::operator affine_element() - throws via invert when z=0
- affine_element::operator+ and operator* - call throwing functions

Also adds two new fuzzers:
- crypto_signatures: tests ECDSA and Schnorr signature verification
- hash_operations: tests Blake2s, Blake3s, Keccak256, SHA256, Poseidon2

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add two new fuzzers to improve coverage of cryptographic primitives:

- ecc_operations.fuzzer.cpp: Tests actual ECC operations including
  point addition, scalar multiplication, MSM, compression/decompression,
  batch normalization, and Grumpkin curve operations

- pedersen_ops.fuzzer.cpp: Tests Pedersen hash and commitment operations
  with various input sizes and generator indices

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a static constexpr serialized_size() method to NativeVerificationKey_
that calculates the expected byte size of a serialized VK. This replaces
duplicated size calculations across bbapi_ultra_honk.cpp with a single
source of truth.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add bbapi_msgpack.fuzzer.cpp: Fast fuzzer for bbapi command
  msgpack deserialization (~27k exec/s)
- Add field_arithmetic.fuzzer.cpp: Fast fuzzer for field element
  operations (~66k exec/s)
- Speed up witness_deser.fuzzer.cpp by reducing MAX_WITNESS_INDEX
  from 100k to 1k and entry count from 100 to 20

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- trace_to_polynomials: Use .at() for bounds checking on real_variable_index
  to prevent OOB access with malformed ACIR witness indices
- bbapi_chonk: Validate VK buffer size before deserialization to prevent
  buffer overread attacks
- bbapi_ultra_honk: Reject oversized proofs by checking all proof data
  was consumed during verification
- transcript: Add verify_proof_fully_consumed() helper method

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ludamad ludamad marked this pull request as ready for review January 16, 2026 23:12
@ludamad ludamad force-pushed the ad/test/bbapi-fuzzer branch from 582b91a to 7af41a9 Compare January 16, 2026 23:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants