Add v2 roundtrip fuzzer - #1887
Open
caarloshenriq wants to merge 1 commit into
Open
caarloshenriq wants to merge 1 commit into
caarloshenriq wants to merge 1 commit into
Conversation
Co-authored-by: Carlos Santos <rickhenriquetab@gmail.com>
caarloshenriq
requested review from
DanGould,
benalleng and
spacebear21
as code owners
September 16, 2026 18:37
Collaborator
Coverage Report for CI Build 35135586389Coverage remained the same at 86.709%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a libFuzzer target covering the full v2 payjoin roundtrip: sender posts an encrypted message to the receiver's mailbox, the receiver walks the typestate chain and posts a proposal back, the sender decrypts and validates it. Unlike v1, every message the state machine sees is wrapped in two layers of crypto (HPKE messages A/B, OHTTP request/response), so random mutation alone cannot pass an AEAD tag and never reaches the protocol logic.
The harness was built together with @benalleng, who did the initial implementation; I reviewed it and polished a few details (test correctness, comments on two harness-side invariants).
Design
Both crypto layers are constructed harness-side so the fuzzer only ever mutates plaintext:
LazyLockstatics make this setup cost vanish across the millions of execs in one fuzz process.pj_uriand encrypts the fuzz-controlled plaintext (base64(psbt)\nquery) to it.As in
roundtrip_v1, a custom mutator keeps a known-good original PSBT (the BIP-78 test vector) intact and spends the mutation budget on the query, where the BIP-77 parameters live. 25% of mutations pass straight tofuzzer_mutate.Reproducibility
The random values (reply keypair, HPKE and OHTTP ephemerals) only key the transport layer. Downstream execution is a function of the plaintext alone, so a crash replays under fresh keys: the harness re-encrypts the same input and the state machine walks the same path. The
seed_psbt_completes_the_roundtriptest guards this property.What is covered
The full chain on both sides:
ReceiverBuilder::build,create_poll_request/process_response,assume_interactive_receiver,check_inputs_not_owned,check_no_inputs_seen_before,identify_receiver_outputs,commit_outputs,commit_inputs,apply_fee_range,finalize_proposal,create_post_request,PayjoinProposal::process_response, plus the sender-side HPKE encrypt/decrypt and the v1 sender context used to validate the returned proposal.Fuzzing results
From an empty corpus on x86_64 Linux, 6 forks, 61 seconds:
Coverage was still growing when the run ended. Throughput is lower than the other targets (~300-500 exec/s) since each execution runs two full HPKE handshakes and two OHTTP round trips end to end.
Addresses part of #1267.
Disclosure: co-authored by Claude
Pull Request Checklist
Please confirm the following before requesting review:
AI
in the body of this PR.