igneum/docs/spec/04-seeds-and-vdf.md
igneum-labs f69ec95f8f Spec 0.1: lottery hash, consensus delta, finality v2 with the quorum floor, seeds and VDF, fees, open items
docs/spec/01 to 06 and the README index, alongside the existing overview. Section 1 is the normative
definition of the lottery hash with test vectors copied from the igneum-genesis-mh pack (cache fingerprint
48c4f5bf24166b2e, 96 hashes, mixer constants) and every prototype value marked with the measurement that
fixes it at gate 1. Sections 2 to 5 are the design as decided on 3 October 2026, labelled Designed. Section 6
lists 60 open items with the experiment or decision that closes each and its gate.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 17:45:08 +00:00

12 KiB

Igneum protocol specification, section 4: epoch and era seeds through the class-group VDF

Spec version 0.1, 3 October 2026. Status of this section: Measured for the VDF primitive on one machine (proto-vdf/, docs/bench-log.md entry "proto-vdf, Wesolowski VDF"); Designed for the pipeline; Open where marked. The class-group code has not been reviewed by a second cryptographer (proto-vdf/README.md, open item 1).

4.1 Why a delay

The hourly program is generated from a seed, the seed comes from a checkpoint, and the checkpoint commits to the blocks before it. The miner who finds the last block before a checkpoint can compute the program that block implies, benchmark it on its own fleet, and withhold the block if the program is bad for it. The review priced this at roughly 130 to 1 for a 30% miner; the prototype's own model gives 6 to 15 to 1 on the burned block for 10% to 40% miners (proto-vdf/README.md, grinding table, Measured by Monte Carlo over 2,000,000 epochs against the analytic model, agreement 0.03 blocks). Either way the sign is positive: with no delay, grinding pays and favours the largest miner.

A miner has about 2 s to decide whether to publish a block under a 1 block/s DAG (approximate, from the block rate). The delay only has to exceed that by a margin no hardware advantage can close. With the delay, withholding has the same expected program as publishing and only burns the block: gain 0 in every row of the grinding table.

4.2 The primitive

Wesolowski VDF (Efficient Verifiable Delay Functions, EUROCRYPT 2019) in the class group of an imaginary quadratic field with a prime discriminant derived from the input. Chia's construction (vendor/chiavdf, commit 7e62ce14, 29 Sep 2026): no trusted setup, group order unknown to everyone, a fresh discriminant per input so nothing can be precomputed. NUDUPL and NUCOMP ported from chiavdf's qfb_nudupl and qfb_nucomp with the Lehmer partial xgcd; the textbook Cohen 5.4.7 composition and plain duplication are kept as oracles and agree on 15,000 random cases (Measured, proto-vdf/README.md).

input (32 bytes)
  D  = -HashPrime(tag_D || input), 1024 bits, |D| prime, D = 1 mod 8
  x  = (2, 1, (1 - D) / 8), the generator form of Cl(D)
  y  = x^(2^T)                                   T sequential squarings
  l  = HashPrime(tag_l || x || y || T), 256 bits  Fiat-Shamir challenge
  pi = x^floor(2^T / l)
  output = SHA-256(tag_out || input || T || y)
proof = (T, y, pi)
verify: rederive D and x, recompute l, check pi^l * x^(2^T mod l) == y, recompute output

Tags (Implemented in proto-vdf/src/seed.rs for the epoch path): tag_D = "igneum-epoch-discriminant", tag_l = "igneum-vdf-challenge", tag_out = "igneum-program-seed". The era path uses "igneum-era-discriminant" and "igneum-era-seed" (Designed, not yet in code). Prime |D| kills the 2-torsion, the low-order element Wesolowski must exclude. Whether to mirror chiavdf's byte layout for HashPrime exactly, and whether the proof should carry D (the verifier otherwise pays a 17 ms average prime search), are Open (O-4.5).

Parameter Value Label
Group Class group, 1024-bit prime discriminant from the input Designed (production choice)
Fiat-Shamir prime 256 bits Designed (Chia uses 264; 2x the 128-bit level)
Proof (T, y, pi), 516 bytes with the prototype serialisation (sign byte plus fixed-width a and b) Measured. The serialisation should become chiavdf's compact encoding before any wire format is frozen (Open, O-4.5)
Proof plan 12-bit digits, at most 65,536 checkpoints (17 MB) during evaluation Implemented; proving costs 12 to 13% of evaluation single-threaded and parallelises over residue classes

