//! Every pinned pack's program id re-derived from its own `program_id_derivation` text (the documentation finding of //! 7 October 2026, the in-house pass adv-accept-3: program.json and spec 1.4.6 stated the plain form while generator 4 //! appends `'sub/' || sub_version_le16`, so a client written from the text derived 30956569d8f3d8d7 for Devnet 3's epoch //! 0 where the chain says fce15bf61030be57). The text is parsed part by part and the bytes come from the pack's own fields //! (generator, attempt, seed_words, sub_version, load_class), never from the code's id function, so the test fails the //! moment the printed derivation and the hashed bytes disagree. use igneum_pow::generator::LoadClass; use serde_json::Value; use std::path::{Path, PathBuf}; fn fnv1a64(b: &[u8]) -> u64 { let mut h: u64 = 0xcbf2_9ce4_8422_2325; for &x in b { h ^= x as u64; h = h.wrapping_mul(0x0000_0100_0000_01b3); } h } fn hex64(v: &Value) -> u64 { u64::from_str_radix(v.as_str().unwrap().trim_start_matches("0x"), 16).unwrap() } /// The bytes a derivation part names, from the pack's own fields. fn part_bytes(part: &str, j: &Value, class: Option<&LoadClass>) -> Vec { if let Some(lit) = part.strip_prefix('\'').and_then(|p| p.strip_suffix('\'')) { return lit.as_bytes().to_vec(); } let c = || class.unwrap_or_else(|| panic!("part {part} needs the pack's load_class")); match part { "generator_le32" => (j["generator"].as_u64().unwrap() as u32).to_le_bytes().to_vec(), "attempt_le32" => (j["attempt"].as_u64().unwrap() as u32).to_le_bytes().to_vec(), "seed_words as little-endian bytes" => j["seed_words"].as_array().unwrap().iter().flat_map(|w| (hex64(w) as u32).to_le_bytes()).collect(), "sub_version_le16" => (j["sub_version"].as_u64().expect("a generator-4 pack carries sub_version") as u16).to_le_bytes().to_vec(), "mix[3]" => c().mix.to_vec(), "load_slots_u8" => vec![c().load_slots], "scratch_k_u8" => vec![c().scratch.unwrap()], "scratch_kb_u8" => vec![c().scratch_kb], "mixer_mult_u8" => vec![c().mixer_mult], "growth_u8" => vec![c().growth as u8], "derive_len_le16" => c().derive_len.to_le_bytes().to_vec(), "shadow_instrs_le16" => c().shadow.unwrap().instrs.to_le_bytes().to_vec(), "shadow_reps_le16" => c().shadow.unwrap().reps.to_le_bytes().to_vec(), "hot_mb_u8" => vec![c().hot.unwrap().mb], "hot_k_u8" => vec![c().hot.unwrap().k], other => panic!("derivation part {other:?} is not one this test knows; teach it the field before pinning such a pack"), } } fn rederive(dir: &Path) -> (u64, u64, String) { let j: Value = serde_json::from_str(&std::fs::read_to_string(dir.join("program.json")).unwrap()).unwrap(); let text = j["program_id_derivation"].as_str().unwrap().to_string(); let parts = text.strip_prefix("FNV-1a 64 over ").unwrap_or_else(|| panic!("{}: the derivation does not start with 'FNV-1a 64 over '", dir.display())); let class = j["load_class"].as_str().and_then(LoadClass::parse); let mut b = Vec::new(); for part in parts.split(" || ") { b.extend(part_bytes(part.trim(), &j, class.as_ref())); } (fnv1a64(&b), hex64(&j["program_id"]), text) } fn pinned_packs() -> Vec { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../proto-cuda"); let mut out = Vec::new(); for sub in ["packs-ca3-v4", "packs-ca3-shadow"] { let mut v: Vec<_> = std::fs::read_dir(root.join(sub)).unwrap().map(|e| e.unwrap().path()).filter(|p| p.join("program.json").is_file()).collect(); v.sort(); out.extend(v); } out.push(root.join("packs/igneum-devnet-v4-epoch0")); assert!(out.len() >= 18, "the pinned packs are missing; this test never skips ({} found)", out.len()); out } #[test] fn every_pinned_pack_id_rederives_from_its_own_derivation_text() { let mut seen_sub = false; for dir in pinned_packs() { let (derived, pinned, text) = rederive(&dir); assert_eq!(derived, pinned, "{}: the id re-derived from \"{text}\" is {derived:016x}, the pack says {pinned:016x}", dir.display()); if text.contains("'sub/'") { seen_sub = true; } } assert!(seen_sub, "at least one generator-4 pack states the 'sub/' || sub_version_le16 suffix"); } #[test] fn the_class_v4_derivation_states_the_suffix_and_the_plain_text_derives_another_id() { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../proto-cuda/packs-ca3-v4/v4-devnet-epoch0"); let j: Value = serde_json::from_str(&std::fs::read_to_string(root.join("program.json")).unwrap()).unwrap(); let text = j["program_id_derivation"].as_str().unwrap(); assert!(text.ends_with("attempt_le32 || 'sub/' || sub_version_le16"), "{text}"); // the known-failed case: the text as printed before 7 October 2026 (no suffix) derives a different id let plain = "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32"; let mut b = Vec::new(); for part in plain.strip_prefix("FNV-1a 64 over ").unwrap().split(" || ") { b.extend(part_bytes(part, &j, None)); } assert_ne!(fnv1a64(&b), hex64(&j["program_id"]), "the plain text must not derive the pinned id (it did before the fix)"); assert_eq!(hex64(&j["program_id"]), 0xa785_0016_87d8_688a); } /// The record maker (ignored in the suite): prints `DERIVATION ` for every pack directory under proto-cuda, /// the program rebuilt as the pack tests rebuild it (generator 3 with era bytes under class v2's era layout for packs-ca2-era, /// generator 3 through the v3 seam otherwise, generator 2 with its load class, plain generator 2), so program.json's line can /// be set from the code's own recipe after a derivation change. `cargo test --release --test derivation -- --ignored --nocapture`. #[test] #[ignore] fn print_every_pack_derivation() { use igneum_pow::generator::{generate_era, generate_from_seed_bytes, generate_from_seed_bytes_class, generate_from_seed_bytes_program_class, ProgramClass, GENERATOR_VERSION_V3}; let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../proto-cuda"); let mut dirs: Vec = std::fs::read_dir(&root).unwrap().map(|e| e.unwrap().path()).filter(|p| p.file_name().unwrap().to_str().unwrap().starts_with("packs")).flat_map(|g| std::fs::read_dir(g).unwrap().map(|e| e.unwrap().path())).filter(|p| p.join("program.json").is_file()).collect(); dirs.sort(); for dir in dirs { let j: Value = serde_json::from_str(&std::fs::read_to_string(dir.join("program.json")).unwrap()).unwrap(); let seed = j["seed"].as_str().unwrap(); let seed_bytes = igneum_pow::bind::unhex(j["seed_bytes"].as_str().unwrap()).unwrap(); let gen = j["generator"].as_u64().unwrap() as u32; let era = j.get("era_seed_bytes").and_then(|v| v.as_str()).map(|h| igneum_pow::bind::unhex(h).unwrap()); let lc = j.get("load_class").and_then(|c| c.as_str()); let program = if gen == GENERATOR_VERSION_V3 && dir.parent().unwrap().file_name().unwrap() == "packs-ca2-era" { let allowed: Vec = j["era"]["allowed_widths"].as_array().unwrap().iter().map(|v| v.as_u64().unwrap() as u8).collect(); generate_era(seed, &seed_bytes, LoadClass::V2, era.as_deref().unwrap(), &allowed) } else if gen == GENERATOR_VERSION_V3 { generate_from_seed_bytes_program_class(seed, &seed_bytes, ProgramClass::V3, era.as_deref()) } else if gen == 4 { generate_from_seed_bytes_program_class(seed, &seed_bytes, ProgramClass::V4, era.as_deref()) } else if let Some(c) = lc { let Some(class) = LoadClass::parse(c) else { println!("SKIP {} load_class {c:?} is a name the parser no longer accepts (an old experiment's pack); its derivation line stands as written", dir.strip_prefix(&root).unwrap().display()); continue; }; generate_from_seed_bytes_class(seed, &seed_bytes, class) } else { generate_from_seed_bytes(seed, &seed_bytes) }; println!("DERIVATION {} {:016x} {}", dir.strip_prefix(&root).unwrap().display(), program.program_id(), program.program_id_derivation()); assert_eq!(program.program_id(), hex64(&j["program_id"]), "{}: the rebuilt program's id is the pack's", dir.display()); } }