This takes over #744 with @elichai's go-ahead: his three targets, ported to the current API, with his authorship kept on the first commit. As @sipa suggested there, it is one binary, fuzz, that picks the target from the FUZZ environment variable, as in Bitcoin Core. There is a target for the core API, ecdsa, and one per module: ecdh, recovery, extrakeys, schnorrsig, musig, ellswift and silentpayments. It is built with --enable-fuzz or -DSECP256K1_BUILD_FUZZ=ON, and with VERIFY, like tests, so internal checks run. The instrumentation comes from CFLAGS and the engine from FUZZ_LIBS (SECP256K1_FUZZ_LIBS in CMake), so an OSS-Fuzz build can pass its own. A CI job runs each target under ASan and UBSan, from an empty corpus, for 10000 runs or 20 seconds; a crash it finds is public in its log at once.
The targets check what the public headers document, and that forged or tampered signatures do not verify. Where tweak-add or silent payments output creation fails, the target checks that the failure has its documented cause. #744 asserted that tweak-add always succeeds, but it returns 0, as documented, when the two keys sum to 0 mod n; its consume_pubkey also overwrote the prefix byte. Both are fixed. ellswift and silentpayments take what an attacker controls from the input: the peer's 64 bytes and decoy outputs to scan. Internal targets, which @sipa suggested, can come on top of this; #1407 and @erickcestari's diffsecp have field, scalar and group ones. Background and a roadmap, with this PR as its first step: https://claude.ai/artifact/68binXRWqAZewaZABsEqBz
Assisted-by: my usual tools (LLM, Internet, computer). Mistakes are mine.