Measured on the Apple M5 Max, one core, rustc 1.69.0, GMP 6.3.0, 3 October 2026 (docs/bench-log.md, proto-vdf entry):

Group Squarings/s T for 600 s T for 3,600 s Verify Proof bytes
Class group, 1024-bit D 163,000 98.0 million 588 million 4.5 ms (12.6 ms including deriving D) 516
Class group, 2048-bit D 83,500 50.1 million 301 million 8.0 ms 1,028
RSA-2048 (trusted-setup stand-in, timing only, never for production) 1,257,000 754 million 4.53 billion 1.4 ms 512

Full-length run, class 1024: T = 97,126,043, evaluation 585.4 s at 165,900 sq/s, proof 9.1 s on 12 threads (56.8 s on one), verify 4.47 ms. Determinism: the same checkpoint hash gave the same seed and identical proof bytes in two processes at T = 1,000,000; a wrong checkpoint, a flipped seed bit and T + 1 are all rejected.

4.3 The epoch seed pipeline

Designed. Epoch e is the DAA-score interval [3,600 e, 3,600 (e + 1)) (section 1.12).

  1. Seed checkpoint. C(e) is the highest-index checkpoint (section 3, C1) whose checkpoint block has DAA score at most 3,600 e - 1,200: the latest checkpoint at least 20 minutes of DAA time before the epoch starts. The checkpoint block hash is Kaspa's full header hash, which covers the nonce, as the grinding defence requires (proto-vdf/README.md: a hash that covers only the body would let a miner start the VDF while still searching nonces).
  2. Evaluation. input = hash(C(e)), T = T_epoch, run 4.2. program_seed_e is the 32-byte output; proof_e is (T, y, pi).
  3. Program. S_e = seed_words_from_bytes(program_seed_e) (section 1.3.1), program = generate_from_words(S_e) (section 1.4). The 1,200-s lead is 2x the reference evaluation time, so a core half as fast as the reference still finishes before the epoch (4.6).
  4. Header. Every header carries seed_source = hash(C(e)) for its own epoch (section 2.4). A header is valid under the lottery only if its seed_source is a block on its own selected chain at the blue score of checkpoint index i(C(e)), and its PoW verifies under the program derived from that block. The proof is not in the header: a node verifies proof_e once per epoch (4.5 ms) and caches S_e.

Determinism of step 1 is the point of the rule: which block is "the checkpoint at blue score 30 i" is a function of the header's own past, so two nodes validating the same header derive the same program, and a header mined under a reorged-away checkpoint names a block that is not on its chain and is invalid. Whether C(e) must be certified (section 3) or merely be the selected-chain block at that blue score in the header's past is Open (O-4.3): requiring certification couples mining to finality liveness (a stall longer than the lead would stop the program from being derivable), which the design document accepts ("an epoch cannot start without a valid proof") and this specification argues against, because the chain is meant to keep running on plain GHOSTDAG through a finality pause (section 3.7 item 2). The proposal: the selected-chain block at that blue score, certified or not, deep enough (1,200 DAA s plus d) that a reorg across it is a merge-depth-scale event.

4.4 The era seed pipeline

Designed (design document: "The era draw applies a one-hour delay function to the hash of all blue blocks in the day ending at the last certified checkpoint one epoch before the boundary"). Era n is the DAA-score interval [15,552,000 n, 15,552,000 (n + 1)) (section 1.12).

  1. C_era(n) is the highest-index checkpoint whose block has DAA score at most 15,552,000 n - 7,200 (2 hours of lead, 2x the 1-hour evaluation).
  2. input = Hash(chain_id || n_le64 || h_1 || h_2 || ... || h_m) where h_1..h_m are the hashes of the blue blocks in C_era(n)'s past with DAA score in (daa(C_era(n)) - 86,400, daa(C_era(n))], in ascending (blue score, hash) order, and Hash is the chain's BLAKE2b-based hash. This is a function of C_era(n)'s past, so it is as deterministic as 4.3 step 1.
  3. Run 4.2 with T = T_era = 6 x T_epoch and the era tags. E_n is the output.
  4. The era draw of section 1.13.1 consumes E_n as its only randomness (proto-vdf/README.md open item 6: check that nothing else enters the draw).

