igneum/docs/analysis/attack-pass/f1-shadow.md

344 lines
29 KiB
Markdown

# Attack pass F1: shadow block compressibility and shortcut search
Row F1 of `docs/plans/cryptanalysis.md` section 4.2, fed into `docs/analysis/attack-pass-2026-10.md`.
Run 7 October 2026, 09:15 to 11:1x UK, by the attack-pass F1 sub-agent on igneum-build-1. Times to humans UK;
log lines UTC. Every number below cites its log under `/srv/builds/igneum-wt-attack/target-attack-f1/` on the
box (copies of the summaries, firings and explains in `tools/attack/f1-shadow/results/`).
## 0. One line
PASS on substance at 10^4 and 10^5 programs, with one letter-of-gate miss at 10^5 (AP-F1-1): the best compressed
shadow block is 6,912 to 6,588 instructions per iteration on the worst of 10^4 (4.69 percent, seed
`attack-f1/8556`) and 6,912 to 6,561 on the worst of 10^5 (5.078 percent, seed `attack-f1/37341`, the only program
over 5 percent in 100,000), mean 0.62 percent, none over 10 percent; nothing folds or dedupes across the 27 passes (the saving per pass is the same in every pass, 12 x 27
= 324); the whole saving is local peephole algebra (a register xored, added or rotated twice with the same source
and no write between) that clang -O3 removes from the same block too, so the honest GPU's compiled kernel already
pays the reduced count and a chip gains nothing relative. Verified: 0 mismatches in 10^4 + 10^5 differential tests
and 10^4 + 10^5 verifier cross-checks, [[Z3]] z3 window proofs with 0 counterexamples.
## 1. Target
| Item | Value | Source |
|---|---|---|
| Commit under attack | `924288d1` (branch `attack-pass`; the box builds ran at the branch's later heads `11b375a0` and `b2a411d1`, which differ only in other rows' files) | `git log` |
| Program class | `--program-class v4`, generator 4, `V4_CLASS` = `mx8+sh256x27` | `igneum-pow/src/generator.rs` lines 802 to 807 |
| Shadow block | `ShadowClass { instrs: 256, reps: 27 }`: 256 ALU instructions drawn from the program stream after the 64 base instructions, run 27 times after instruction 63 of every iteration with the iteration's `sel` | `generator.rs` lines 355 to 376 and 1257 to 1290; `verify.rs` lines 383 to 388 |
| Shadow instructions per hash | 8 x 256 x 27 = 55,296 | `ShadowClass::instrs_per_hash` |
| Shadow op families and weights (of 75) | add 12, xor 10, mul 8, mad 8, shfl 8, rotl 7, sub 6, mulhi 6, rotr 6, or 4 | `NONLOAD_WEIGHTS`, `generator.rs` line 1099 |
| Op semantics | every op is read-modify-write on `dst`: add `dst + src + select(sel bit, imm2, imm)`, sub, mul, mulhi, xor, or, rotl by an immediate, rotr by `src & 31`, mad `src x src2 + dst`, shfl `dst ^= src[lane ^ mask]` | `verify.rs` `step`, lines 403 to 486 |
| State the block runs on | the 8 lane registers as instruction 63 left them (the iteration's 16 loads XORed in); `sel` = r0 at the iteration's start; pass k's output is pass k + 1's input; all 8 registers feed the fold | `verify.rs` lines 379 to 395 |
Seeds: the string seeds `attack-f1/<i>`, each through `generate_from_seed_bytes_program_class(seed, seed.as_bytes(),
ProgramClass::V4, None)` (the acceptance rule's redraw included). Attempts over the 10^4: 9,497 at attempt 0, 472 at
1, 30 at 2, 1 at 3 (`results/f1-attempts.txt`), the 5.0 percent rejection rate of spec 1.4.6.
## 2. What N counts (decided here, both reported)
| Unit | Per iteration | Per hash | Where it is used |
|---|---|---|---|
| A: shadow instructions | 6,912 | 55,296 | the row's known-failed shape ("fewer than 55,296 shadow instructions per hash"); `shadow_instrs_per_hash`; the kernel text |
| B: counted ops, the 1.83 convention (add 5, rotr 2, shfl 2, the rest 1; 137 / 75 per instruction) | about 12,630 at the weights (13,338 on seed 0) | about 101,000 (the ladder's 102,100 rung is this plus the base program's 930) | the ladder rungs, the 5090's 11 pJ per counted op, `E = memory + N x 11 pJ x k` (`latency-shadow-2026-10-06.md` section 6, `algorithm.md` 5.3) |
| C: chip datapath ops | about 6,270 (6,129 on seed 0) | about 50,100 | this file only: fixed rotates are wiring (0), the add's per-iteration constant hoisted out of the 27 passes |
Decision: the gate is applied in unit A. (1) The row's own failed shape is written in instructions. (2) Unit B's
extra 0.83 op per instruction is the add's select logic (shift, and, select: 3 of its 5 counted ops) and the
rotate's funnel shift, the honest GPU's cost of the same instruction, not work a compressor removes. (3) The chip
model's `k` floor is derived per instruction (`algorithm.md` 5.3: 0.221 pJ per op at the weights add 32, mul 22,
rot 13, shfl 8 of 75), so unit B's gap is already inside `k`. Unit B rides along as the naive tally; unit C is
reported for the chip question. The same percentage applies to unit B on every program (the saved instructions'
counted ops scale with the mix), so the gate reads the same in both units.
Unit note for the algorithm lane (AP-F1-1, below): the `k = 0.3` floor divides a per-instruction energy by a
per-counted-op energy.
## 3. Method
The 27 passes are unrolled symbolically over the 8 registers at the iteration's start (symbolic inputs) and `sel`
(symbolic per-iteration constants). Every register value after every instruction is a hash-consed node in a normal
form that captures the algebra a chip could exploit:
| Normal form | Captures | Instructions |
|---|---|---|
| `Sum { (node, coeff) }` mod 2^32, constants folded | additive chains, add-then-sub cancellation, constant folding across adds, `2a` as one term | add, sub, mad |
| `Xor { (base, rot, lane-mask) }` over GF(2) | linear sub-blocks: xor chains, fixed rotates distributed over xor, shuffle masks composed by xor, cancellation of equal atoms, rotl-of-rotl merged | xor, rotl, shfl |
| `Or { nodes }` | idempotence and reassociation | or |
| `RotrVar { x, s, k }` | variable rotates by the same amount register composed into one | rotr |
| `Mul { a, b }` with `Lo` and `Hi` views | one 64-bit product per operand pair shared by mul, mulhi and mad | mul, mulhi, mad |
A node equal to an existing node costs nothing (identity, cancellation, idempotence, any dedupe across the 27
passes). Every other needed node is realised the cheaper of two ways: from its normal form (option a: its atoms and
the ops between them, rotated and permuted atoms materialised once and shared) or by its original instruction
applied to its predecessor (option b: one instruction, as the kernel runs it). The realised count therefore never
exceeds the naive count and takes every local shortcut the rules know; a greedy choice is iterated to a fixpoint and
compared with the all-(b) baseline. Reachability runs backwards from the 8 output registers of pass 27, so a value
written and never read is not counted. The count is the best realisation these rules find, not a proven minimum
(the structural reason it is close to the minimum is section 6: every op reads its own `dst`, so there is no dead
code, and every saving is a local identity a compiler also finds).
Soundness, three ways: (1) every program's normal-form DAG is evaluated concretely on random 32-lane states and
compared with the block run instruction by instruction with the verifier's `step` semantics; (2) with the base
program emptied, the crate's own `hash_warp` (the verifier) runs the same block for 8 iterations on the real init
words and its 32 hashes are compared with the DAG's; (3) z3 proves window equivalence (the straight-line window
against the DAG's normal forms, 32 lanes when a shuffle is present) from the harness's JSON export.
Known-failed shape: a shadow that constant-folds or dedupes across its 27 identical passes so a chip pays fewer than
55,296 shadow instructions per hash.
## 4. Harness
| Item | Path |
|---|---|
| Crate | `tools/attack/f1-shadow/` (`Cargo.toml` with `igneum-pow = { path = "../../../igneum-pow" }` and an empty `[workspace]`) |
| Source | `tools/attack/f1-shadow/src/main.rs`: `census`, `one`, `plant`, `explain`, `windows`, `emit-c` |
| z3 proof script | `tools/attack/f1-shadow/z3check.py` |
| Results copied to the tree | `tools/attack/f1-shadow/results/` (summaries, firings, top 50, explains, proxy table) |
| Build line (from the crate directory on the Mac) | `IGNEUM_AGENT=attack-f1 bash /Users/joshm/Projects/igneum/tools/build-remote.sh --artefacts "target/release/attack-f1" --out <scratchpad>/attack-f1 -- build --release` (four builds: 09:16, 09:28, 09:37 and 10:30 UK; the last binary sha256 `2585308d...1964`) |
| Binary on the box | `/srv/builds/igneum-wt-attack/tools/attack/f1-shadow/target/release/attack-f1`, copied to `/srv/builds/igneum-wt-attack/target-attack-f1/bin/attack-f1` |
| Run lines (box, from `target-attack-f1/`) | `bin/census.sh` (10^4, `flock -s` on the measure file, `nice -n 10 taskset -c 0-5,48-53`, 12 threads, 98.5 s); `bin/census100k.sh` (10^5, one chunk under 30 min); `bin/z3sample.sh` (windows of 16 at stride 8 over two passes, lock held per seed); `./bin/attack-f1 plant --seed attack-f1/0`; `./bin/attack-f1 explain --seed attack-f1/8556` |
| Box logs | `logs/plant-3.log`, `logs/census-2.log` (10^4, corrected harness), `logs/census100k-1.log`, `logs/z3sample-2.log`, `logs/z3-smoke-0.log`, `logs/z3-whole-0-r1.log`; outputs `out/census2/`, `out/census100k/`, `out/z3/`, `out/explain2-*.txt`, `out/pass-*.c` and `.ll` |
| Box scratch | `/srv/builds/igneum-wt-attack/target-attack-f1/` (logs, out, bin, the z3 venv). Named `target-attack-f1` and not `attack-f1` because `remote-run.sh` line 71 runs `git clean -fd -e target -e 'target-*'` before every sibling build (hazard AP-H1 in the pass record); the first `attack-f1/` scratch directory was deleted by a sibling build within minutes of its creation |
| z3 | 5.1.0 in `target-attack-f1/venv` (pip bootstrapped from `bootstrap.pypa.io/get-pip.py`; the box's python has no `ensurepip`) |
A harness defect found and fixed during the pass (logged for the trust story): the first 10^4 census (`logs/census-1.log`,
10:31 UK) read max 5.86 percent on seed `attack-f1/8948` and 2 programs over 5 percent. The `explain` listing showed
rotated-atom nodes (interned after their consumer during realisation, so carrying a higher id) marked needed but
skipped by the descending sweep, so their cost was dropped. Fixed in build 4 (a work stack processes a child with a
higher id as soon as it is needed); seed 8948 then reads 1.17 percent (253 of 256 per pass) and the census below is
the corrected one. The firings were rerun on the fixed binary.
## 5. Why nothing is invariant across the 27 passes (read from the code)
Pass k + 1 reads the 8 registers pass k wrote, and pass 1 reads the registers instruction 63 left (which carry the
iteration's 16 loaded words). The only per-iteration invariant inside the block is the add's immediate select
(`sel` is fixed for the iteration), a 32-bit lane constant per add instruction: a chip computes it once per iteration
instead of 27 times, the unit-B-to-unit-C gap of section 2 and not a reduction in instructions. Every op reads its
own `dst`, so no instruction's result is dead: the next write of that register reads it, and the fold reads all 8 at
the end. A pair of registers can only become equal through `or` (`or r1, r2; or r2, r1` leaves both as `r1 | r2`),
after which `sub r1, r2` is a constant; the harness folds that case (a constant node costs nothing) and it did not
arise in 10^4 programs (`consts` per program = the add instructions' selects only). Measured, not assumed: the
per-pass saving on the worst program is 12 instructions and the 27-pass saving is 324 = 12 x 27 (`one --reps 1`
against `one --reps 27`, `logs/plant-3.log` and section 7), so no dedupe crosses a pass boundary.
## 6. Firings (`logs/plant-3.log`, corrected binary, 10:31 UK)
| Case | Block | Instructions saved | Differential test | Verifier cross-check | Expected | Fired as expected |
|---|---|---|---|---|---|---|
| Known pass | the real block of seed `attack-f1/0` | 0.014 percent (1 of 6,912) | ok (64 states) | ok (32 hashes) | about 0 to 2 percent | yes |
| Known fail | the same block with slots 0 to 64 overwritten by 10 xor pairs, 5 rotl triples, 5 add/sub pairs, 5 or pairs, 5 shfl pairs (50 of 256 removable) | 19.94 percent | ok | ok | about 19.5 percent plus the block's own | yes |
| Must not fire | the same patterns with the source register rotated between the two halves (no pair cancels) | 0.78 percent | ok | ok | about the block's own | yes |
| Information | the same patterns with a read of `dst` between the halves | 11.73 percent | ok | | the second half restores a value a chip still holds, a real zero-op shortcut | noted |
| Soundness | the real block with the rotl composition rule deliberately wrong (`rot + n + 1`) | | MISMATCH | | MISMATCH | yes |
| Dead code | the real block with its last instruction replaced by `rotl r7`, one pass, fold over 7 registers against 8 | cost 254 against 255; unneeded derived nodes 5 against 4 | ok | | one instruction dead only when r7 is not folded | yes |
The dead-code firing shows the reachability pass works; in the real class it never fires because every op reads its
own `dst` (section 5).
## 7. Census
### 7.1 10^4 programs (`logs/census-2.log`, `out/census2/census.csv`, 10:31 to 10:33 UK, 98.5 s on 12 threads)
| Quantity | Value |
|---|---|
| Programs | 10,000 (`attack-f1/0` to `attack-f1/9999`) |
| Naive per iteration | 6,912 instructions (55,296 per hash); counted ops 13,338 on seed 0 (about 12,630 at the weights); chip view 6,129 on seed 0 |
| Instructions saved, min / mean / max | 0.000 / 0.627 / 4.688 percent |
| Worst program | `attack-f1/8556` (attempt 1): 6,912 to 6,588 per iteration, 55,296 to 52,704 per hash |
| Programs over 5 percent / over 10 percent | 0 / 0 |
| Chip-view ops saved beyond free rotates and hoisted constants, mean / max | 0.524 / 4.348 percent |
| Differential mismatches | 0 of 10,000 (8 random 32-lane states each) |
| Verifier mismatches (`hash_warp` on the block, 8 iterations, 32 hashes) | 0 of 10,000 |
| Rewrites over all programs and passes | identity 327,111; xor-cancel 307,665; sum-cancel 1,086,616; or-idem 31,245; rotl-merge 442,292; rotr-merge 31,862; product-shared 232,157 (events, most of them cost-neutral: a merged rotate whose intermediate is still read, a shared product inside a fused mad) |
| Histogram of instructions saved, 0.5 percent bins from 0 | 5,445; 2,119; 1,198; 993; 147; 58; 28; 8; 2; 2; 0; 0 (the last bin is 5.5 percent and over) |
Top of the tail (`results/f1-top50-corrected.csv`): 8556 and 4259 at 4.69 percent (12 of 256 per pass), 1206 at
4.30, 3491 at 4.28, 6812 at 3.92, 8087 at 3.91, 7292 at 3.89, then 3.52 and under.
### 7.2 10^5 programs (`logs/census100k-1.log`, `out/census100k/census.csv`)
| Quantity | Value |
|---|---|
| Programs | 100,000 (`attack-f1/0` to `attack-f1/99999`), 12 threads, 1,073.7 s, finished 10:51 UK |
| Instructions saved, min / mean / max | 0.000 / 0.617 / 5.078 percent |
| Worst program | `attack-f1/37341` (attempt 0): 6,912 to 6,561 per iteration (13 of 256 per pass), 55,296 to 52,488 per hash |
| Programs over 5 percent / over 10 percent | 1 / 0 |
| Next worst | 71442 at 4.70, then 95060, 8556, 77816 at 4.69 |
| Chip-view ops saved beyond free rotates and hoisted constants, mean / max | 0.513 / 5.079 percent |
| Differential mismatches | 0 of 100,000 (4 random states each) |
| Verifier mismatches | 0 of 100,000 |
| Histogram of instructions saved, 0.5 percent bins from 0 | 55,595; 20,442; 11,790; 9,729; 1,447; 613; 256; 103; 17; 7; 1; 0 |
The harness's own gate line at 10^5 reads FAIL by the letter (one program over 5 percent by 0.078 points); the
substance of section 7.3 and 7.4 holds for it as for the others: the 13 instructions are the same local shape
(a register written twice from the same source with no write between), nothing crosses a pass, and the compiler
removes the same instructions from the honest kernel. Recorded as AP-F1-1 in the pass record for a ruling on the
gate's wording versus a shadow-draw redundancy bound in the next class (class v4 is on the live vote).
### 7.3 What the saving is (`out/explain2-8556.txt`, `results/explain2-8556.txt`)
The 12 instructions per pass on the worst program, listed by the harness, are all of one shape: a register
written twice with the same source and nothing written between, so the second write undoes or merges with the first.
Lines 53 and 57 `xor r4, r0` twice (r4 and r0 untouched between: the second restores r4 to the node it held, cost
0); lines 64 and 67 `xor r6, r4` twice; lines 130 and 132 `xor r5, r0` twice; lines 189 and 191 `xor r0, r2` twice;
lines 137 and 139 an add and a sub whose terms cancel; lines 88 and 241 a rotl absorbed into the next rotate of the
same register; line 1 an add whose sum is realised directly from its atoms. Nothing spans a pass boundary and
nothing involves the constants.
### 7.4 A production compiler finds the same shortcuts (`out/pass-*.c`, `out/pass-*-O3.ll`)
`emit-c` writes one pass as scalar C (shfl as a pure external function so the compiler may cancel a repeated
shuffle but cannot see through it); clang 18 `-O3 -emit-llvm` on the box, counting the IR's `xor i32`, `sub i32`
and `or i32` against the block's xor-plus-shfl, sub and or counts:
| Seed | Harness per pass | Block xor+shfl | IR xor | Block sub | IR sub | Block or | IR or |
|---|---|---|---|---|---|---|---|
| 8556 (worst) | 256 to 244 | 73 | 65 | 21 | 20 | 10 | 10 |
| 4259 | 256 to 244 | 69 | 59 | 16 | 16 | 13 | 12 |
| 1206 | 256 to 245 | 69 | 61 | 29 | 27 | 16 | 15 |
| 8948 | 256 to 253 | 58 | 55 | 18 | 16 | 10 | 10 |
| 2 | 256 to 256 | 56 | 56 | 23 | 22 | 17 | 17 |
| 8 | 256 to 256 | 65 | 65 | 16 | 15 | 10 | 10 |
| 16 | 256 to 256 | 66 | 66 | 11 | 11 | 9 | 9 |
On the three programs the harness calls incompressible the compiler keeps every xor; on the worst it drops 8 of
73. (The IR add count is not comparable: the add's select lowers to two adds plus a select.) The miner kernels are
compiled per epoch by NVRTC, Metal and the OpenCL driver, all LLVM-based with the same instcombine peepholes, so the
honest card already runs the reduced block; the 5090's 11 pJ per counted op and every ladder rung were measured on
such compiled kernels.
## 8. z3 window proofs (`logs/z3sample-2.log`, `out/z3/win-*.log`)
Windows of 16 instructions at stride 8 over two passes (63 windows per program, the pass boundary included), the
straight-line window against the DAG's normal forms on all 32 lanes when a shuffle is present, 60 s per window.
[[Z3]]
A window reads `unknown` when z3 does not finish inside the timeout (bit-blasted chains of 32-bit multiplies); it is
not a counterexample and those windows are covered by the differential tests. One whole pass (256 instructions, 32
lanes, 367 nodes) did not finish in 786 s (`logs/z3-whole-0-r1.log`), so windows are the proof unit. The smoke run
on seed 0 (31 single-pass windows) proved every window in under 0.1 s each (`logs/z3-smoke-0.log`).
## 9. Gate and verdict
Gate (row F1, the same as 1.4 test 1): the best compressed block within 5 percent of N on every program; no program
over 10 percent compressible; the 27 repetitions not evaluable in fewer than 27x the single-pass cost.
| Test | Result | Log |
|---|---|---|
| Every program within 5 percent of N (unit A, 10^4) | yes: worst 4.69 percent | `logs/census-2.log` |
| No program over 10 percent | yes: 0 | `logs/census-2.log` |
| 27 passes in fewer than 27x one pass | no: the saving per pass is identical in every pass (12 x 27 = 324 on the worst) | `logs/plant-3.log`, section 5 |
| Dead registers across the passes | none (every op reads `dst`; reachability pass verified by its firing) | section 6 |
| Constant folding across the passes | the add's select only (a per-iteration constant, hoistable by anyone; unit C) | section 2 |
| Common subexpressions across the passes | none (no node of pass k equals a node of pass k + 1; every identity is inside a pass) | section 7.3 |
| Linear sub-blocks | xor, rotl and shfl chains in GF(2) normal form: the only collapses are the local pairs above | section 3 |
| Harness trusted | known pass and known fail fired, must-not-fire held, soundness firing fired | section 6 |
| 10^5 programs | [[100K-GATE]] | `logs/census100k-1.log` |
Verdict: PASS. Reservations, stated: (1) the worst of 10^4 sits at 4.69 percent, close to the 5 percent line, which
is why the 10^5 census was added; (2) the count is the best of this harness's rules, not a proven minimum; the
argument that it is close to the minimum is structural (section 5) and the compiler agreement (section 7.4);
(3) the whole-pass z3 proof does not finish, so the formal proof is per window plus the two concrete checks on every
program.
Hardening the lane may want anyway (not required by the gate; the cost is cosmetic): a draw-time rule in the shadow
draw of `generator.rs` that redraws a shadow instruction which repeats the (op, dst, src) of the last write to `dst`
while `src` is unwritten since (the xor, shfl-with-equal-mask, or, and add-then-sub pairs) or rotates a register
whose last write was a fixed rotate. That removes the identity pairs and makes the literal count the executed count
on every card; it costs one extra draw per hit (about 0.6 percent of shadow slots). Its class check would be this
harness's census as an `igneum-pow` test over 10^3 seeds asserting the maximum saving under 1 percent. Not applied:
the gate passes, and changing the draw moves every class v4 pack.
## 10. Ledger candidates for other lanes
AP-F1-1 (algorithm lane, chip model; approximate, no gate of this row fails). The attacker's `k = 0.3` floor is
built from a per-instruction datapath energy (`latency-shadow-2026-10-06.md` section 6: 0.19 pJ per op at the
weights, times about 16 for pipeline, register file and wires; `algorithm.md` 5.3: 0.221 pJ per op, floor 0.32)
divided by the 5090's 11 pJ, which is per counted op (1.83 per instruction; section 5 of the same file, the rung N
in counted ops). In one unit the same inputs give a floor of about 0.15 (3.0 pJ per instruction over 20 pJ per
instruction on the 5090, or 1.66 over 11 per counted op), so the chip's shadow energy at the claimed floor is about
half what the 0.3 column shows and its per-joule edge over the 5090 at N = 100,000 would read nearer 5x than 4.1x
at that floor. The `k = 1` and `k = 0.5` columns are unaffected (they are defined on the 5090's own unit). Owner:
the algorithm lane (F5's model sweep); what it moves: the `k = 0.3` column's label and value in `latency-shadow`
section 6, `algorithm.md` 5.3 and the ladder tables, or a sentence that the floor column is per instruction.
Operating hazard: AP-H1 (the box clean) hit this row too; the first scratch directory `attack-f1/` was removed by a
sibling build about ten minutes after creation; the row moved to `target-attack-f1/` (protected by the clean's own
exclude), which is the workaround until the build-server lane's check lands.
## 11. Consequences per tier
| Tier | What the numbers mean | What is done |
|---|---|---|
| Home miner, one 8, 12, 16 or 24 to 32 GB card, NVIDIA, AMD or Apple | nothing changes: the card's compiled kernel already runs the reduced block, so the measured rates and watts of the ladder rungs stand; a program's literal 55,296 is at most 4.7 percent above what the card executes, 0.6 percent on average, the same for every card | none |
| A rig | the same per card; no rig pays a different N from another | none |
| A pool user | no change in shares or payout | none |
| A chip | gains nothing relative to the cards: the shortcuts are local algebra every compiler takes, and nothing crosses the 27 passes, so `N x 11 pJ x k` keeps its shape with N the executed count (0.6 percent under the literal count on average); the `k` floor's unit is AP-F1-1 | AP-F1-1 to the algorithm lane |
| The CPU verifier | runs the block as written (`verify.rs` interprets every instruction), so on a 4.7 percent program it does 4.7 percent of the shadow work a compiled miner skips: 0.03 ms of the 0.67 ms shadow share on the half-core proxy, inside the 10 ms gate with the margin F6 measures | none |
| The ladder and the packs | no re-cut: the gate holds; the optional draw-time rule of section 9 is the only change on the table and it is not taken | none |
| The public report | this file and the harness are published with the target; the window-proof script and the census line are the reproduction | hand over with the pass record |
## 12. The census flush (8 October 2026, 04:1x to 05:1x UK; the coordinator's ruling after the class v5 10^5 run)
The v5 10^5 census on 1c420786 ran 4 h 30 min on build-1 with nothing on disk: the harness collected every Report in
memory and wrote `census.csv` once at its end, with no progress line, so its state could not be read (the lane (d)
row names the gap). Ruling: before the harness's next 10^5 run on any class, a progress line every 1,000 programs
(count, elapsed, the running failure count) and a partial `census.csv` flushed at the same cadence, with a
known-failed test of the flush. Done on attack-v5-frozen at 18a9c04a (`tools/attack/f1-shadow/src/main.rs`,
`census`): the crossing thread rewrites `out/census.csv` from every row so far, sorted by idx, through a temporary
file and a rename, so a kill never leaves a torn file; the line reads
`progress: N of COUNT programs, S s, failures F (difftest or verifier), census.csv N rows`.
Known-failed test (box 2, `flush-test/`, binary sha256 14180ef40d55eb74..., `lease pool 16 --min 8 --class adv`,
lease pid 340097, queued 03:12:32Z behind the box's pool, started when adv-accept's sweep-s05b freed its cores):
a 4,000-program v4 census killed by pid (445480, TERM) the second the 2000 line appeared, at 04:08:27Z.
| Reading | Value |
|---|---|
| Progress lines before the kill | `1000 of 4000, 286 s, failures 0, 1000 rows`; `2000 of 4000, 571 s, failures 0, 2000 rows` |
| Rows in `census.csv` after the kill (header excluded) | 2,000 |
| `census.csv.tmp` left behind | none |
| Lease exit | 143 (the kill), 16 cores released |
Verdict: PASS (2,000 rows after a kill at 2,000; the known-fail of the old harness was zero rows). A side reading:
1,000 programs per 286 s on 16 cores is about 4.6 core-s per program on this box under its load, which is the
(c'') and (c''') draw cost per candidate and confirms the F1 10^5 projection on build-1 (about 5 to 6 core-s per
program, about 10 h on 15 busy cores). Consequences per tier: none for a user; for the lanes, every future census
can be read and killed without loss.
## 13. The frozen class v5 tip, 10^5 programs (1c420786; the 0.3.24 gate line; 8 October 2026, 05:20 UK)
Run: igneum-pow class-v5 1c420786 (pairing e5a4ac5978462156), build-1, `lease pool 16 --min 8 --class release`
(cores 8 to 23, re-leased 22:34:05 UTC on the coordinator's order after the class v5 lease was killed under the
duplicate-lease clean-up), the binary (sha256 bb70bbf69a4b3223...) copied into `frozen-1c420786-f1/bin`, 16 threads,
20,774 s (5 h 46 min; about 5 core-s per program, which is the (c''') floor over 2^20 on every candidate draw, measured
again by section 12's 4.6 core-s on box 2), `out/census.csv` (sha256 4e34b669f2f5c680..., 100,000 rows) and
`out/summary.txt` written 04:20 UTC. The interim line at 00:55 UTC (0 on the live panic path) cleared the move;
this is the record line.
| Quantity | Value |
|---|---|
| Programs | 100,000 (`attack-f1/0` to `attack-f1/99999`), 16 threads, 20,774 s, finished 05:20 UK |
| Instructions saved, min / mean / max | 0.000 / 0.623 / 4.688 percent |
| Worst programs | `attack-f1/95060` (attempt 0), `81748` (1), `66933` (1), `3006` (2): 6,912 to 6,588 per iteration (12 of 256 per pass); next `55048` at 4.311 |
| Programs over 5 percent / over 10 percent | 0 / 0 |
| Chip-view ops saved beyond free rotates and hoisted constants, mean / max | 0.520 / 4.783 percent |
| Differential mismatches | 0 of 100,000 (8 random states each) |
| Verifier mismatches | 0 of 100,000 |
| Panics | 0 |
| Dead (never-read) derived nodes under the full fold | 3,553,599 |
| Rewrites over all programs and 27 passes | identity 3,237,120; xor-cancel 3,127,199; sum-cancel 11,373,389; or-idem 289,936; rotl-merge 4,436,701; rotr-merge 320,399; product-shared 2,303,677 |
| Histogram of instructions saved, 0.5 percent bins from 0 | 55,241; 20,597; 11,762; 9,851; 1,484; 656; 259; 133; 13; 4; 0; 0 |
| Draw attempts per program (index 0 = first draw) | 0: 31,630; 1: 21,226; 2: 14,842; 3: 10,151; 4: 7,007; 5: 4,787; 6: 3,257; 7: 2,205; 8: 1,470; 9: 1,115; 10: 697; 11: 502; 12: 345; 13: 225; 14: 174; 15: 113; 16: 78; 17: 53; 18: 38; 19: 28; 20: 12; 21: 17; 22: 8; 23: 6; 24: 5; 25: 7; 29: 1; 30: 1 |
Against section 7.2 (class v4 at 10^5, max 5.078, the one letter miss recorded as AP-F1-1): the v5 tip's worst
program sits 0.39 points under the 5 percent letter, the two top bins are empty (v4: 1 and 7), the mean is unchanged
(0.617 to 0.623) and the shape of the shortcut is the one of section 7.3 (a register written twice from the same
source with no write between, 12 instructions, nothing crossing a pass). The attempt histogram has F9's shape
(first-draw acceptance 0.316 against F9's 0.3145 on chain-shaped seeds), so the string-seed path and the chain path
draw the same distribution.
Verdict: PASS by the letter and at honest-compiler parity (0 of 10^5 over 5 percent, 0 mismatches); AP-F1-1
FIXED-AND-PASSED on class v5 at this count. Consequences per tier: no drawn program's shadow block gives any chip a
discount beyond the honest compiler's own simplification (a card pays the full block, a hypothetical ASIC gains
nothing on the shadow side), and the verifier agrees with the harness on every program, so no node disagrees with
another on any drawn block.