From 2df3aedafea445ccc69a203bf4c1d7d25b2cc912 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 12:34:41 +0000 Subject: [PATCH] Class v6 census: the era-aware F8-form uniformity tool (v6census-uniform) Co-Authored-By: Claude Fable 5.1 Documents-only replay of 14c550e38 (cfd0b1db936c45275e33697c5b283eb12b25a424) for the box mirror master --- tools/attack/v6-census/uniform/Cargo.toml | 15 +++ tools/attack/v6-census/uniform/src/main.rs | 117 +++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 tools/attack/v6-census/uniform/Cargo.toml create mode 100644 tools/attack/v6-census/uniform/src/main.rs diff --git a/tools/attack/v6-census/uniform/Cargo.toml b/tools/attack/v6-census/uniform/Cargo.toml new file mode 100644 index 000000000..d8b2b0d63 --- /dev/null +++ b/tools/attack/v6-census/uniform/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "v6census-uniform" +version = "0.1.0" +edition = "2021" +publish = false + +[[bin]] +name = "v6census-uniform" +path = "src/main.rs" + +[dependencies] +igneum-pow = { path = "../../../../igneum-pow" } + +[profile.release] +opt-level = 3 diff --git a/tools/attack/v6-census/uniform/src/main.rs b/tools/attack/v6-census/uniform/src/main.rs new file mode 100644 index 000000000..60fe4a996 --- /dev/null +++ b/tools/attack/v6-census/uniform/src/main.rs @@ -0,0 +1,117 @@ +//! v6census-uniform (class v6 census lane, 8 October 2026): the F8-form uniformity read of the invention lane's tool +//! (`tools/attack/v6-invention/uniform`) with the era draw added, for the read-width and op-mix candidates. Per seed: +//! the first accepted candidate of the class under the harness (`IGNEUM_FAMILY_GATE`, the class's own attempt cap), +//! then over `nonces` nonces every load's word index through the library's own `trace_load_indices`; per site the +//! distinct-index ratio `d_s / E_s` with `E_s = N - N^2 / (2 W_s)` at the site's window over the width (the (c'') +//! form), and the cross-hash ITEM histogram's top 0.1 percent share against a uniform SplitMix64 control of the same +//! size (the F8 harness's null; under an era the narrow-window sites raise the share by design, so the line to read +//! is the candidate against the control class at the same era, not the no-era 1.2x alone). One TSV row per seed. +//! +//! v6census-uniform --class w64m8g+sh256x27 --seeds 16 --nonces 1048576 --threads 16 [--era igneum-era-test/3 --era-widths 64] +use igneum_pow::generator::{attempts_class_to, max_attempts_for, EraParams, LoadClass, ITERATIONS}; +use igneum_pow::seed::{seed_words_from_bytes, SplitMix64}; +use igneum_pow::verify::{trace_load_indices, window, DatasetMode, DatasetSource}; +use std::collections::HashSet; +use std::io::Write; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Mutex; + +fn arg(args: &[String], k: &str, d: &str) -> String { + args.iter().position(|a| a == k).and_then(|i| args.get(i + 1).cloned()).unwrap_or_else(|| d.to_string()) +} + +fn top_share(counts: &mut Vec, frac: f64) -> (f64, u32) { + let total: u64 = counts.iter().map(|&c| c as u64).sum(); + counts.sort_unstable_by(|a, b| b.cmp(a)); + let k = ((counts.len() as f64) * frac) as usize; + let top: u64 = counts[..k].iter().map(|&c| c as u64).sum(); + (top as f64 / total as f64, counts[0]) +} + +fn parse_widths(s: &str) -> Vec { + let mut v: Vec = s.split(',').map(|x| match x.trim() { "4" => 1u8, "16" => 4, "64" => 16, _ => panic!("width") }).collect(); + v.sort_unstable(); + v +} + +fn main() { + let args: Vec = std::env::args().collect(); + let class_name = arg(&args, "--class", "mx8+sh256x27"); + let seeds: u32 = arg(&args, "--seeds", "16").parse().unwrap(); + let nonces: u32 = arg(&args, "--nonces", "1048576").parse().unwrap(); + let threads: usize = arg(&args, "--threads", "16").parse().unwrap(); + let log2: u32 = arg(&args, "--log2", "28").parse().unwrap(); + let day = arg(&args, "--day", "2026-10-03"); + let prefix = arg(&args, "--prefix", "igneum-v6c"); + let era = arg(&args, "--era", "none"); + let widths = parse_widths(&arg(&args, "--era-widths", "4")); + let mut class = LoadClass::parse(&class_name).expect("class"); + if era != "none" { + assert!(era.starts_with("igneum-era-test/"), "era: igneum-era-test/"); + class = LoadClass::era(class, &EraParams::test_era_bytes(&era), &widths); + } + let cap = max_attempts_for(&class); + let ds = DatasetSource::new(&day, DatasetMode::ClosedForm, log2); + let items = 1usize << (log2 - 4); + let mask = (1u32 << log2) - 1; + let n = (nonces as f64) * (ITERATIONS as f64); // evaluations per site + let next = AtomicUsize::new(0); + let out = Mutex::new(std::io::stdout()); + println!("class\tera\tseed\tattempt\tprogram_id\tmin_site_ratio\tmin_site\ttop0.1_share\tcontrol_share\tratio_to_control\tmax_item_reads\tcontrol_max\treads"); + std::thread::scope(|s| { + for _ in 0..threads { + s.spawn(|| loop { + let i = next.fetch_add(1, Ordering::Relaxed) as u32; + if i >= seeds { + break; + } + let label = format!("{prefix}/{i}"); + let tries = attempts_class_to(&label, label.as_bytes(), class, cap); + let Some((p, _)) = tries.into_iter().find(|(_, r)| r.is_ok()) else { + let mut o = out.lock().unwrap(); + writeln!(o, "{class_name}\t{era}\t{i}\texhausted").unwrap(); + continue; + }; + let seed = seed_words_from_bytes(label.as_bytes()); + let loads: Vec<_> = p.instrs.iter().filter(|x| x.op.is_load()).cloned().collect(); + let sites = loads.len(); + let mut distinct: Vec> = (0..sites).map(|_| HashSet::with_capacity(nonces as usize)).collect(); + let mut counts = vec![0u32; items]; + let mut reads: u64 = 0; + let mut base = 0u32; + while base < nonces { + let rows = trace_load_indices(&p, &seed, base, &ds); + for (k, row) in rows.iter().enumerate() { + let site = k % sites; + for &idx in row.iter() { + distinct[site].insert(idx); + counts[(idx >> 4) as usize] += 1; + reads += 1; + } + } + base += 32; + } + let (min_ratio, min_site) = distinct + .iter() + .enumerate() + .map(|(s, d)| { + let ins = &loads[s]; + let w = if p.class.era.is_some() { (window(ins, mask, log2).0 as u64 + 1) as f64 } else { (1u64 << log2) as f64 } / (ins.width.max(1) as f64); + let e_s = n - n * n / (2.0 * w); + (d.len() as f64 / e_s, s) + }) + .fold((f64::MAX, 0usize), |a, b| if b.0 < a.0 { b } else { a }); + let (share, max_reads) = top_share(&mut counts, 0.001); + let mut ctrl = vec![0u32; items]; + let mut rng = SplitMix64::new(0x9e37_79b9_7f4a_7c15 ^ i as u64); + for _ in 0..reads { + let x = rng.next() as usize & (items - 1); + ctrl[x] += 1; + } + let (cshare, cmax) = top_share(&mut ctrl, 0.001); + let mut o = out.lock().unwrap(); + writeln!(o, "{class_name}\t{era}\t{i}\t{}\t{:016x}\t{min_ratio:.5}\t{min_site}\t{share:.6}\t{cshare:.6}\t{:.4}\t{max_reads}\t{cmax}\t{reads}", p.attempt, p.program_id(), share / cshare).unwrap(); + }); + } + }); +}