4.5 Who evaluates, who verifies

Every mining node evaluates both VDFs itself: one CPU core for 10 minutes each hour (17% of one core) and once for an hour each era, plus 17 MB of RAM if it also proves. The GPU is untouched. The proof exists for nodes that did not evaluate (light clients, syncing nodes, late starters): 516 bytes and 4.5 ms per epoch. Proofs gossip as their own message type and are also retrievable by seed_source from any peer.

There is no timelord role and no race: unlike Chia, the chain does not wait for the VDF; it uses a VDF output that was fixed 20 minutes (epoch) or 2 hours (era) earlier. "No node evaluates" means no miner is running a CPU, which means nobody is mining.

4.6 T from a reference core rate, fixed at genesis

Designed (proto-vdf/README.md, parameter recommendation). Before genesis, run vdf bench (or chiavdf's vdf_bench) on every devnet node type that will mine, take the fastest honest single-core NUDUPL rate observed as r_ref (squarings per second), and fix at genesis:

Constant Definition On the M5 Max core (r_ref = 163,000)
T_epoch 600 x r_ref 98.0 million
T_era 3,600 x r_ref 588 million

Choosing the fastest honest core, not the median, keeps the stated 10 minutes an upper bound for honest nodes and leaves the attacker margin intact. T MUST NOT be derived from on-chain timing, which is manipulable. T is a genesis constant; hardware will get faster over the years and the margin will erode slowly from 300x, which a fixed T covers for decades, and the upgrade path of section 5.7 exists if it is ever needed.

Attacker evaluator speed vs reference Epoch delay Era delay Beats the 2-s window
1x 600 s 3,600 s no, margin 300x
2x 300 s 1,800 s no, 150x
10x 60 s 360 s no, 30x
100x 6 s 36 s no, 3x
300x 2 s 12 s epoch yes, era no

Chia's and the Ethereum Foundation's VDF hardware efforts targeted single to low double-digit speedups over CPUs (approximate, from memory, proto-vdf/README.md). chiavdf's AVX-512 IFMA assembly path is faster than the prototype's 163,000 sq/s and the x86 devnet nodes will set r_ref higher than this Mac (open item 2 there).

4.7 Fallback for a node without the seed at an epoch boundary

Open (O-4.4). A node that has not finished evaluating program_seed_e when epoch e starts cannot build the program, so it cannot mine the new program or validate new blocks' PoW until it has y. It can still receive and relay. Two options:

Option Rule For Against
A (proposed by proto-vdf/README.md) The previous epoch's program stays valid for the first N blocks of epoch e, and each header names the program seed it mined under A slow node keeps mining through the boundary Two programs are valid at once for N blocks; a miner may pick the better of the two, which reintroduces a small choice the VDF was meant to remove; N is a new parameter
B (this specification's preference) No consensus fallback. The 1,200-s lead is 2x the reference evaluation; a node slower than that takes (y, pi) from any peer and verifies in 4.5 ms; seed_source in every header tells it which proof to ask for No second valid program, no new parameter; the proof is 516 bytes A node isolated from all peers and slower than 2x the reference loses up to the remainder of its own evaluation. Honest nodes evaluate at r_ref or take the proof from peers, so the case is a slow node that is also isolated

Decision at gate 3 with the devnet, where the time to first block after an epoch boundary is measured on the slowest node type.

4.8 Open items from the prototype

Carried into section 6: external review of classgroup.rs against chiavdf (O-4.1); reference core choice (O-4.2); whether C(e) must be certified and the header field (O-4.3); the fallback (O-4.4); HashPrime layout, carrying D in the proof, compact form encoding (O-4.5); reduction only when a exceeds 8 limbs as chiavdf does, a further speedup to port (O-4.6); no fuzzing of deserialize on hostile bytes beyond validity checks, no measurement on NVIDIA or AMD hosts' CPUs (O-4.7).