Skip to content

test(lfm): choose the grinding leg's control by the host's verdict, not nonce + 1 - #954

Merged
MauroToscano merged 1 commit into
per-table-gpufrom
pt/grinding-fix
Sep 7, 2026
Merged

test(lfm): choose the grinding leg's control by the host's verdict, not nonce + 1#954
MauroToscano merged 1 commit into
per-table-gpufrom
pt/grinding-fix

Conversation

@MauroToscano

Copy link
Copy Markdown
Contributor

Summary

The "grinding defect" behind the failures of
lfm::algebraic_commit::tests::the_emitted_grinding_check_accepts_exactly_the_hosts_nonces
was the test's own negative control, not the emitter. The control used nonce + 1 as a
"nonce the host would reject". At grinding factor 8 one nonce in 256 is valid, so the
successor of a valid nonce is itself valid with probability 2^-8, and generate_nonce's
find_any re-samples the same few chunk-start winners run after run. Once a recurring
winner has a valid successor, the control fires deterministically for that scheduling
outcome, which looks exactly like a value-specific emitter defect.

Under Rpo with the test's seed at factor 8, the recurring winner 0x1400000000000009 has
the host-VALID successor 0x140000000000000A. The emitter proved it because
is_valid_nonce accepts it. emit_grinding_check and grinding.rs are unchanged: the
emitter follows the host's specification exactly for every nonce below p.

Changes (one file: prover/src/lfm/algebraic_commit.rs, tests only)

  • The gate test chooses its control as the FIRST nonce after the winner that
    is_valid_nonce rejects, asserts that rejection before asking the leg to agree, and
    prints the ground nonce and the control for every run.
  • New deterministic test the_emitted_grinding_check_agrees_with_the_host_on_the_incident_nonces:
    pins the Rpo verdicts literally (…09 valid, …0A valid, …0B rejected), constructs
    the arena directly (no grinding) for 0x1400000000000009 and +1 under Rpo, Rpx and
    Poseidon, walks forward sequentially until each tenant has shown both verdicts, and
    asserts the leg's verdict equals the host's on every nonce.
  • Shared fixtures hoisted (GRINDING_SEED_CELL, GRINDING_FACTOR, grinding_leg_program,
    grinding_members, leg_proves) so both tests exercise the same program.

Evidence

Mechanism verified by computation: a Python port of RPO from prover/src/lfm/rpo.rs,
checked against the 19-entry Miden hash_elements known-answer table and against all
three observed valid Rpo winners, evaluated under the test's seed at factor 8:

nonce first 8 digest bytes (BE) host verdict
0x1400000000000009 0x001503362b7f3c96 valid
0x140000000000000A 0x007fac32538532ee valid (the old "control")
0x140000000000000B above 2^56 rejected

All 13 probe runs (box B, 09-07) are predicted by the single rule "fail iff the Rpo
winner's successor is host-valid": winners 0x2000000000000025 (successor rejected,
PASS ×5), 66 (successor rejected, PASS ×6), 0x1400000000000009 (successor valid,
FAIL ×2 at the control arm, line 1115).

Direction of the defect, for traceability

The 2026-09-01 handoff described a REJECT-direction defect ("emit_grinding_check REJECTS
a nonce is_valid_nonce accepts"). That claim was an inference from the test failing
under load ("find_any changes which valid nonce is sampled, therefore the failure means
REJECT"); it assumed nonce + 1 is always host-rejected and no failing arm was read. The
09-07 probe read the arm: the control (ACCEPT). There was one cause, not two, and it was
the control. The handoff's "latent on main" is withdrawn on the same basis: origin/main
carries neither this test nor the pattern, and the two host-side wrapping_add(1) tamper
tests in crypto/stark are robust by construction (the nonce is absorbed, so any change
moves every later challenge).

Gate

Box A, this commit's content (be808f3d, rebased as efdda93), ×10 under a 64-way spin,
walls 68–76 s. Every run:

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 1162 filtered out
Rpo: nonce 0x1400000000000009 host=true machine=true
Rpo: nonce 0x140000000000000a host=true machine=true
Rpo: nonce 0x140000000000000b host=false machine=false

Runs 7, 9, 10 also showed Rpx: nonce 0x1400000000000009 host=false machine=false.
Ground/control pairs varied per run (e.g. Rpo 0x42/0x43, 0x9000000000000025/…26,
0xb000000000000006/…07; Rpx 0x4000000000000024/…25, 0xc0000000000000b3/…b4;
Poseidon 0x200000000000000e/…0f).

make lint on efdda93 (box A): G_LINT exit=0, all six passes, no error or Diff lines.
cargo fmt --all applied; cargo check -p lambda-vm-prover --tests clean, 0 warnings.

…ot nonce + 1

The 09-07 failures of the_emitted_grinding_check_accepts_exactly_the_hosts_nonces
fired on the CONTROL arm: under Rpo the recurring find_any winner
0x1400000000000009 has a host-VALID successor 0x140000000000000A (one nonce in
256 is valid at factor 8), so the test asked the emitter to reject a nonce
is_valid_nonce accepts. The emitter was right; the control was not a control.

The control is now the first host-rejected nonce after the winner, asserted as
such before the leg is asked to agree, and the ground nonce is printed. A new
deterministic test pins the incident pair and its first rejected successor for
Rpo, and walks Rpx and Poseidon to both verdicts, without grinding, asserting
the leg's verdict equals is_valid_nonce on every nonce. The emitter and
grinding.rs are unchanged.
@MauroToscano
MauroToscano merged commit 64e1610 into per-table-gpu Sep 7, 2026
8 checks passed
@MauroToscano
MauroToscano deleted the pt/grinding-fix branch September 7, 2026 18:44
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.

1 participant