Skip to content

Fix flaky signed-context fuzz tests: constrain bounded keys, not raw inputs#480

Open
thedavidmeister wants to merge 1 commit into
mainfrom
2026-06-15-flow-signedctx-fuzz
Open

Fix flaky signed-context fuzz tests: constrain bounded keys, not raw inputs#480
thedavidmeister wants to merge 1 commit into
mainfrom
2026-06-15-flow-signedctx-fuzz

Conversation

@thedavidmeister

@thedavidmeister thedavidmeister commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

What

testFlowBasicValidateMultipleSignedContexts (and its single-context sibling testFlowBasicValidateSignedContexts) in test/src/concrete/Flow.signedContext.t.sol are a latent/flaky red on rainix-sol-test. They pass at the configured forge-config: default.fuzz.runs = 100 under the pinned seed = "0xdeadbeef", but fail deterministically once enough fuzz runs reach a colliding input. CI fuzzes with a random seed, so this surfaces intermittently.

Root cause (broken test, not a code bug)

Both tests guarded the raw fuzz inputs:

vm.assume(fuzzedKeyBob != fuzzedKeyAlice);
uint256 aliceKey = boundPrivateKey(fuzzedKeyAlice);
uint256 bobKey   = boundPrivateKey(fuzzedKeyBob);

forge-std's boundPrivateKey is _bound(x, 1, SECP256K1_ORDER - 1), which is not injective over the full uint256 domain — e.g. boundPrivateKey(0) == boundPrivateKey(1) == 1. So distinct raw inputs (passing vm.assume) can fold onto the same private key. When they do, the "bad" second signed context vm.signContext(aliceKey, bobKey, ...) is actually signed by the same key it declares as signer, so LibContext.build's SignatureChecker.isValidSignatureNow correctly validates it — and the expected InvalidSignature revert never fires ("next call did not revert as expected").

The validation code is correct; the test's distinctness precondition was asserted pre-bound but consumed post-bound. Diagnosis and repro are in #479. The captured counterexample under 0xdeadbeef is fuzzedKeyAlice = 0, fuzzedKeyBob = 1.

Fix

Move the vm.assume onto the bounded keys (aliceKey != bobKey) in both tests, so the degenerate collision is discarded rather than asserted on, while the bad-signature revert path is still fully exercised across the input domain. The assertion itself is unchanged (not weakened).

Verification

  • Before fix, bumping the per-test runs and running forge test --match-test testFlowBasicValidateMultipleSignedContexts --fuzz-seed 0xdeadbeef: FAIL at run 19, counterexample [..., 0, 1].
  • After fix, same test at runs = 100000 under seed 0xdeadbeef: both tests pass (0 failed).
  • Both tests pass across seeds 0xdeadbeef, 0x1, 0x2, 0xc0ffee, 0xbadc0de, 0x12345 at the configured 100 runs.
  • forge fmt --check clean. (rainix-sol-static slither red is pre-existing and unrelated — tracked in fix: remove redundant statement flagged by slither (unblocks rainix-sol-static) #476.)

Closes #479

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
    • Improved robustness of signed-context fuzz tests with refined constraint handling for cryptographic key validation.
  • Documentation
    • Added clarifying comments explaining key validation behavior and test assumptions.

boundPrivateKey is not injective over the full uint256 domain, so two
distinct fuzz inputs (e.g. 0 and 1) can fold onto the same private key.
The bad-signature assertions in testFlowBasicValidateMultipleSignedContexts
and testFlowBasicValidateSignedContexts only hold when alice and bob have
distinct keys, but the tests guarded the raw inputs via
vm.assume(fuzzedKeyBob != fuzzedKeyAlice). Under the colliding case the
'bad' signature is signed by the same key it claims as signer, so it
validates and the expected InvalidSignature revert never fires
(deterministic under seed 0xdeadbeef at higher run counts).

Move the assume onto the bounded keys (aliceKey != bobKey) so the revert
path is exercised across the input domain without the degenerate
collision masquerading as a failure.

Closes #479

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@thedavidmeister thedavidmeister self-assigned this Jun 15, 2026
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0fe9ef80-7bc8-413f-a600-359a07fcd096

📥 Commits

Reviewing files that changed from the base of the PR and between 772e568 and 83f35ab.

📒 Files selected for processing (1)
  • test/src/concrete/Flow.signedContext.t.sol

Walkthrough

Both signed-context fuzz tests in Flow.signedContext.t.sol are updated to move the vm.assume distinct-key guard from the raw fuzz inputs to the post-boundPrivateKey values (aliceKey != bobKey), with inline comments explaining that boundPrivateKey is not injective over the full uint256 domain.

Changes

Signed-context fuzz test key collision fix

Layer / File(s) Summary
Bound-key inequality constraint in both fuzz tests
test/src/concrete/Flow.signedContext.t.sol
In testFlowBasicValidateMultipleSignedContexts (lines 25–33) and testFlowBasicValidateSignedContexts (lines 62–70), the vm.assume precondition is changed from comparing raw fuzz inputs to comparing bounded keys (aliceKey != bobKey), with added comments explaining the non-injectivity of boundPrivateKey.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Possibly related issues

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: fixing flaky fuzz tests by constraining bounded keys instead of raw inputs.
Linked Issues check ✅ Passed The PR fully addresses issue #479 by moving the vm.assume constraint from raw inputs to bounded keys, fixing both affected tests as required.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the flaky fuzz tests documented in issue #479; no unrelated modifications are present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2026-06-15-flow-signedctx-fuzz

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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.

Flaky fuzz: testFlowBasicValidateMultipleSignedContexts can pass two colliding bound private keys (over-constrained vm.assume)

1 participant