Program id derivation stated exactly (adv-accept-3 documentation finding, 7 October 2026): the id and its printed derivation come from one byte recipe; program.json and spec 1.4.6 name the 'sub/' || sub_version_le16 suffix of generator 4 and the class-rung form; every pinned pack's id re-derived from its own text

generator.rs: IdRecipe (bytes + labelled parts), program_id_recipe and program_id_class_recipe build the bytes the id hashes and the text program.json prints, Program::program_id_derivation picks the form as program_id does. emit.rs prints that text. Spec 01 section 1.4.6 (the "Program id" paragraph) states the suffix, the class v5 form (generator 5, no suffix) and the rung form. tests/derivation.rs re-derives each of the 18 pinned packs' ids from its own derivation string with the pack's fields only (the plain text gives 8aa9f185d63f269e for the devnet v4 pack where the id is a785001687d8688a: the known-failed case). Packs: program.json re-exported for the 7 generator-4 packs and the 9 shadow ladder packs, one line each (the derivation); every other file byte-identical on re-export, ids and fingerprints unchanged. No object change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
igneum-labs 2026-10-07 20:25:53 +00:00
parent 57526e05c2
commit 6f2d63c826
20 changed files with 212 additions and 54 deletions

View file

@ -178,7 +178,7 @@ Implemented (`igneum-pow/src/accept.rs`, `proto-metal/main.swift`; ledger M6 Fix
Attempts. Attempt 0 of a program seed `b` (the 32-byte epoch seed, or the UTF-8 of a seed string) is the candidate drawn from `seed_words_from_bytes(b)`. If it fails, attempt `k = 1, 2, ...` is drawn from `seed_words_from_bytes(b || k_le32)`; the first accepted candidate is the program of the epoch. Measured rejection rate under this generator: 5.14 percent over 100,000 seeds (census section 7) and the 20,000-seed confirmation of `docs/bench-log.md` (4 October 2026), so the probability that 32 consecutive candidates fail is below 2^-136, and an implementation MAY treat 32 consecutive failures as a consensus fault (`MAX_ATTEMPTS`).
Program id. `FNV-1a-64("igneum-program/" || generator_le32 || seed words as little-endian bytes || attempt_le32)` with `generator = 2` under class v2 and `generator = 3` under class v3, written into every pack. Two implementations that agree on the id agree on the generator version, the seed words and the attempt.
Program id. `FNV-1a-64("igneum-program/" || generator_le32 || seed words as little-endian bytes || attempt_le32 || suffix)` with `generator = 2` under class v2 and `generator = 3` under class v3 (no suffix), and `generator = 4` under class v4 with the suffix `"sub/" || sub_version_le16` (the class v4 stream's sub-version, 3 since 7 October 2026: `PROGRAM_SUBVERSION_V4` in `generator.rs`, `IGNEUM_PROGRAM_SUBVERSION` in program.h, `"sub_version"` in program.json; without the suffix Devnet 3's epoch-0 id reads 30956569d8f3d8d7 where the chain and the packs say fce15bf61030be57); class v5 is `generator = 5` with no suffix. A program of a non-default class (a read-width, scratch, mixer, derivation, era, shadow or hot rung other than class v4's rung 0) uses the tag `"igneum-program-rw/"` and appends the class's fields after `attempt_le32` (`generator::program_id_class_recipe`). Every pack prints its own derivation as `program_id_derivation` in program.json, built from the same byte recipe the id is hashed from (`generator::IdRecipe`), and `igneum-pow/tests/derivation.rs` re-derives every pinned pack's id from that text. Two implementations that agree on the id agree on the generator version, the seed words, the attempt and, under class v4, the sub-version.
Why the closed form: the test is then a pure function of the program (no cache, no day), costs 1.3 to 3.4 ms on one core, and the census checked on 100,000 programs that its verdict agrees with the memory-hard dataset's on all but 39 threshold-edge cases (section 7.3). What the three parts catch: (a) the empty-list fallback of 1.4.3; (b) registers that saturate to all ones (2.4 percent of candidates); (c) zero-absorbing register sets, lane-constant load sites, output bias and value-level address repeats (2.1 percent). Not in the rule, and why: a contraction as the last write (80 percent of programs) and the `or` count are too common and (c) already catches the cases that matter; the load critical path is a hash-rate question, not a weakness.

View file

@ -1812,7 +1812,7 @@ pub fn program_json(p: &Program, day: &str, ds: &DatasetSource) -> String {
s.push_str(&format!(" \"generator\": {},\n", p.generator));
s.push_str(&format!(" \"attempt\": {},\n", p.attempt));
s.push_str(&format!(" \"program_id\": {},\n", jhex64(p.program_id())));
s.push_str(" \"program_id_derivation\": \"FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32\",\n");
s.push_str(&format!(" \"program_id_derivation\": {},\n", jstr(&p.program_id_derivation())));
s.push_str(&format!(
" \"dataset_mode\": {},\n",
jstr(if memhard.is_some() { "memory-hard" } else { "closed-form" })

View file

@ -1077,6 +1077,17 @@ impl Program {
}
}
/// The derivation of [`Program::program_id`] as text, from the same byte recipe (program.json's
/// "program_id_derivation"; spec 01 section 1.4.6).
pub fn program_id_derivation(&self) -> String {
let v4_rung_0 = self.generator == GENERATOR_VERSION_V4 && LoadClass { era: None, ..self.class } == V4_CLASS;
if self.class.is_v2() || self.generator == GENERATOR_VERSION_V3 || v4_rung_0 {
program_id_recipe(self.generator, &self.seed, self.attempt).text()
} else {
program_id_class_recipe(self.generator, &self.seed, self.attempt, &self.class).text()
}
}
/// The program class of this program, from its generator version (3 = v3, 4 = v4, everything else v2).
pub fn program_class(&self) -> ProgramClass {
match self.generator {
@ -1087,24 +1098,61 @@ impl Program {
}
}
pub fn program_id(generator: u32, seed: &[u32; 8], attempt: u32) -> u64 {
let mut b = Vec::with_capacity(PROGRAM_ID_TAG.len() + 4 + 32 + 4 + 6);
b.extend_from_slice(PROGRAM_ID_TAG);
b.extend_from_slice(&generator.to_le_bytes());
for w in seed {
b.extend_from_slice(&w.to_le_bytes());
/// The byte recipe of a program id and the text that states it: the bytes FNV-1a 64 hashes and, part by part, the label
/// of each part (`'literal'` or `field_le32`), so the derivation printed in program.json is built from the same list the id
/// is hashed from and the two cannot drift (the documentation finding of 7 October 2026: program.json and spec 1.4.6 said
/// the plain form while generator 4 appended `'sub/' || sub_version_le16`, so a client written from the text derived another
/// id). `tests/derivation.rs` re-derives every pinned pack's id from its own derivation string.
#[derive(Clone, Debug, Default)]
pub struct IdRecipe {
pub bytes: Vec<u8>,
parts: Vec<String>,
}
impl IdRecipe {
fn lit(&mut self, s: &[u8]) {
self.bytes.extend_from_slice(s);
self.parts.push(format!("'{}'", String::from_utf8_lossy(s)));
}
b.extend_from_slice(&attempt.to_le_bytes());
fn field(&mut self, bytes: &[u8], label: &str) {
self.bytes.extend_from_slice(bytes);
self.parts.push(label.to_string());
}
/// The derivation as program.json prints it: `FNV-1a 64 over <part> || <part> || ...`.
pub fn text(&self) -> String {
format!("FNV-1a 64 over {}", self.parts.join(" || "))
}
/// The id: FNV-1a 64 over the bytes.
pub fn id(&self) -> u64 {
fnv1a64(&self.bytes)
}
}
/// The recipe of [`program_id`].
pub fn program_id_recipe(generator: u32, seed: &[u32; 8], attempt: u32) -> IdRecipe {
let mut r = IdRecipe::default();
r.lit(PROGRAM_ID_TAG);
r.field(&generator.to_le_bytes(), "generator_le32");
let mut sw = Vec::with_capacity(32);
for w in seed {
sw.extend_from_slice(&w.to_le_bytes());
}
r.field(&sw, "seed_words as little-endian bytes");
r.field(&attempt.to_le_bytes(), "attempt_le32");
if generator == GENERATOR_VERSION_V4 {
// The class v4 sub-version (AP-F8-1 amendment, 7 October 2026): `"sub/" || sub_version as little-endian u16`
// appended for generator 4 only, so a binary from before the load-source rule (sub-version 0, no suffix) and
// one after it never share a program id for one seed; the node's id check then catches a split. v2 and v3
// ids are byte-identical. The node reads the sub-version from [`PROGRAM_SUBVERSION_V4`]; packs carry it as
// IGNEUM_PROGRAM_SUBVERSION and program.json "sub_version".
b.extend_from_slice(b"sub/");
b.extend_from_slice(&PROGRAM_SUBVERSION_V4.to_le_bytes());
r.lit(b"sub/");
r.field(&PROGRAM_SUBVERSION_V4.to_le_bytes(), "sub_version_le16");
}
fnv1a64(&b)
r
}
pub fn program_id(generator: u32, seed: &[u32; 8], attempt: u32) -> u64 {
program_id_recipe(generator, seed, attempt).id()
}
/// The sub-version of class v4's program stream, in every generator-4 program id and pack (AP-F8-3: 3 = the
@ -1118,53 +1166,60 @@ pub const PROGRAM_ID_TAG_RW: &[u8] = b"igneum-program-rw/";
/// The program id of a non-default class: the tag, then the same fields as [`program_id`], then the three mix
/// percentages and the slot count as bytes.
pub fn program_id_class(generator: u32, seed: &[u32; 8], attempt: u32, class: &LoadClass) -> u64 {
let mut b = Vec::with_capacity(PROGRAM_ID_TAG_RW.len() + 4 + 32 + 4 + 4);
b.extend_from_slice(PROGRAM_ID_TAG_RW);
b.extend_from_slice(&generator.to_le_bytes());
/// The recipe of [`program_id_class`].
pub fn program_id_class_recipe(generator: u32, seed: &[u32; 8], attempt: u32, class: &LoadClass) -> IdRecipe {
let mut r = IdRecipe::default();
r.lit(PROGRAM_ID_TAG_RW);
r.field(&generator.to_le_bytes(), "generator_le32");
let mut sw = Vec::with_capacity(32);
for w in seed {
b.extend_from_slice(&w.to_le_bytes());
sw.extend_from_slice(&w.to_le_bytes());
}
b.extend_from_slice(&attempt.to_le_bytes());
b.extend_from_slice(&class.mix);
b.push(class.load_slots);
r.field(&sw, "seed_words as little-endian bytes");
r.field(&attempt.to_le_bytes(), "attempt_le32");
r.field(&class.mix, "mix[3]");
r.field(&[class.load_slots], "load_slots_u8");
if let Some(k) = class.scratch {
b.extend_from_slice(b"scratch/");
b.push(k);
b.push(class.scratch_kb);
r.lit(b"scratch/");
r.field(&[k], "scratch_k_u8");
r.field(&[class.scratch_kb], "scratch_kb_u8");
}
if class.mixer_mult != 1 || class.growth {
// Counter ASIC 2.0: the mixer multiplier and the growth rule are part of the construction, so a program of
// the same seed under a different mixer carries a different id (under the v3 seam the id is
// program_id(3, seed, attempt) and this branch is not taken)
b.extend_from_slice(b"mixer/");
b.push(class.mixer_mult);
b.push(class.growth as u8);
r.lit(b"mixer/");
r.field(&[class.mixer_mult], "mixer_mult_u8");
r.field(&[class.growth as u8], "growth_u8");
}
if class.derive_len != 0 {
// Counter ASIC 3.0 item 2: the derivation program's length is part of the construction
b.extend_from_slice(b"derive/");
b.extend_from_slice(&class.derive_len.to_le_bytes());
r.lit(b"derive/");
r.field(&class.derive_len.to_le_bytes(), "derive_len_le16");
}
if let Some(e) = class.era {
b.extend_from_slice(b"era/");
b.extend_from_slice(&e.id_bytes());
r.lit(b"era/");
r.field(&e.id_bytes(), "era_id_bytes (allowed[3] || width_words_u8 || stride_mul_le32 || stride_rot_le32 || interleave[4])");
}
if let Some(sh) = class.shadow {
// Counter ASIC 3.0 item 8: the shadow block's size and repeat count are part of the construction
b.extend_from_slice(b"shadow/");
b.extend_from_slice(&sh.instrs.to_le_bytes());
b.extend_from_slice(&sh.reps.to_le_bytes());
r.lit(b"shadow/");
r.field(&sh.instrs.to_le_bytes(), "shadow_instrs_le16");
r.field(&sh.reps.to_le_bytes(), "shadow_reps_le16");
}
if let Some(h) = class.hot {
b.extend_from_slice(b"hot/");
b.push(h.mb);
b.push(h.k);
r.lit(b"hot/");
r.field(&[h.mb], "hot_mb_u8");
r.field(&[h.k], "hot_k_u8");
if h.added {
b.extend_from_slice(b"added");
r.lit(b"added");
}
}
fnv1a64(&b)
r
}
pub fn program_id_class(generator: u32, seed: &[u32; 8], attempt: u32, class: &LoadClass) -> u64 {
program_id_class_recipe(generator, seed, attempt, class).id()
}
/// Weights of the ten non-load families under version 2, in draw order. Sum 75. The load family has no

View file

@ -0,0 +1,103 @@
//! 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<u8> {
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<PathBuf> {
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);
}

View file

@ -3,7 +3,7 @@
"generator": 2,
"attempt": 0,
"program_id": "0xb42f8c8549967581",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program-rw/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || mix[3] || load_slots_u8 || 'mixer/' || mixer_mult_u8 || growth_u8 || 'shadow/' || shadow_instrs_le16 || shadow_reps_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-genesis",
"seed_bytes": "69676e65756d2d67656e65736973",

View file

@ -3,7 +3,7 @@
"generator": 2,
"attempt": 0,
"program_id": "0x9a5be3853b011f6c",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program-rw/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || mix[3] || load_slots_u8 || 'mixer/' || mixer_mult_u8 || growth_u8 || 'shadow/' || shadow_instrs_le16 || shadow_reps_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-genesis",
"seed_bytes": "69676e65756d2d67656e65736973",

View file

@ -3,7 +3,7 @@
"generator": 2,
"attempt": 0,
"program_id": "0x9a3d4d853ae722fb",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program-rw/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || mix[3] || load_slots_u8 || 'mixer/' || mixer_mult_u8 || growth_u8 || 'shadow/' || shadow_instrs_le16 || shadow_reps_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-genesis",
"seed_bytes": "69676e65756d2d67656e65736973",

View file

@ -3,7 +3,7 @@
"generator": 2,
"attempt": 0,
"program_id": "0x9a8b77853b298baa",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program-rw/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || mix[3] || load_slots_u8 || 'mixer/' || mixer_mult_u8 || growth_u8 || 'shadow/' || shadow_instrs_le16 || shadow_reps_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-genesis",
"seed_bytes": "69676e65756d2d67656e65736973",

View file

@ -3,7 +3,7 @@
"generator": 2,
"attempt": 0,
"program_id": "0x9abe71853b54db11",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program-rw/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || mix[3] || load_slots_u8 || 'mixer/' || mixer_mult_u8 || growth_u8 || 'shadow/' || shadow_instrs_le16 || shadow_reps_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-genesis",
"seed_bytes": "69676e65756d2d67656e65736973",

View file

@ -3,7 +3,7 @@
"generator": 2,
"attempt": 0,
"program_id": "0x9ae3d3853b749dd4",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program-rw/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || mix[3] || load_slots_u8 || 'mixer/' || mixer_mult_u8 || growth_u8 || 'shadow/' || shadow_instrs_le16 || shadow_reps_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-genesis",
"seed_bytes": "69676e65756d2d67656e65736973",

View file

@ -3,7 +3,7 @@
"generator": 2,
"attempt": 0,
"program_id": "0x9a477f853aefcc76",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program-rw/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || mix[3] || load_slots_u8 || 'mixer/' || mixer_mult_u8 || growth_u8 || 'shadow/' || shadow_instrs_le16 || shadow_reps_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-genesis",
"seed_bytes": "69676e65756d2d67656e65736973",

View file

@ -3,7 +3,7 @@
"generator": 2,
"attempt": 0,
"program_id": "0x9b6191853bdf72c1",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program-rw/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || mix[3] || load_slots_u8 || 'mixer/' || mixer_mult_u8 || growth_u8 || 'shadow/' || shadow_instrs_le16 || shadow_reps_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-genesis",
"seed_bytes": "69676e65756d2d67656e65736973",

View file

@ -3,7 +3,7 @@
"generator": 2,
"attempt": 0,
"program_id": "0x90cd909ac3e78d4a",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program-rw/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || mix[3] || load_slots_u8 || 'mixer/' || mixer_mult_u8 || growth_u8 || 'shadow/' || shadow_instrs_le16 || shadow_reps_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-genesis",
"seed_bytes": "69676e65756d2d67656e65736973",

View file

@ -3,7 +3,7 @@
"generator": 4,
"attempt": 1,
"program_id": "0xa785001687d8688a",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || 'sub/' || sub_version_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000",
"seed_bytes": "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07",

View file

@ -3,7 +3,7 @@
"generator": 4,
"attempt": 1,
"program_id": "0xa785001687d8688a",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || 'sub/' || sub_version_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000",
"seed_bytes": "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07",

View file

@ -3,7 +3,7 @@
"generator": 4,
"attempt": 1,
"program_id": "0xa785001687d8688a",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || 'sub/' || sub_version_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000",
"seed_bytes": "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07",

View file

@ -3,7 +3,7 @@
"generator": 4,
"attempt": 1,
"program_id": "0xa785001687d8688a",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || 'sub/' || sub_version_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000",
"seed_bytes": "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07",

View file

@ -3,7 +3,7 @@
"generator": 4,
"attempt": 1,
"program_id": "0xa785001687d8688a",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || 'sub/' || sub_version_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000",
"seed_bytes": "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07",

View file

@ -3,7 +3,7 @@
"generator": 4,
"attempt": 1,
"program_id": "0xa785001687d8688a",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || 'sub/' || sub_version_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000",
"seed_bytes": "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07",

View file

@ -3,7 +3,7 @@
"generator": 4,
"attempt": 1,
"program_id": "0xa785001687d8688a",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32",
"program_id_derivation": "FNV-1a 64 over 'igneum-program/' || generator_le32 || seed_words as little-endian bytes || attempt_le32 || 'sub/' || sub_version_le16",
"dataset_mode": "memory-hard",
"seed": "igneum-epoch/edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07/day/69676e65756d2d6461792ffa50000000000000",
"seed_bytes": "edc4fa844da9dc98d37e965176f6558a31560e40502ab3ae5491b21aaaabfb07",