From 5ae7e2c5a543c770b6da12daa7b4d4a3e7144edf Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Wed, 7 Oct 2026 22:21:24 +0000 Subject: [PATCH] spec 01 1.4.7.6: the class v5 constants table (one row per igneum-pow pub const, for the spec-constants check); igneum-pow: the listed-programs (c''') reading as an ignored test (IGNEUM_V5_PROGRAMS file: epoch, era, attempt per line) Co-Authored-By: Claude Fable 5.1 --- docs/spec/01-lottery-hash.md | 15 +++++++++ igneum-pow/src/accept.rs | 62 ++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/docs/spec/01-lottery-hash.md b/docs/spec/01-lottery-hash.md index 9dd6b96ed..9f84eee2d 100644 --- a/docs/spec/01-lottery-hash.md +++ b/docs/spec/01-lottery-hash.md @@ -232,6 +232,21 @@ Class v5 is a program-class step like class v4's (section 2's class signal): the The acceptance vectors of (c'''): seed 100767 of the f8 label space (epoch bytes the words of `igneum-attack-f8/program/100767`, era bytes of `igneum-attack-f8/era/100767`) is accepted under class v4 at attempt 2 (`9d68e6286fc817d4`, site 6 at 0.9919) and refused under class v5 at attempt 2 by (c''') naming site 6 at 0.991; the class v5 draw lands on attempt 4 (`734fbb8e3e4cd20f`); the genesis draws of both classes read 0.9990 at their minimum site. The day vector of AP-F4-1: chain day 29,337 under class v4 draws a mixer block of cost 203 and class v5 redraws it. The last-resort vector: seed adv3/steer/2 (`igneum-adv-accept-3/steer/2`, Devnet 3's genesis as the era) at attempt 256 fails part (a) at instruction 47 reading r3 under the class v4 rewrite; class v5's last resort passes at attempt 256 (`9b29c9481f6941d4`). The crate's tests hold every row (`tests/packs.rs`, `accept::tests`, `memhard::tests`, `generator::tests`). +#### 1.4.7.6 Constants + +One row per Rust `pub const` of igneum-pow that class v5 adds; the gate's spec-constants check reads the value column against the crate. `CLASS_SIGNAL_V5 = 6` and `CLASS_SIGNAL_WINDOWS = 7` are the fork's (`consensus/core/src/igneum.rs`) and are named in 1.4.7.4; class v5's attempt cap is class v4's `MAX_ATTEMPTS_V4 = 256` (section 1.4.6). + +| Constant | Value | Where | +|---|---|---| +| `MIN_DISTINCT_RATIO_V5` | 0.995 | `igneum-pow/src/accept.rs`, part (c''') | +| `MIXER_COST_REJECT_MAX` | 205 | `igneum-pow/src/memhard.rs`, AP-F4-1 | +| `MIXER_NAF_WORD_MIN` | 4 | `igneum-pow/src/memhard.rs`, AP-F4-1 (a multiplier with `w32` under this, a two-adder chain, rejects) | +| `MIXER_REDRAW_CAP` | 64 | `igneum-pow/src/memhard.rs` | +| `SHADOW_REMOVABLE_MAX_PERMILLE` | 30 | `igneum-pow/src/generator.rs`, AP-F1-1 | +| `SHADOW_REDRAW_CAP` | 64 | `igneum-pow/src/generator.rs` | +| `LAST_RESORT_SCAN` | 256 | `igneum-pow/src/generator.rs`, the verified last resort | +| `GENERATOR_VERSION_V5` | 5 | `igneum-pow/src/generator.rs` | + ## 1.5 Fixed memory footprint Implemented for the prototype size; Designed for genesis. diff --git a/igneum-pow/src/accept.rs b/igneum-pow/src/accept.rs index 9937dba06..905a1c4dc 100644 --- a/igneum-pow/src/accept.rs +++ b/igneum-pow/src/accept.rs @@ -883,6 +883,68 @@ mod tests { assert_eq!(v5_under, 0); } + /// The (c''') reading on a listed set of chain-shaped programs (run by hand on a box through the lease): the file + /// `IGNEUM_V5_PROGRAMS` holds one program per line, ` [tag...]` + /// (a hex field of 64 characters is the 32 bytes; anything else is a label whose `seed_words_from_bytes` words are + /// the bytes, as the f8 and adv label spaces derive theirs). Per line: the class v4 program at that attempt (its id, + /// minimum site and ratio at the 2^20 sample), the class v5 verdict at the same attempt, and the class v5 draw's + /// attempt. The coordinator's question of 7 October 2026, 23:3x UK: whether the drawn-era programs adv-cache-2 read + /// as biased (R from 3 to 22) sit under the 0.995 floor. + #[test] + #[ignore] + fn v5_floor_on_listed_programs() { + use crate::generator::{V5_CLASS, V3_ALLOWED}; + use crate::seed::seed_words_from_bytes; + let path = std::env::var("IGNEUM_V5_PROGRAMS").expect("IGNEUM_V5_PROGRAMS="); + let text = std::fs::read_to_string(&path).expect("the programs file"); + let bytes_of = |f: &str| -> Vec { + if f.len() == 64 && f.chars().all(|c| c.is_ascii_hexdigit()) { + crate::bind::unhex(f).unwrap() + } else { + seed_words_from_bytes(f.as_bytes()).iter().flat_map(|x| x.to_le_bytes()).collect() + } + }; + let mut refused = 0; + let mut rows = 0; + for line in text.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + let f: Vec<&str> = line.split_whitespace().collect(); + if f.len() < 3 { + println!("skip (needs epoch era attempt): {line}"); + continue; + } + let (epoch, era, attempt) = (bytes_of(f[0]), bytes_of(f[1]), f[2].parse::().expect("attempt")); + let tag = f[3..].join(" "); + let label = format!("igneum-epoch/{}", epoch.iter().map(|b| format!("{b:02x}")).collect::()); + let v4 = candidate_class(&label, &epoch, attempt, LoadClass::era(V4_CLASS, &era, &V3_ALLOWED)); + let st = site_index_stats(&v4, ACCEPT_UNITS_DISTINCT_V4).unwrap(); + let (min, site) = distinct_ratio_on(&v4, &st, ACCEPT_UNITS_DISTINCT_V4, 0.0).unwrap(); + let v4_verdict = check(&v4).is_ok(); + let v5 = candidate_class(&label, &epoch, attempt, LoadClass::era(V5_CLASS, &era, &V3_ALLOWED)); + let v5_verdict = check(&v5); + let drawn = f8_draw(&epoch, &era, V5_CLASS); + let era_params = v4.class.era.as_ref().map(|e| e.stride_rot).unwrap_or(0); + rows += 1; + if v5_verdict.is_err() { + refused += 1; + } + println!( + "listed: id {:016x} attempt {attempt} R {era_params} | v4 {} min site {site} ratio {min:.4} (most read {:#x} x{}) | v5 at this attempt {} | v5 draw attempt {} id {:016x} | {tag}", + crate::generator::program_id(crate::generator::GENERATOR_VERSION_V4, &v4.seed, attempt), + if v4_verdict { "accepted" } else { "REJECTED" }, + st[site].top_index, + st[site].top_count, + match &v5_verdict { Ok(_) => "accepted".to_string(), Err(r) => format!("REFUSED {r}") }, + drawn.attempt, + drawn.program_id() + ); + } + println!("listed: {refused} of {rows} refused under class v5 at the listed attempt"); + } + #[test] fn distinct_bound_scales_with_the_load_count() { assert_eq!(min_distinct_sum(128), MIN_DISTINCT_SUM);