# Report: the chained cache, chain break or skip (lane adv-cache-3) Internal adversarial pass, not an independent review. Lane `adv-cache-3`, the chain-break-or-skip class of the chained cache: line `(s, j)` in fewer than `j + 1` blocks without an earlier line; relations through the XOR chaining and the feed-forward; partial knowledge; the pebbling curve of the 64-line chain. Plan: `docs/plans/cryptanalysis/plan-chained-cache-3.md`. Every sentence here that could be quoted publicly carries the label: internal adversarial pass, not an independent review. Times are UK time (BST); the logs carry UTC. ## Header | Item | Value | |---|---| | Target commit | `017e70376489251e18564c0abce7e466e606c8b3` (class v4 sub-version 3, object byte 7); `igneum-pow` at `build/master` 04c4d9bc is byte-identical (`git diff --quiet 017e7037 HEAD -- igneum-pow` printed IDENTICAL at 19:42), and the harness depends on it by path | | Harness | `tools/attack/adv-cache-3/` (crate `attack-adv-cache-3`, binary `adv-cache-3`, commands `check`, `skip`, `relations`, `image`, `pebble`, `cross`), branch `adv-cache-3` on the build mirror | | Binary sha256 | `37a7a661c548a67827e29c4134bb91751ef2083920b386d3ebc9b599add3ca8a` on both boxes (built from commit 4e363b91's tree, `cargo build --release`, rustc 1.99.0). The first build `067ad69c...` had 66 rank samples per `j` instead of 4,096 and was replaced; its one run (`skip-d20730`, 20:09) agrees with the rerun on every other number | | Self-test on every start | the restated `B` equals the library's `chacha_block` on 4,096 random inputs; `core_inv` inverts `core` at w = 2, 4, 8, 16, 32; the restated chain equals `Cache::fill_segment` on segments 0, 21,859 and 65,535 of day 20730 | | Vectors passed | day 20730 cache FNV-1a 64 `0x448274a57f508cbc` (the kit's `vectors.json`) and day 20733 `0x7334fa46e5d972eb` (the Devnet 3 pack): MATCH (`check.log`) | | Boxes and scheduling | build box 1 for the skip, relations, pebble and cross runs, build box 2 for the exhaustive image census; every run through `/srv/builds/_bin/lease pool` (main's rule of 20:1x, no sweep by hand), nice 10 on cores 8 to 95; the boxes read load 400 to 600 on 96 threads all evening, so wall times are not timings | | Logs | `/srv/builds/_adv-cache-3/logs/.log` on each box (outside the worktree mirror); copies under `docs/analysis/cryptanalysis/logs/adv-cache-3/` on this branch, `ledger.txt` the start and end of every run | | THE QUEUE | files 90, 91, 92 (the coordinator's definitions) claimed at 19:49 with owner files; implemented and run as files 93 (skip batch, 14 runs), 94 (relations, 4 runs), 96 (the 1,024-line chain, 4 runs) on build box 1 and 95 (the image census) on build box 2; 97 (the image census again at 48 cores) queued behind the class v5 waiters | | Box-hours | 0.26 slot-hours in all (section 9); no pod-hours (no GPU row in this lane) | ## Status board | # | Question | Method | Known-failed shape (fired?) | Gate | Result | Status | |---|---|---|---|---|---|---| | Q1 (brief a, file 90) | Line `(s, j)` in fewer than `j + 1` blocks without an earlier line of its segment | `skip`: 7 earlier-line-free templates at 1 or 2 blocks against every line; the GF(2) rank of the `(x_j, line_j, 1)` sample matrix; the 512 x 512 bit-dependence table and the 16 x 16 word table; the inversion attempt; the reduced-round ladder | `no-xor` fired (64,512 of 65,536 lines at 1 block; dependence table all zero); `no-feedforward` fired (64,512 lines recovered up the chain; 64,512 of 64,512 inversions); `--rounds 0` fired (rank 17 of 1,025) | 0 lines under `j + 1`; rank 1,025; no zero cell; 0 inversions | 64-line chain, 1,024 segments, days 20730 and 20733: 0 of 131,072 lines by any template (16.9 M compares); 1,024-line chain, 64 segments, both days: 0 of 131,072 (268.6 M compares); rank 1,025 of 1,025 at `j` = 1, 2, 32, 63 and 1,023; flip table worst z +4.47 / -4.88 of 262,144 cells, 0 zero cells; every output word changes with every input word; 0 of 130,000 inversions | BOUND, PASS | | Q1 (4) | Exhaustive image census at w = 2: every one of 2^32 states per step, depth 64 | `image` | `no-feedforward` fired (a permutation: the image stays 2^32 at every one of 6 depths) | the chain loses entropy no faster than a random function | all 64 depths: image 0.632142, 0.468559, 0.312098, 0.189061, 0.106546, 0.057174, 0.029762 of 2^32 at depths 1, 2, 4, 8, 16, 32, 64 against the random-function recursion 0.632121, 0.468536, 0.312080, 0.189050, 0.106537, 0.057173, 0.029762: within 2.3 x 10^-5 at every depth, exactly equal at depth 64 to six places | BOUND, PASS | | Q2 (brief b, c, file 91) | Relations through `line_j = C(x_j) + x_j`; partial knowledge | `relations`: per-bit bias of 4 relations and the 512 x 512 linear-correlation table over 4 day keys x 2^20 lines; `skip`'s word table and inversion for the partial-knowledge half | `--rounds 1` and `--rounds 2` did NOT fire on the bias and correlation statistics (worst 4.47 and 4.65 sigma at 2^16 lines); the relation class's plants that do fire are in `skip`: `--rounds 1` leaves 21 exact affine relations (rank 1,004) and 6,985 zero cells in the flip table, `no-feedforward` inverts every line | every bias and cell within 6 sigma at 2^22 samples; 0 words from a proper subset; 0 inversions | 4,128,768 lines: worst bias 3.58 sigma of 2,048 bits; worst correlation cell 4.83 sigma of 262,144 (0 cells over 5, 0.15 expected); 0 of 16 output words from a proper subset of input words; 0 inversions | BOUND, PASS; the plant caveat in section 2 | | Q3 (brief d, file 92) | The pebbling curve of the 64-line chain under storage `f`; the amortising adversary | `pebble`: exact DP optimum over placements (checked against exhaustive search at 10, 12, 14, 16 lines, 12 of 12 agree), the two stride placements, ops per item and SRAM; Monte Carlo of `m` requests per segment, fixed and Poisson | `--skip-edge 8` fired (optimum 5.19 blocks at `f = 1/64` against 16.0) | monotone; never under the honest hold-every-k-th curve; 9,360 at `f = 1` | Monotone, 9,360 at `f = 1`. The DP optimum sits UNDER the hold-every-k-th curve at small `f`: 16.0 against 31.5 blocks per read at `f = 1/64`, 10.5 against 15.5 at 2/64, 6.09 against 7.5 at 4/64, 3.17 against 3.5 at 8/64, 1.45 against 1.5 at 16/64, equal from 32/64. Not an attack: a correction of the honest baseline (section 3) | FINDING (bookkeeping, not a break): the honest curve of the gate is mis-specified at small `f`; the chip's partial-cache price at `f = 1/64` is 9.3x the item's ops, not 17.4x | | Q4 (brief e) | Cross-segment and cross-day relations; the known-constant words | `cross`: 512 x 512 correlation tables at `j` = 0, 1, 63 across one-bit segment pairs and across days 20730 and 20731 | `--plant no-xor --rounds 1` fired (3,385 to 3,585 cells over 6 sigma per table, worst 64) | every cell within 6 sigma | 4,096 pairs per table: worst 4.50, 4.75, 5.00 (segments at `j` = 0, 1, 63), 4.56 (days); 0 cells over 6 sigma of 1,048,576 | BOUND, PASS | ## 1. Q1: the skip search Commands (box 1, file 93 and file 96, binary `37a7a661...`): `adv-cache-3 skip --day 20730 --segments 1024 --threads 88` and `--day 20733`; `--segments 64 --lines 1024` on both days; plants `--plant no-xor`, `--plant no-feedforward` at 64 and 1,024 lines; the ladder `--rounds 0, 1, 2` at 256 segments; the model `--w 4 --rounds 2 --segments 65536 --lines 16` with both plants. Seeds: the chain day keys `seed_words_from_bytes("igneum-day/" || le64(d))`; segments `s = (p * 0x9E37) AND 0xffff` for `p` in 0..segments, or every segment when `segments >= 65,536`. Logs `skip-*.log`. What was searched, from the code (`memhard.rs` `chacha_block`, `fill_segment_tagged`): | Test | What it would catch | Day 20730 | Day 20733 | |---|---|---|---| | Templates: `B(c_j)`, `B(c_j XOR c_i)`, `B(c_j) XOR B(c_i)`, `B(c_j) XOR c_i`, `B(B(c_j))`, `B(c_j) + c_i` for `i < j`, and `Cinv(line_j) XOR c_j = line_{j-1}` (up the chain from a stored later line) | a line computable from the public constants alone, or a line computable from its successor | 0 matches on 65,536 lines at 64 lines and 65,536 at 1,024 lines (`B(c_0) = line_0` is the chain's own definition at 1 = j + 1 blocks and is counted as not under); chance expectation under 10^-146 | the same, 0 | | GF(2) rank of the 4,096 x 1,025 matrix `(x_j bits, line_j bits, 1)` and of `(line_{j-1}, line_j, 1)` | any affine relation between a line and its input, which is a skip (a linear `B` chains to a linear closed form) | 1,025 of 1,025 at `j` = 1, 2, 32, 63 and pooled; at 1,024 lines 1,025 at `j` = 1 and 1,023 | the same | | Flip table: each of the 512 bits of `line_{j-1}` flipped, the flip rate of each of the 512 bits of `line_j`, over 4,096 lines | a bit of a line that does not reach a bit of the next (a skip through a sub-block) | worst z +4.44 / -4.53 (64-line), +4.34 / -4.88 (1,024-line); 0 zero cells | +4.47 / -4.47; +4.41 / -4.47; 0 zero cells | | Word table: each input word randomised, which output words change | an output word computable from fewer than 16 input words (the partial-knowledge gain) | 4,096 of 4,096 for every pair; 0 of 16 words from a proper subset | the same | | Inversion: `Cinv(line_j) = x_j`; the fixed-point iteration `x <- Cinv(y - x)` from 0, 64 steps | a cheap inverse of `B = C + x`, which walks up the chain from any stored line | 0 of 64,512 (64-line) and 0 of 65,472 (1,024-line) | 0 and 0 | The reduced-round ladder (256 segments, day 20730), the margin of the rank and flip tests: | Double rounds of `C` | Rank at `j = 1` of 1,025 | Zero cells of 262,144 | Flip table worst z | Reading | |---|---|---|---|---| | 0 (`B(x) = 2x`) | 17 | 261,648 | 64 | fully affine; the plant for the rank test | | 1 (2 ChaCha rounds) | 1,004 | 6,985 | 64 | 21 exact affine relations survive one double round; 6,985 input-output bit pairs never interact | | 2 (4 rounds) | 1,025 | 0 | +4.72 / -4.59 at 4,096 lines; +4.71 / -4.73 at 262,080 lines (file 98) | nothing: at 2^18 lines a flip bias of 2^-8.5 would read 6 sigma, so the single-bit flip test stops between one and two double rounds | | 3 (6 rounds) | 1,025 | 0 | +4.81 / -4.70 at 262,080 lines | nothing | | 4 (8 rounds) | 1,025 | 0 | +4.76 / -4.77 at 262,080 lines | nothing | | 6 (12 rounds, the real `B`) | 1,025 | 0 | +4.47 / -4.53 at 4,096 lines; +4.38 / -4.66 at 262,080 lines | nothing; the expected maximum of 262,144 normal draws is 4.9 sigma and every ladder row sits on it | The small-scale model `B(4, 2)` (16 words of 4 bits, 2 double rounds, rotations 1, 1, 1, 3): the template search over the 16-line chain reads 0 matches on 1,048,576 lines (34.5 M compares, chance 1.9 x 10^-12); the flip table has 0 zero cells. Two caveats on the model, stated so nobody over-reads it: `s` is truncated to 4 bits, so the 65,536 "segments" are 16 distinct chains repeated (the per-`j` rank of 16 is that repetition, not a relation); and the word-level test is not valid at 4-bit words (a 4-bit output word equals its old value by chance 1 in 16, so "16 of 16 words from a subset" at w = 4 is chance, not structure). The model's job here was to run the same code at a width where the plants are cheap; both plants fired on it (61,440 of 65,536 lines each). Known-failed shapes, all fired: `no-xor` (prev not XORed in) reads 64,512 of 65,536 lines at 1 block by `B(c_j)`, a flip table of 262,144 zero cells and 16 of 16 words from a subset (rank of `(x_j, line_j)` 529, since `x_j = c_j` varies in two words only); `no-feedforward` (`B = C`) reads 64,512 lines recovered by `Cinv(line_j) XOR c_j` and 64,512 of 64,512 inversions, with the rank and flip tables unchanged (a permutation is still a good mixer; the loss is the one-way property); `--rounds 0` collapses the rank to 17. At 1,024 lines the plants read 16,368 of 16,384. Reading: no earlier-line-free derivation of any line, no affine relation between consecutive lines, no bit or word of a line computable from part of its input, no inverse. The one-way property of `B = C(x) + x` is what the chain's cost rests on, and the plant without it falls to the inverse template at once. ## 2. Q2: the feed-forward relations and partial knowledge Command (box 1, file 94): `adv-cache-3 relations --day0 20730 --days 4 --lines-log2 20 --threads 88` (log `relations-4d-l20.log`); the ladder `--rounds 1`, `--rounds 2` at 2^16 lines, `--rounds 3` at 2^18. Lines `j >= 1` of segments 0 to 16,383 on days 20730 to 20733: 4,128,768 lines. | Statistic | Samples | Worst |z| | Where | Gate 6 | |---|---|---|---|---| | `line_j XOR x_j`, per bit | 4,128,768 | 3.00 | word 1 bit 16 | PASS | | `line_j - x_j` (that is `C(x_j)`), per bit | 4,128,768 | 3.58 | word 2 bit 11 | PASS | | `line_j XOR line_{j-1}`, per bit | 4,128,768 | 3.29 | word 8 bit 11 | PASS | | `line_j - line_{j-1}`, per bit | 4,128,768 | 3.29 | word 10 bit 13 | PASS | | `x_j[a] XOR line_j[b]` over all 262,144 cells (the `line_{j-1}` table is the same up to a sign per column, since `x_j = line_{j-1} XOR c_j`) | 4,128,768 | 4.83 | in word 9 bit 8, out word 14 bit 19; 0 cells over 5 sigma against 0.15 expected | PASS | The expected maximum of 2,048 or 262,144 normal draws is 3.5 or 4.9 sigma; the worst cells sit on those. Partial knowledge (section 1's word table and inversion): given `k < 16` words of `line_{j-1}`, 0 words of `line_j` are determined (every output word changes when any single input word changes, 4,096 of 4,096 times); given `line_j`, nothing of `x_j` leaks beyond the correlation table's chance level, the direct inverse recovers 0 lines and the fixed-point iteration converges on 0. What IS known of `x_j` from the code: at `j = 0` all 16 words (`x_0 = c_0`, public, the spec says so); at `j >= 1` no word, since every word of `c_j` is XORed with the previous line. The plant caveat, stated plainly: the queue file's known-failed shape ("a reduced C at 2 rounds must show a measurable bias") did not fire on the bias and correlation statistics. At one double round (2 ChaCha rounds) the worst bias reads 3.22 sigma and the worst correlation cell 4.47 at 2^16 lines; at two double rounds 4.58 and 4.65; at three 4.33 and 4.45 at 2^18 lines. Single-bit biases of `C(x) + x` over a near-uniform `x` and single-bit-in, single-bit-out linear correlations are not where a reduced ChaCha leaks: the 21 affine relations one double round leaves involve many bits at once, and the public distinguishers on 3 to 7 rounds use a chosen input difference with a multi-bit output mask and 2^30 or more samples. The relation class's plants that do fire are the rank test (rank 1,004 at one double round, 17 at zero) and the flip table (6,985 zero cells at one double round), both in section 1, and `no-feedforward` on the inversion. So the Q2 sweep is a bound on exactly what it measures (per-bit biases and pairwise correlations at 2^22 samples, under 6 sigma), and the known-failed shape for the relation class is carried by section 1's tests, not by this one. A statistic that would fire at two double rounds is a differential-linear one with 2^20 or more samples per input difference; section 8b. ## 3. Q3: the pebbling curve Command (box 1, file 93): `adv-cache-3 pebble --lines 64 --exhaustive-upto 16 --mc 1000000` (log `pebble.log`); plant `--skip-edge 8` (`pebble-plant-skip8.log`). Pure arithmetic and Monte Carlo on the chain as a graph; no day key. The model: `k` held lines of 64 (`f = k / 64`); a uniform read of line `j` costs the walk from the nearest held line at or below `j` (or from nothing: `j + 1`). The exact optimum over placements by dynamic programming agrees with exhaustive search over every subset at 10, 12, 14 and 16 lines for `k` = 1, 2, 4 (12 of 12). Ops per item `9,360 + 8 x blocks x 608`; SRAM `f x 128 mm^2` at the N5 headline of `chip-model-v3.md` section 2. | `f` | `k` held | DP optimum, blocks per read | hold every (64/k)-th line (offset 0 and offset step-1) | ops per item at the optimum | multiple of the item's 9,360 | SRAM mm^2 | |---|---|---|---|---|---|---| | 1/64 | 1 | 16.00 (line 32 held) | 31.50 | 87,184 | 9.3x | 2 | | 2/64 | 2 | 10.50 | 15.50 | 60,432 | 6.5x | 4 | | 4/64 | 4 | 6.09 | 7.50 | 39,000 | 4.2x | 8 | | 8/64 | 8 | 3.17 | 3.50 | 24,788 | 2.6x | 16 | | 16/64 | 16 | 1.45 | 1.50 | 16,428 | 1.8x | 32 | | 32/64 | 32 | 0.50 | 0.50 | 11,792 | 1.26x | 64 | | 1 | 64 | 0 | 0 | 9,360 | 1.00x | 128 | The finding, and what it is not: the gate asked for a curve "never below the honest hold-every-k-th curve". The optimum IS below it at small `f`, by 2.0x at `f = 1/64` and 1.5x at 2/64, because holding every `(64/k)`-th line puts the first held line at the segment's start, where the chain is cheap anyway (line 0 costs 1 block from nothing), and leaves the far half unprotected. The optimal single held line is line 32; the optimal `k` lines are spaced closer toward the end of the segment. This is a correction of the honest baseline that sibling `adv-cache`'s Q1b table and the gate wording carry (31.5, 15.5, 7.5, 3.5, 1.5, 0.5 blocks), not an attack: the honest miner holds the whole cache and pays nothing per read; what moves is the price a partial-cache chip pays, which at `f = 1/64` is 9.3x the item's operations instead of 17.4x. At the chip-relevant point `f = 1/2` nothing changes (0.50 blocks per read, 1.26x the item's ops, 64 mm^2 saved), so the SRAM column of `chip-model-v3.md` and sibling `adv-cache`'s verdict (monotone toward the full store) stand. The curve is monotone in `f` and reads 9,360 at `f = 1` as the gate requires. The amortising adversary (`m` requests in one segment, one walk per gap from the nearest held line to the deepest request; the 2^16 segments are independent so nothing amortises across them; Monte Carlo 10^6 trials, the stride placement at offset step-1): | `f` | m = 1 | m = 2 | m = 4 | m = 8 | m = 16 | m = 64 | Poisson 1 | Poisson 8 | Poisson 64 | |---|---|---|---|---|---|---|---|---|---| | 1/64 (line 63 held: in effect nothing) | 31.52 | 21.07 | 12.67 | 7.05 | 3.73 | 0.98 | 23.24 | 6.95 | 0.98 | | 2/64 | 15.49 | 12.94 | 9.55 | 6.10 | 3.47 | 0.95 | 13.24 | 5.90 | 0.95 | | 4/64 | 7.50 | 6.90 | 5.89 | 4.48 | 2.94 | 0.90 | 6.93 | 4.33 | 0.90 | | 8/64 | 3.50 | 3.36 | 3.11 | 2.69 | 2.09 | 0.80 | 3.37 | 2.62 | 0.80 | | 16/64 | 1.50 | 1.47 | 1.42 | 1.32 | 1.16 | 0.61 | 1.47 | 1.30 | 0.61 | | 32/64 | 0.50 | 0.50 | 0.49 | 0.47 | 0.45 | 0.32 | 0.50 | 0.47 | 0.32 | Cross-check: with nothing held the Poisson rows read 23.24, 6.95 and 0.98 blocks per read at `m` = 1, 8, 64; sibling `adv-cache` measured 23.84, 7.06 and 0.99 on real addresses (its batch rows), so the uniform model and the real derivation agree to 3 percent. Batching helps only when `m` requests per segment are many, which costs `m x 2^16 x 64 B` of item state (the sibling's point); with half the lines held the gain at `m = 64` is 0.50 to 0.32 blocks per read, 0.2 x 608 = 110 operations per read against the item's 9,360. Known-failed shape: `--skip-edge 8` (line `j` also derivable from line `j - 8` in one block) lowers the `f = 1/64` optimum from 16.00 to 5.19 blocks per read; fired. ## 4. Q4: cross-segment and cross-day relations Command (box 1, file 93): `adv-cache-3 cross --day 20730 --segments 4096 --threads 88` (`cross-d20730.log`); plant `--plant no-xor --rounds 1` (`cross-plant-noxor-r1.log`). Pairs `s, s XOR 2^(p mod 16)` with `s = (p * 0x9E37) AND 0xffff`; the cross-day table pairs line `(s, j)` of day 20730 with the same of day 20731, `j = p mod 64`. | Table | Samples | Worst |z| of 262,144 cells | Cells over 6 sigma | |---|---|---|---| | `line_0(s)` against `line_0(s XOR 2^b)` (the 2^16 first inputs differ in word 12 only: the multi-target) | 4,096 | 4.50 | 0 | | `line_1(s)` against `line_1(s XOR 2^b)` | 4,096 | 4.75 | 0 | | `line_63(s)` against `line_63(s XOR 2^b)` | 4,096 | 5.00 | 0 | | `line_j(s)` of day 20730 against day 20731 | 4,096 | 4.56 | 0 | The plant (prev not XORed in, one double round) reads 3,385 to 3,585 cells over 6 sigma per segment table (worst 64) and 1,113 in the day table; fired. ## 5. Q1 (4): the exhaustive image census at w = 2 Command (box 2, file 95 to depth 8 at 87 cores, then file 97 in full at 32 cores): `adv-cache-3 image --w 2 --rounds 6 --depth 64 --threads {cores}` (logs `image-w2-r6-d64-partial-to-depth8.log`, `image-w2-r6-d64-full.log`); the plant `--plant no-feedforward --depth 6` (`image-w2-plant-noff.log`). The 16-word block at 2-bit words is a 32-bit state; every one of the 2^32 states is enumerated at each step, so the census is exact. `S_0` is every state; `S_k = { B(p XOR c_k) : p in S_{k-1} }` with the real constant layout truncated to 2 bits (`j` wraps mod 4). What it measures: how much of the state space the chain can still reach at depth `k`, against a random function (`tau_k = 1 - exp(-tau_{k-1})`) and a permutation (1 at every depth, the plant). | Depth | Image of 2^32 | Random-function recursion | Difference | Wall at 32 cores | |---|---|---|---|---| | 1 | 0.632142 | 0.632121 | +2.1 x 10^-5 | 87 s | | 2 | 0.468559 | 0.468536 | +2.3 x 10^-5 | 133 s | | 4 | 0.312098 | 0.312080 | +1.8 x 10^-5 | 201 s | | 8 | 0.189061 | 0.189050 | +1.1 x 10^-5 | 288 s | | 16 | 0.106546 | 0.106537 | +0.9 x 10^-5 | 395 s | | 24 | 0.074372 | 0.074368 | +0.4 x 10^-5 | 466 s | | 32 | 0.057174 | 0.057173 | +0.1 x 10^-5 | 513 s | | 48 | 0.039133 | 0.039132 | +0.1 x 10^-5 | 579 s | | 64 | 0.029762 | 0.029762 | 0 to six places | 633 s | | plant `no-feedforward`, depths 1 to 6 | 1.000000 at every depth (4,294,967,296 states) | | | 451 s | The full run was 2.3 x 10^11 reduced block evaluations (the images summed over 64 depths), 10.5 minutes on 32 cores. Reading: `B = C + x` behaves as a random function to five decimal places at every depth of the chain, so the chain loses `log2(k / 2)` bits of its state per `k` steps (about 5 bits of 512 at depth 64, 0.03 of the space at 2-bit words) and no faster. A skip would show as an image smaller than the recursion (a collapse of the state space, which a chip could enumerate) or larger (a permutation-like structure, which inverts); neither. The plant without the feed-forward is a permutation and reads 2^32 at every depth, so the test fires on the shape it is meant to catch. A caveat on the model, the same as section 1's: at 2-bit words the rotations are all 1 and `s`, `j` are truncated, so this measures the chain's shape under a ChaCha-like random-looking block, not 12-round ChaCha's own diffusion. ## 6. Consequences per tier Every row is a bound or a bookkeeping correction, so nothing changes for any tier today: a home miner with one 8, 12, 16 or 24 GB card on any vendor and OS, a rig and a pool user fill the 256 MiB cache once a day (0.2 s on one core per the spec's table, under a second at the growth steps) and the hash never reads it. For the chip model: the partial-cache price at small `f` is about half of what the hold-every-k-th curve says (section 3), which makes a chip holding 1/64 of the cache pay 9.3x the item's operations instead of 17.4x; still far above the full store, and at `f = 1/2` nothing moves, so the SRAM column (128 mm^2, $46 at N5 for 256 MiB) stays the chip's cost. What is being done: the curve row is handed to the coordinator for `chip-model-v3.md` and sibling `adv-cache`'s table; section 8b names the one statistic that would sharpen the reduced-round margin. ## 7. What is not covered - No differential-linear cryptanalysis of reduced ChaCha with chosen input differences and multi-bit masks; the ladder here stops where single-bit statistics stop (two double rounds at 4,096 to 2^16 samples). Public work on 7 of 20 rounds is general knowledge here, not a citation, and the real `B` has 12 rounds. - The 2-bit and 4-bit models change the rotations (1, 1, 1, 3 and 1, 1, 1, 1) and truncate `s` and `j`; they test the code path and the chain shape, not ChaCha's diffusion. - The derivation program class (`derive_len != 0`) is not exercised; class v4 has the fixed mixer and the chain does not depend on it. - GPU: no row; nothing in this class needs one. ## 8b. What a longer pass would add One line: a differential-linear sweep on the reduced ladder (one chosen input difference, every output bit and every two-bit output mask, 2^24 samples per round count, 2 to 6 double rounds) would put a number on the round margin where section 1's single-bit tests stop (between one and two double rounds at 2^18 lines, file 98); it changes no row at 12 rounds, and nothing here is a reason to wait for it. ## 9. Run ledger and box-hours | Run | Box | Started (BST) | Wall | Slot-hours | |---|---|---|---|---| | `check`, first `skip` (binary `067ad69c...`, under the sweep flock) | 1 | 20:06, 20:09 | 2 s, 1 s (3 min waiting for the lock) | 0.001 | | Files 93, 94, 95 queued under the sweep flock | 1, 2 | 20:12 to 20:15 | never started; killed by pid file 20:20 to 20:21 under main's rule (every sweep through `lease pool`); nothing measured was lost | 0 | | File 93 (14 runs: skip x 10, pebble x 2, cross x 2), file 94 (relations x 4), file 96 (skip at 1,024 lines x 4), through `lease pool 88` | 1 | 20:22:52 to 20:23:06 | 14 s in all, 0.1 to 2 s per run on 88 cores | 0.004 | | File 95, the image census, `lease pool 88` (87 cores taken) | 2 | 20:22:46 | 106 s to depth 8; released at 20:24:38 by main's order for the class v5 gate (partial kept) | 0.026 | | File 97, the image census again plus the plant, `lease pool 48 --min 16` | 2 | queued 20:26; its yield loop passed at 20:35 when the class-v5 waiter line was absent for a moment, the lease took 48 cores at 20:41:15 and the binary ran about 30 s while class-v5 waited; killed by pid 20:41:5x (my error against main's order of 20:3x: no adv-* lease on box 2 until the class v5 census runs); not restarted until main clears box 2 | 0.4 min | 0.007 | | File 98, the flip-table ladder at 2^18 lines (rounds 2, 3, 4, 6), resubmitted 20:43 at `lease pool 32 --min 16` under the ranked lease (class adv), binary `45911ba7...` (the harness with `--dep-samples`, commit d5d53701) | 1 | queued 20:33, cores taken 21:13 after 30 min waiting | 4 runs of 5 s each on 32 cores, done 21:14 | 0.005 | | File 97, the image census again at `lease pool 32 --min 16`, class adv | 2 | restarted 21:13 when main opened box 2; cores taken 21:13 | depth 64 in 10.5 min, the plant 7.5 min; done 21:34 | 0.17 (32 of 88 cores for 18 min, counted as 0.36 of a slot) | | Sibling file 43 (`adv-cache-2 warps-devnet-2e26-v2`, owner adv-cache-2: the 2^26-nonce warps census of the devnet program), claimed by this lane at 21:16 as the next unclaimed queue file, run with the same command at 32 threads (24 taken) | 2 | 21:35 | killed at 21:39 by adv-cache-2's drain (by mistake, as an orphan of its own; 247 s and 24 cores lost); the owner says file 43 is superseded by its item 430 at 2^25 nonces, so it is not run again; the partial log is kept as `sibling-43-warps-devnet-2e26-v2.log` (section 10) | 0.03 | Running total: 0.26 slot-hours of the 8 budgeted (the ask line is 16); no pod-hours. Every sweep the plan called for ran in seconds because the chain is 2^22 blocks a day and the statistics here are 2^22 to 2^27 block evaluations; the width went into day keys, chain lengths and the reduced-round ladder rather than into time. ## 10. Sibling queue file 43, run for adv-cache-2 Claimed at 21:16 as the only unclaimed file in THE QUEUE (`43-adv-cache-2-warps-devnet-2e26-v2.sh`, owner `adv-cache-2`, its binary and its log directory), run with the file's own command at 32 threads (`lease pool 32 --min 16`, 24 cores taken) from 21:35. The process was ended by SIGTERM at 21:39 after 247 s (rc 143): adv-cache-2's drain killed it by mistake as an orphan of its own, about 3 minutes of 24 cores lost. The owner has since said the file is superseded by its item 430 at 2^25 nonces, so the row is not needed and the file is not run again. What the log had written before the kill, for the owner to read against its own gates (its statistics, not this lane's): | Row in the owner's log | Reading | |---|---| | per-site histograms (16 sites, 2^22 items each, 2^29 reads) | worst z_max +5.21, chi2/dof 1.00084 at site 15 | | LINE histogram, 2^36 line reads | matches the windowed control to 4 figures (chi2/dof 630.31 against 630.29; z_max 147.4 against 147.0: the window layer's designed non-uniformity, present in the control too) | | hot set, lines, f = 0.1 / 0.5 / 1 percent | S_f equals the control's E_f to 1.0000x, 1.0001x, 1.0001x: "verdict clear" | | SEGMENT histogram | matches the control (631.64 against 631.68; the largest bucket 21,859 in both) | | REAL LINE STORE | f = 1/2 stride 0.260x of the item's ops, f = 1/2 hottest 0.431x, f = 1/4 stride 0.779x; equal under the control | | ITEM STORE (hottest items) | f = 0.001: 0.9991x of the model's ops per hash; f = 0.01: 0.9918x; the f = 0.1 row cut by the kill | The file stays claimed as it is; nothing else was queued behind it in this lane.