The root chain of phase 1 is a public proof-of-work chain on the soft3 harness: hemera as the work function, bbg as the state, mudra NSIG1 as the signature, cyber-radio as the wire, tade as the framing. It carries exactly four things a neuron can do — mine, transfer, cyberlink with stake, and be paid for the focus its stake creates. The focus economy — epochs of a fixed number of blocks, φ* over the staked graph, settlement of Δφ⁺ to staked links by recomputation on every node, the subsidy split between miners and the focus pool — is consensus from genesis and is specified in chain-economy. The pool (privacy, §11) is rule set 2; the ticket lottery and fold are the scaling rule set of chain-economy §7.3.
Owner decision 2026-10-15: "pure PoW, public chain, no features — mining, transfers, cyberlinks — on the whole soft3 harness; the four phase-1 cores run in shadow mode as indexers and activate later by scheduled fork". Superseded in part by the owner's order of 2026-10-17 ("the goal is foculus, stakes with valence, and mining — not just relaunching a network on the new stack"): ordering stays proof of work, and the cores' economy ships in consensus at genesis, no shadow mode (chain-economy.md). Spec before code: implementation starts from this page, chain-economy, chain-wire and chain-conformance.
Two chains run the same binary from two genesis files: pussy on 2026-11-05 13:37:00 UTC, bostrom at 13:22:42 UTC on the day bbg row 43 of cyber/launch is closed (the bostrom replay needs incremental commitments; pussy does not).
The shape is parano1d's — fixed small header, ASERT, heaviest chain, bounded reorg, compact bodies — with the recursion tax removed: no proof is on the critical path. Numbers quoted from parano1d are from docs.parano1d.org (v2 parameters page, read 2026-10-15) and are cited as reference points, never copied blindly.
Design rules this page obeys:
- field arithmetic never floats in anything consensus-relevant; the DAA is integer-only (§1.5);
- zheng proofs are optional and later (checkpoint proofs, §7); nox programs are not required — validation is native Rust;
- canonical encodings: every value has one valid byte form; a decoder that accepts two forms for one value is a consensus bug;
- vocabulary: file · particle · cyberlink · neuron · token · focus;
- no rung of the ladder depends on a rung above it (§9).
0. parameters
Every constant in one table. S0 is the genesis supply of the chain's native
coin, read from the genesis file (§4).
| name | value | unit | where used |
|---|---|---|---|
HEADER_BYTES |
168 | bytes | §1.1 |
BLOCK_TIME (T) |
30 | s | §1.5 |
HALF_LIFE (H) |
600 | s | §1.5 |
MTP_WINDOW |
11 | headers | §1.4 |
MAX_FUTURE_DRIFT |
120 | s | §1.4 |
POW_LIMIT |
2^236 (bits 0x1e100000) |
target | §1.3 |
GENESIS_BITS |
0x1e010000 (target 2^232) |
bits | §1.3, §4 |
MAX_BLOCK_BYTES |
262,144 | bytes, header + body | §1.6 |
MAX_BLOCK_TXS |
1,024 | transactions incl. coinbase | §1.6 |
MAX_TX_BYTES |
512 | bytes | §2 |
MIN_FEE_PER_BYTE |
1 | native units per tx byte | §2.6 |
COINBASE_MATURITY |
100 | blocks | §2.2 |
FINALITY_DEPTH |
120 | blocks (60 min) | §5.2 |
CHECKPOINT_INTERVAL |
120 | blocks | §5.3 |
CHECKPOINT_SUNSET |
525,600 | blocks (≈ 6 months) | §5.3 |
BLOCKS_PER_YEAR |
1,051,200 | blocks | §3.5 |
SUBSIDY |
floor(S0 / 105,120,000) | native units per block (1 %/yr) | §3.5 |
ORPHAN_POOL |
1,024 headers, 600 s | — | §5.4 |
NONCE_WINDOW |
16 | nonces ahead admitted to mempool | §2.5 |
MEMPOOL |
8,192 txs / 16 MiB | — | chain-wire §4 |
MAX_REORG |
FINALITY_DEPTH − 1 = 119 |
blocks | §5.2 |
POOL_DEPTH |
40 | commitment-tree levels (rule set 2, frozen at genesis) | §11.4 |
POOL_DIGEST |
64 | bytes of every wide pool digest (frozen at genesis) | §11.1 |
ANCHOR_WINDOW |
1,000 | blocks (rule set 2, frozen at genesis) | §11.4 |
MAX_SPEND_TX_BYTES |
9,985 | bytes of a kind-5 transaction (rule set 2) | §11.7 |
| economy constants | EPOCH_LENGTH 240, SETTLE_DELAY 120, MIN_LOCK 20,160, FOCUS_MAX_BPS 5,000, … |
— | chain-economy §0 |
Rationale for the two that matter most: T = 30 s is the interval parano1d measured its way to (15 → 20 → 30) for a proof-gated chain; our blocks carry no proof, so 30 s is conservative, and conservative is the point of phase 1. H = 600 s (20 blocks) is between parano1d's 180 s (reacts in six blocks, amplifies timestamp play: a 120 s future-drift shifts the target 1.6× per block) and BCH's two days (a 10× hash-rate loss would stall the chain for a day); at 600 s a 120 s drift moves the target 1.15× and a 100× hash-rate collapse recovers in about 66 minutes (§1.5).
1. block
1.1 header
A header is exactly 168 bytes, little-endian throughout, no varints, no optional fields. 168 = 3 × 56: three full hemera rate blocks plus the mandatory padded block, four permutations per hash.
| offset | size | field | type | meaning |
|---|---|---|---|---|
| 0 | 4 | version |
u32 | bits 0–15 rule set (this spec = 1); bits 16–31 miner signals (§7) |
| 4 | 8 | height |
u64 | 0 for genesis, prev.height + 1 otherwise |
| 12 | 8 | time |
u64 | unix seconds, §1.4 |
| 20 | 4 | bits |
u32 | compact target, §1.3 |
| 24 | 16 | nonce |
[u8; 16] | miner-chosen; external workers return it as 16 LE bytes |
| 40 | 32 | prev |
[u8; 32] | block id of the parent; zero for genesis |
| 72 | 32 | tx_root |
[u8; 32] | §1.7; for genesis the genesis file particle (§4) |
| 104 | 32 | state_root |
[u8; 32] | bbg root after applying this block, §3.3 |
| 136 | 32 | chain |
[u8; 32] | chain id = genesis file particle, §4.4 |
The block id is the flat hemera sponge over the 168 header bytes:
block_id = hemera(header_bytes) // 32 bytes, no domain prefix
The chain id is a header field, so a header of one chain never validates on the other and every header is self-identifying. It costs 32 bytes per block, 88 MB per year of permanent headers; accepted.
Siblings share the parent's target (§1.5 reads only the parent), so changing
a candidate's time never changes its work; miners cannot shop for an easier
target by timestamp.
1.2 proof of work
valid_pow(header) := u256_le(block_id) < target(bits)
Both sides read as 256-bit little-endian integers; equality fails. Genesis (height 0) is exempt: its id is pinned by the genesis file, not mined.
Expected hashes per block are 2^256 / (target + 1), the block's work (§5.1).
Measured 2026-10-16 on an M4 Max, one core, hemera::hash over 168 bytes
from a release build against hemera 0.4 (release/0.4 7237a23, the
phase1.toml pin), a linear nonce search through Header::id / valid_pow
on a shared machine: 90,300 H/s — about 11 µs per header (hemera 0.3 on
2026-10-15: 64,400 H/s, 15 µs; 0.4's single permutation is 2.2× faster,
the sponge over 168 bytes 1.4×), far from the µs-per-permutation figure of
steps-blocks-epochs §7, which is the permutation alone on the optimized
path. Ten cores give order 0.9 MH/s per machine; three such machines
together order 2–3 MH/s (the cybernode boxes are x86 and must be measured
separately). The genesis target (2^232, 2^24 ≈ 16.8 M expected hashes) is
sized so one such machine finds a block in about twenty seconds at that
rate, and the DAA takes over from there. A
honeycrisp or GPU hemera kernel will be one to three orders faster; the
chain does not care, ASERT does (§1.5), and §8 says what it means.
1.3 compact target
bits is Bitcoin's compact form, with one tightening: the encoding must be
canonical.
exp = bits >> 24
mant = bits & 0x007fffff
reject if bits & 0x00800000 // sign bit set
target = exp >= 3 ? mant << (8 * (exp - 3)) : mant >> (8 * (3 - exp))
Canonical encode:
size = byte_length(target) // 0 for target 0
mant = size <= 3 ? target << (8*(3-size)) : target >> (8*(size-3))
if mant & 0x00800000 { mant >>= 8; size += 1 }
bits = (size << 24) | mant
A header is invalid unless bits == encode(decode(bits)) and
decode(bits) <= POW_LIMIT and decode(bits) >= 1. Examples:
0x1e010000 ↔ 2^232 (canonical, GENESIS_BITS); 0x1d100000 ↔ 2^228
(canonical); 0x1e001000 decodes to 2^228 too and is rejected;
0x1d800000 is rejected (sign). POW_LIMIT = 2^236 is the floor: at the
measured 90 kH/s one laptop core mines a floor block in about 12 s, so the
chain never stalls below one laptop core. Vectors in chain-conformance §2.
1.4 timestamps
time > MTP(prev)whereMTPis the median of thetimeof the previousMTP_WINDOW= 11 headers (fewer near genesis: all available, genesis included); median of an even count is the lower middle;time <= now + MAX_FUTURE_DRIFTagainst the validating node's clock; a header failing only this rule is held, not rejected, and re-evaluated for up to 600 s;- genesis
timeis the genesis file's value.
1.5 difficulty adjustment — ASERT, integer only
The target of a block at height h ≥ 1 with parent P (height h − 1) is a
pure function of the genesis anchor and the parent:
Δt = P.time − genesis.time // i64 seconds
ideal = (h − 1) · T // i64 seconds
e = floor_div((Δt − ideal) · 65536, H) // i64, floor toward −∞
shifts = e >> 16 // arithmetic shift
frac = e & 0xffff // 0 ≤ frac < 65536
factor = 65536 + ((195766423245049·frac + 971821376·frac² + 5127·frac³ + 2^47) >> 48)
target = genesis_target · factor // u256 × u32 → u288 (use u512)
target = shifts < 0 ? target >> (−shifts) : target << shifts
target = target >> 16
target = clamp(target, 1, POW_LIMIT)
bits(h) = encode(target)
factor is the cubic approximation of 2^(frac/65536) in 16.16 fixed point,
error below 0.01 % (the aserti3-2d polynomial, attributed to Bitcoin Cash,
MIT). Shifts beyond 256 saturate at the clamp. Everything is integer; a
floating-point pow anywhere in this path is a consensus bug. The parent's
time, not the candidate's, enters the formula; this is what gives siblings
one target.
Behavior:
- hash rate ×k, held: the interval shortens to T/k immediately and the chain runs ahead of its ideal clock; the target halves for every H = 600 s the parent is ahead of schedule, so the lead stops growing once the target has fallen by k and the interval is back at T — a 2× step is 90 % absorbed within about 50 minutes, a 10× step within about two hours. The error signal is the absolute drift of the parent's time from its ideal time, so there is no averaging window to game and no block-count lag.
- hash rate ÷k: the interval stretches to k·T at first; the target doubles every 600 s of wall time whether or not blocks arrive, so recovery takes H·log2(k): k = 10 → 33 min, k = 100 → 66 min, with the chain producing blocks at a rising rate throughout. This is the property that makes a small chain survivable when one farm leaves.
- timestamp play: a miner setting
timeat the +120 s drift limit moves the next target by at most 2^(120/600) = 1.149; the MTP rule bounds backward play to the window median. A miner controlling many consecutive blocks can lower difficulty by at most 1.149 per block — the attack is visible (wall time disagrees with block time) and self-correcting the moment honest blocks resume, because ASERT measures absolute drift, not per-block deltas. - clock drift in the network is irrelevant beyond the two rules above; nodes need no synchronized clocks to agree on targets.
Reference points: parano1d (T 30 s, H 180 s, MTP 11, drift 120 s); Bitcoin Cash (T 600 s, H 172,800 s).
1.6 body and budgets
body = count: u32 LE ‖ tx[0] ‖ tx[1] ‖ … ‖ tx[count−1]
tx[0]is the coinbase (§2.2) and no other tx is;count ≤ MAX_BLOCK_TXS;168 + len(body) ≤ MAX_BLOCK_BYTES;- each
txis self-delimiting (fixed size per kind, §2) andlen(tx) ≤ MAX_TX_BYTES; - the same txid never appears twice in a block.
Rationale: 256 KiB and 1,024 txs is 40 tx/s sustained, three orders of magnitude above bostrom's historical rate (2.9 M links in five years ≈ 0.02/s) and small enough that a block crosses three continents in under a second over QUIC. parano1d's terminal cap is 1.1 MB because it carries proofs; ours carries none.
1.7 transaction root
A hemera Merkle tree over the transactions in body order, domain-separated, no duplication of odd nodes:
leaf_i = hemera("soft3/chain/leaf/v1\0" ‖ tx_bytes_i)
level = [leaf_0 … leaf_{n−1}]
while len(level) > 1:
next = []
for pairs (L, R) in level: next.push(hemera("soft3/chain/node/v1\0" ‖ L ‖ R))
if len(level) odd: next.push(last(level)) // promoted unchanged
level = next
tx_root = level[0]
Promoting the odd node instead of duplicating it removes the duplicate-tx
malleability of Bitcoin's construction. A coinbase-only block has
tx_root = leaf_0.
2. transactions
2.1 envelope
tx = version: u8 (= 1) ‖ kind: u8 ‖ body ‖ sig
| kind | name | body bytes | sig | total bytes |
|---|---|---|---|---|
| 0 | coinbase | 80 | none | 82 |
| 1 | transfer | 120 | NSIG1 (102) | 224 |
| 2 | cyberlink | 153 | NSIG1 (102) | 257 |
| 3 | claim | 36 | NSIG1 (102) | 140 |
| 6 | unlock | 120 | NSIG1 (102) | 224 |
| 7 | payout | 144 | NSIG1 (102) | 248 |
Kinds 6 and 7 are the economy's (chain-economy §3.4–§3.5). Any other
version or kind is invalid under rule set 1; kinds 4 (deposit) and 5
(spend) are the pool's, formats frozen at genesis, valid only from rule set
2 (§11.7); kinds 8–10 are reserved (chain-economy §3.5). Fixed sizes: a
decoder knows the length from the second byte; trailing or missing bytes are
a decode error.
txid = hemera("soft3/chain/txid/v1\0" ‖ chain ‖ tx_bytes)
statement = hemera("soft3/chain/sign/v1\0" ‖ chain ‖ tx_bytes_without_sig)
chain is the 32-byte chain id. Binding it into both hashes gives
cross-chain replay protection for free: a pussy transfer is not a valid
bostrom transfer even for the same key and nonce.
2.2 coinbase (kind 0)
height: u64 ‖ to: neuron[32] ‖ amount: u64 ‖ extra: [u8; 32]
heightequals the block height (prevents identical coinbases in two blocks, hence identical txids);amount == SUBSIDY − cut(h) + Σ fees of the block's other txs, exactly, wherecut(h)is the focus pool's share of the subsidy (chain-economy §6.1–§6.2, credited to the pool in the same step); less is invalid too (no burning by omission — supply must be a pure function of height, §3.5);extrais free: pool extranonce, a commitment, zeros;- the output is credited to
balances[H(to ‖ τ_native)]and is spendable only from heightheight + COINBASE_MATURITY, so a reorg never invalidates spends of a subsidy that was itself reorged out.
2.3 transfer (kind 1)
from: neuron[32] ‖ nonce: u64 ‖ token: [u8;32] ‖ amount: u64 ‖ to: [u8;32] ‖ fee: u64
Moves amount of token from from to to and fee of the native coin
from from to the block's coinbase. to is any 32-byte card id (a neuron
id, or a particle — value can be parked on a particle). amount may be 0
(a fee-only tx is valid, useful for claiming a nonce slot). token is a
token id (§3.1).
2.4 cyberlink (kind 2)
from: neuron[32] ‖ nonce: u64 ‖ token: [u8;32] ‖ amount: u64 ‖ p: particle[32] ‖ q: particle[32] ‖ valence: i8 ‖ fee: u64
The cyberlink (p, q, token, amount, valence) per
cybergraph/specs/cyberlink.md, authored
by neuron from. p ≠ q; valence ∈ {−1, 0, +1} (any other byte is
invalid). amount > 0 locks amount of the native coin (no other token)
as stake on the position card(from, p, q) with this valence: the stake is
the balance at stake_key(card), unlocked by kind 6 after MIN_LOCK, and
earns at epoch settlement when it adds weight that raises syntropy — the
whole rule is chain-economy §3–§5. amount = 0 is a bare assertion,
topology only. Every link calls bbg's insert with amount = 0 (the axon
lists); stake accounting is the chain's (§3.2).
Why two neuron-signed kinds and not one: the two actions have different state footprints (a transfer touches two balances; a link touches two particles, two axon lists, an axon-particle and a balance) and different audiences (wallets vs cyb). One tx per action keeps each a fixed-size record that is trivial to index and impossible to mis-parse.
2.5 nonces and replay
Every neuron record carries nonce: u64 (§3.2). A tx of kinds 1–3 is valid
only if tx.nonce == neurons[from].nonce; applying it increments the nonce.
Together with the chain id in the statement this closes replay within and
across chains. Mempool admission accepts nonces in
[current, current + NONCE_WINDOW) and orders them; block validation
accepts only the exact current nonce, in body order.
2.6 fees
fee ≥ len(tx_bytes) · MIN_FEE_PER_BYTE in the native coin, paid to the
block's miner through the coinbase amount. Nothing is burned. At 1 unit per
byte a transfer costs 224 BOOT (bostrom; BOOT has no decimals, supply ≈
1.15 × 10^15) or 224 PUSSY (pussy, supply ≈ 1.15 × 10^18): a spam floor, not
a market. Fee markets, growth fees and burns are cores-era rules (§7).
2.7 signatures — mudra NSIG1
sig is the 102-byte NSIG1 envelope of
mudra/specs/neuron-auth.md:
"NSIG1" ‖ pubkey[33] ‖ ecdsa[64], verified by
mudra::neuron::verify_statement(subject, statement, sig) with
subject = tx.from (kinds 1, 2) or subject = claim::neuron_of(pubkey)
(kind 3) and statement as in §2.1. The envelope already requires
neuron_of(pubkey) == subject, so the neuron id is the hash of the key and
no key registry exists. The curve is secp256k1; phase-1 signatures are
classical, stated plainly (§8).
2.8 the legacy bridge — implicit, with one explicit case
claim::neuron_of(pubkey) = hemera(compressed pubkey) is both mudra's native
id for a legacy key and the id genesis uses for every snapshot account whose
pubkey is known (pubkeys.csv lists all 61,675 bostrom accounts; the ones
that ever signed a transaction carry a key; §4). Such a holder signs transfers with the same key and the same
mnemonic they used on bostrom or pussy — the bridge is implicit; no claim tx
exists for them. The ADR-036 claim of
mudra/specs/bridge.md (binding a legacy address
to a different native neuron) is not a chain transaction in phase 1: a holder
who wants a new neuron transfers to it.
The explicit case: accounts whose pubkey never appeared on the old chain (8,390 wallets that never sent a transaction; address-only). Genesis parks their balances under a dormant owner id
legacy_owner(hrp, account_id) = hemera("soft3/chain/legacy/v1\0" ‖ hrp ‖ account_id[20])
that no key controls, and kind 3 moves them:
claim (kind 3): account_id: [u8;20] ‖ nonce: u64 ‖ fee: u64
valid iff ripemd160(sha256(sig.pubkey)) == account_id
(mudra cosmos::account_id), the dormant owner holds at least fee of the
native coin, and nonce == neurons[neuron_of(pubkey)].nonce. Effect: every
balance of legacy_owner(hrp, account_id) (all tokens) moves to
neuron_of(pubkey); fee to the miner. The hrp is the chain's (§4.1).
3. state
3.1 identities
- particle: 32 bytes,
hemera(bytes)of a file per thefilecrate (row 19 of cyber/launch: every crate computes this today); the chain never distinguishes a content particle from any other 32-byte card; - neuron: 32 bytes,
neuron_id::NeuronId; for legacy keyshemera(compressed pubkey); - token: 32 bytes,
token(denom) = hemera(denom_bytes)—hemera("boot"),hemera("pussy"),hemera("hydrogen"),hemera("tocyb"), …; the native coin of a chain istoken(genesis.denom); - axon-particle:
hemera(p ‖ q); - balance key:
hemera(owner ‖ token)(bbgbalance_key).
3.2 bbg dimensions used
The state is one bbg::BbgState; the chain writes seven of its dimensions
and leaves the rest empty but committed:
| dimension | written by | content |
|---|---|---|
| particles | nobody | bbg's insert is called with amount = 0 for every link, so no particle record is written; φ* is published by digest (chain-economy §5.6) |
| cards | cyberlink with amount > 0, kinds 6 and 7 |
one CardRecord { owner, particle, author, valence, since } per position (bbg dimension version 4, chain-economy §3.2) |
| time | settlement blocks | time[settle(E)] = hemera(D_EPOCH ‖ epoch record) (chain-economy §5.6) |
| axons_out, axons_in | cyberlink | axon(p,q) appended once per (p,q) |
| neurons | all | NeuronRecord { focus, karma, stake, nonce }; phase 1 writes nonce only, the other three stay 0 |
| coins | coinbase, genesis | CoinRecord { total_supply } per token |
| balances | all | hemera(owner ‖ token) → u64, plus the raw keys stake_key(card) and focus_key(τ_native) (chain-economy §3.1) |
| locations, files, signals, intents, A(x), N(x) | nobody | empty; their commitments are constants of the empty dimension |
Change requested of bbg (rung 3, one field): NeuronRecord.nonce: u64, with
DIMENSION_VERSION bumped to 3 — landed (bbg dimension version 3,
2026-10-16). The alternative — storing nonces as a
pseudo-token balance — avoids the change and leaves a permanent hack in the
state; rejected.
Balances live inside the root. Today the native node keeps pay balances in
NativeNode.balances outside bbg; under this spec that map is deleted and
every balance, including the miner's and the dormant legacy owners', is an
entry of the balances dimension and therefore under state_root. That is
the fix the launch page asks for.
No nullifiers, no private commitments: phase 1 is an account model with
nonces; A(x) and N(x) stay empty until the pool activates (§11), and the
pool's turnstile keys T(τ) in the balances dimension (§11.5) stay absent.
3.3 state root per block
state_root = bbg root (BbgState::compute_root, the 14-leaf hemera
compression over the 11 dimension commitments, A, N and stats) after the
block's transactions are applied in order, coinbase first. The root is
refreshed once per block, never per transaction.
Cost: every bbg dimension leaf is a keyed-trie root (bbg dimension
version 3, launch row 43): a block costs O(changes · log n) hemera
compressions — measured 0.4–0.9 ms per link from 10 K to 3 M links, flat —
and there is no dimension size cap, so bostrom's genesis commits (bbg
audit/commit-cost-2026-10-15.md, soft3
audit/genesis-dimension-v3-2026-10-16.md). Look proofs over trie leaves
need zheng to open trie paths; nothing in phase 1 needs them.
3.4 transition and conservation
For a block B at height h on state S:
S' = S
apply coinbase: balances[H(to ‖ τ)] += amount ; balances[focus_key(τ)] += cut(h) ; coins[τ].total_supply += SUBSIDY
if h == settle(E): settle epoch E (chain-economy §5)
for tx in body[1..]:
check nonce, signature, balances (every debit ≥ 0 after), kind rules
apply; neurons[from].nonce += 1
assert state_root(B) == root(S')
Invariant checked by the node after every block and exposed in /status:
Σ balances[·, τ_native] (incl. stakes, focus pool and dormant) == S0 + h · SUBSIDY
Σ balances[·, τ] == genesis supply of τ for every other token
Fees move, subsidy mints, nothing burns; supply is a function of height
alone. Conservation is checked by the tok crate's conservation helpers
(plumb), which own the arithmetic; the chain supplies the deltas.
3.5 subsidy — the stakeless onramp, bootstrap phase
The subsidy is the envelope of rewards.md §8 ("the subsidy envelope precedes the lottery it will carry"): a per-block amount paid for a proof meeting a difficulty target, karma-blind and stake-blind, the permissionless door. In phase 1 the proof is a hemera header hash — synthetic work, tolerable "exactly once: at bootstrap the subsidy's product is distribution, not attribution". The settlement ticket of §7–§8 replaces the hash as the proof by scheduled fork (§7); the envelope does not change.
SUBSIDY = floor(S0 / 105,120,000) // = S0 · 1 % / BLOCKS_PER_YEAR
constant per block, 1 % of genesis supply per year, no halving. From
genesis the subsidy is split each epoch between the miner and the focus
pool by θ^½ of the active stake, at most half to the pool
(chain-economy §6); the total minted per block is unchanged. For bostrom
(S0 ≈ 1.15 × 10^15 BOOT) about 1.1 × 10^7 BOOT per block; for pussy
(S0 ≈ 1.15 × 10^18 PUSSY) about 1.1 × 10^10 PUSSY per block. Rationale for
constant-and-small: the only purpose is to pay the security floor of a canary
chain and to put native coin in the hands of newcomers who mine; a halving
schedule is a monetary policy decision the cores' activation makes with real
data (rewards.md §10 derives the floor from attack economics; nothing is
known at genesis). The number is an owner decision and is listed open in §10
with this default.
3.6 retention
- headers: permanent on every node (168 B × 1,051,200 per year = 177 MB/yr);
- bodies: phase-1 nodes are archival — every body is kept, because genesis
replay and the shadow indexers read the whole stream; worst case
256 KiB × 2,880 blocks/day = 720 MB/day, typical a few MB/day; a pruning
mode (
--prune, keep bodies abovetip − FINALITY_DEPTHplus a bbg checkpoint) is permitted for non-archival nodes and is not a consensus rule; - state: one bbg database per chain under
$home/<chain>/bbg; recovery replays committed operations and verifies stored roots before readiness, as native-node.md already requires.
4. genesis
4.1 file
A genesis is one file: a tade stream, dialect urn:cyberia:chain-genesis:1,
first frame (*, k) with that URN, then exactly one p frame, then b
frames, then l frames, in the canonical order below, nothing else. Its
particle is the chain id.
| frame | name | data | size |
|---|---|---|---|
(~, p) |
params | version: u32 (=1) ‖ name ‖ hrp ‖ denom ‖ time: u64 ‖ bits: u32 ‖ subsidy: u64 ‖ checkpoint_key: [u8;33] ‖ checkpoint_sunset: u64 ‖ pool: [u8;74] where each string is len: u8 ‖ utf8 and pool is the frozen 74-byte pool record of §11.10 |
variable |
($, b) |
balance | owner: [u8;32] ‖ token: [u8;32] ‖ amount: u64 |
72 |
(#, l) |
link | neuron: [u8;32] ‖ p: [u8;32] ‖ q: [u8;32] ‖ height: u64 |
104 |
A frame is 0x1F ‖ sigil ‖ render ‖ LEB128(len) ‖ data as the tade crate
encodes it (Chunk::encode); the pair column names (sigil, render). A
reader rejects any other pair, any other order, a second p, and trailing
bytes — the file is canonical or it is not a genesis.
Canonical order: b frames sorted by (owner, token) bytewise, no
duplicates, amount > 0; l frames in the order of the source
(cyberlinks_indexed.csv.gz is in chain order: ascending old height, then
the tx order inside the block), duplicates kept (the old chain counted
re-links); the height-0 links of §4.2 (passports) precede the source links.
subsidy is written explicitly (computed by the pipeline from §3.5) so a
reader needs no arithmetic to know it. checkpoint_key all-zero means no
checkpoints (§5.3) and is what the pipeline writes until the foundation key
is set.
Applying genesis: every b becomes a balance entry and a coins total; every
l runs bbg insert for one link with token = τ_native, amount = 0,
valence = 0, authored by neuron at height (the old height is carried as
data in the link record for indexers; the chain's own height of every genesis
link is 0); every distinct owner and link author gets a neuron record with
nonce = 0. The resulting root is state_root of block 0. Every l frame
also carries a genesis weight for φ*, computed by every node from the file
alone and stored nowhere (chain-economy §4.1, §8).
4.2 derivation from the burial
Inputs, pinned by CID and sha256 in bostrom/snapshot/manifest.json and
space-pussy/snapshot/manifest.json:
| input | columns | use |
|---|---|---|
balances.csv |
address, denom, amount | liquid balances, every denom |
holdings.jsonl |
per account: liquid, delegated, undelegating, per-pool decomposition | delegated and undelegating amounts return to the account; LP positions dissolve into their underlying tokens at halt reserves |
pubkeys.csv |
address, pubkey_type, pubkey_base64 | owner = neuron_of(pubkey) for secp256k1 keys; address-only accounts → legacy_owner(hrp, account_id) |
cyberlinks_indexed.csv.gz |
particle_from, particle_to, neuron, height, timestamp, transaction_hash | l frames; neuron resolved as above |
passports.jsonl, passports_by_owner.json |
nickname, owner | see passports below |
supply.json |
total per denom | the check: Σ b per token equals it after decomposition |
Rules:
- denominations: all carried, each as its own token id;
boot,hydrogen,milliampere,millivolt,tocybon bostrom;pussy,liquidpussyand the rest on pussy; IBC and factory denoms carried under their full denom string as the token name; - owners:
secp256k1pubkeys →neuron_of(the pipeline recomputes the address from the key and refuses a mismatch); the module/contract accounts and address-only accounts →legacy_owner; multisig and non-secp256k1 key types →legacy_owner(claimable later by a fork rule, not by kind 3).account_idis the bech32 payload: 20 bytes for a key account, 32 for a contract (the passport contract islegacy_owner(hrp, 32-byte id)); - staking pools: the delegated and undelegating amounts returned to accounts
leave
bonded_tokens_pool/not_bonded_tokens_pool; the rounding dust the pools still hold stays onbonded_tokens_poolunderlegacy_owner, so Σ of the native coin is exactly the bank supply at halt; - pools: each LP position dissolves into the pool's reserve denoms,
floor(lp · reserve / pool_coin_supply)per denom; the reserve account keeps the rounding dust; pool coins are not carried; a drained pool (no reserve left) dissolves to nothing; - u64: a
bframe and acoinstotal carry a u64; a denom with any balance or a total supply above 2^64 − 1 (18-decimal IBC vouchers) is not carried at all and is listed in the genesis report; the native coin must never be among them; - stake: delegated and undelegating balances are liquid at genesis; no coin is locked without its holder's signature. The launch-page decision "stake at genesis is bonded uniformly from the snapshot" is met on the rank axis instead: every genesis link carries a passive genesis weight, its author's genesis balance spread over the author's links (chain-economy §4.1, §8), which moves φ* and earns nothing;
- particles: the old
particle_from/particle_toare IPFS CIDs; the pipeline re-addresses each per cyber/launch row 20 —hemera(bytes)when the bytes are in the burial blockstore, black holehemera(cid_string)when not (2.37 % of bostrom particles) — and emits one naming linkhemera(cid_string) → particleper re-addressed CID, authored by the genesis neuron[0u8; 32]at height 0, so the old address stays resolvable in the graph. The first genesis fetches no bytes: every CID is the black holehemera(cid_string)and, the two identities coinciding, no naming link is emitted; the content particle sparks when bytes surface (file crate, row 20); - passports: each of the 47,837 bostrom passports becomes one genesis link
owner_neuron → hemera("passport:" ‖ nickname), height 0; the 8.97 T BOOT held by the passport contract stays underlegacy_owner("bostrom", contract_account_id), dormant and unclaimable by kind 3 (no key derives that account id), until the owner decides — the open item on the launch page is untouched here; - TOCYB: carried as the token
hemera("tocyb")unchanged; the TOCYB × 666 → CYB rule belongs to $CYB genesis (phase 3) and is not executed by the phase-1 chain; - pussy supply:
manifest.jsonrecordstotal_post_swap_pussy(1,152,075,800,167,936,256) with a hypothetical minted-for-swap amount priced from pool reserves; no swap is executed at genesis (every denom is carried as its own token instead), so S0 for pussy is the bank supply at halt, 1,099,389,810,279,114,036, andSUBSIDY = 10,458,426,657.
The pipeline is a deterministic program — soft3 genesis build in
soft3/crate/src/genesis/ (specs/genesis.md; chain/genesis.rs consumes
its output through soft3::genesis::state::load) — whose output file
particle is published on the launch page and in the binary; two independent
runs must produce byte-identical files (chain-conformance §10).
4.3 block 0
version = 1, height = 0, time = genesis.time, bits = GENESIS_BITS, nonce = 0,
prev = 0, tx_root = chain, state_root = root(apply(genesis)), chain = particle(genesis file)
No PoW check at height 0. block_id(0) is pinned in the binary beside the
chain id; a node whose computed genesis root differs refuses to start.
Genesis times (cyber/launch decisions 2026-09-18): pussy 2026-11-05T13:37:00Z = 1793885820; bostrom 2026-11-05T13:22:42Z = 1793884962, or the matching second of the day row 43 closes.
4.4 two chains, one binary
soft3 node --chain pussy | bostrom [--genesis path]. The binary embeds the
two chain ids and genesis block ids; --genesis is for rehearsal nets
(pussy-rc) and must match the embedded id for the named chain. All
protocol constants (§0) are identical on both chains; only the genesis file
differs. The chaosnet spacepussy-test keeps its current engine and port
and is not a chain of this spec.
5. consensus
5.1 fork choice — heaviest chain
work(header) = floor(2^256 / (target(bits) + 1)) // u256
chainwork(B) = chainwork(prev) + work(B)
The canonical tip is the valid block with the greatest chainwork. Ties
keep the first-seen tip (Bitcoin's rule); a deterministic hash tie-break
would hand a predictable advantage to whoever can grind for it.
5.2 reorg limit
A node never reorganizes more than MAX_REORG = 119 blocks: a competing
chain whose fork point is at or below tip − FINALITY_DEPTH is rejected
outright, however much work it carries, and logged. After one hour a block
is final for every node that saw it in time. The cost is honest: a partition
longer than an hour produces two chains that will not rejoin automatically;
the operator of the minority side resyncs from a checkpoint. For a chain run
on three known machines plus volunteers this trade is right; it bounds the
damage of a rented-hash-rate rewrite to one hour of history (§8).
5.3 foundation checkpoints, with a sunset
For the first months the chain's hash rate will be small enough that a single GPU farm can out-mine it. The explicit, temporary mitigation is a checkpoint signer:
genesis.checkpoint_keyis one secp256k1 public key held by the foundation;- a checkpoint is
height: u64 ‖ block_id: [u8;32] ‖ sig: NSIG1withstatement = hemera("soft3/chain/checkpoint/v1\0" ‖ chain ‖ height ‖ block_id)andsubject = neuron_of(checkpoint_key); - the signer publishes one checkpoint per
CHECKPOINT_INTERVALat heights that are multiples of 120 and at leastFINALITY_DEPTHbelow its own tip, on thecheckpointsgossip topic and at/checkpoints; - a node with checkpoints enabled (default on) treats a checkpointed block as final: it rejects any chain not containing it and will not reorg below it. Checkpoints never make an invalid block valid and never move the tip forward — they only forbid alternatives;
- sunset: a node ignores every checkpoint with
height > CHECKPOINT_SUNSET(525,600 ≈ 6 months after genesis), and the operator may disable them earlier (--no-checkpoints). The key cannot be rotated without a release; losing it simply ends checkpointing early.
This is centralization, named as such, bounded in power (cannot forge, cannot censor, cannot rewrite — only veto deep reorgs) and bounded in time.
5.4 orphans and ordering
Headers whose prev is unknown go to a bounded pool (ORPHAN_POOL: 1,024
headers, evicted after 600 s or by PoW-weight when full) and trigger a
get-headers from the sender (chain-wire §3). Bodies are requested only for
headers that are on a chain with more work than the local tip or within
FINALITY_DEPTH of it. Every rejected block id is remembered (bounded set)
so it is never re-validated.
5.5 validation order
Cheap before expensive, and nothing stateful before PoW:
- syntax: 168 bytes;
version & 0xffff == 1;chainmatches;bitscanonical and within limits; - parent:
prevknown and valid,height == prev.height + 1; - time: MTP rule, future-drift rule;
- target:
bits == expected bits from ASERT(prev); - proof of work:
block_id < target; the header is now accepted and relayed; - body: size and count budgets,
tx_rootrecomputed and equal, coinbase position and height; - transactions in order: decode, signature (
verify_statement), nonce, balances, kind rules; coinbase amount equals subsidy plus fees; - state: apply on a copy of the parent state,
state_rootequal; commit.
A block failing 6–8 marks the header invalid (and every descendant); failures at 1–5 never reach disk.
6. network
Node-to-node transport, gossip topics, header-first sync, discovery through the graph, anti-spam, eclipse basics and the HTTP surface are specified in chain-wire.md. The consensus rules above do not depend on anything there.
7. upgrades and shadow mode
7.1 rule sets by height
version & 0xffff names the rule set a block claims to follow. A node holds
an activation table
ACTIVATIONS: [(rule_set: u16, height: u64)] // rule set 1 at height 0
compiled into the release and printed in /status. A block at height h is
valid only under the highest rule set whose activation height is ≤ h, and
its version & 0xffff must equal that rule set. A node that does not know
the active rule set (its table ends earlier) stops accepting blocks at that
height and says so in /status — it does not follow a chain it cannot
validate. A scheduled fork is therefore a software release carrying the
table, announced on cyber/launch at least 40,320 blocks (two weeks) before
the height. Nothing on chain votes; this is the flag-day model, chosen
because the chain has no governance object and because every node in the
first months is run by someone reading the launch page.
version >> 16 are miner signal bits: a miner may set them to advertise
readiness for a rule set; they are informational, never consensus.
7.2 what later rule sets bring
Since 2026-10-17 rule set 1 carries the focus economy (chain-economy.md): epochs, φ*, staked links with valence, settlement by recomputation, the subsidy split. Rule set 2 is the pool (§11). The ticket lottery and fold (chain-economy §7.3) and the reports rule set (chain-economy §7.4) follow by scheduled fork. The list below is what the chain leaves room for:
- the pool (§11): kinds 4 and 5, the turnstile, the commitment tree and the block proof, with every format frozen at genesis — rule set 2 brings only its verifying keys;
- further tx kinds ≥ 8 (settlement ticket 8, fold step 9, report 10; kinds 6 unlock and 7 payout are rule set 1) — kinds are a u8;
- the coinbase
extrafield as the commitment slot for the fold accumulator when it becomes consensus (the epoch beacon is the boundary block id, chain-economy §2.3); - the subsidy envelope re-targeted from the header hash to the settlement
ticket (rewards.md §8), with the same
SUBSIDYunless the activation table says otherwise; - bbg dimensions today left empty (signals, A, N) start to be written; the root construction is unchanged, so rule-set-1 roots remain verifiable.
7.3 shadow indexers
Since 2026-10-17 foculus's epoch clock and settlement are consensus (chain-economy.md) and are no longer indexers; what remains in shadow mode is privacy (until rule set 2) and the ticket/fold path (until its rule set). They run on every full node as indexers: processes (or threads) that read the block stream after validation and publish derived results nobody is obliged to believe. The chain gives them exactly one interface, the finalized block stream:
GET /v2/history?after=POSITION&limit=N(existing contract) extended to carry the block id, height and state root of every operation; and- the local event bus of the node process (
chain::Event::Block { header, body, state_root }, emitted once a block isFINALITY_DEPTHdeep — shadow indexers never see a reorg).
What each reads and publishes:
| indexer | reads | publishes (shadow topic / HTTP) |
|---|---|---|
| settlement tickets | the graph, the beacon block_id(boundary(E)) |
sampled tickets and their Shapley estimate compared against the consensus settlement (chain-economy §7.3); /shadow/settlement |
| fold | shadow tickets | cluster accumulators and decider outputs; /shadow/fold |
| privacy | the tx stream | P1–P3 leakage reports on the public wire, stealth-address trial balances; /shadow/privacy |
Shadow topics are gossip topics named shadow/<core> (chain-wire §2), not
consensus, rate-limited like transactions. The point of shadow mode is that
by the activation height each core has months of outputs that the owner, the
red team and the community have compared across nodes; an indexer whose
outputs disagree between nodes is not ready to be consensus.
7.4 optional checkpoint proofs
Later, a zheng proof of a bbg state transition over a block range may be
attached to a checkpoint (bbg's Checkpoint { root, acc, height } already
has the slot). Nothing in phase 1 depends on it; a node without the proof
verifier runs identically.
This section is superseded as the target by
the proven present: every block is a proven
transition whose proof verifies its parents' proofs, proved first and mined
second; the canary blocks of rule set 1 are proven after the fact, and a rule
set before CHECKPOINT_SUNSET makes the block proof a validity condition. Its
one rule binds every later rule set: nothing activates that the block relation
cannot express. §2.7 stands as written (owner, 2026-10-17): pussy and bostrom
carry NSIG1 until their balances are claimed, and their block proofs prove
those signatures; the CYB chain is separate and has no ECDSA from genesis.
8. security model
What is and is not protected at launch, stated plainly.
| property | status at launch |
|---|---|
| double spend inside the canonical chain | protected (nonce + balance rules, §2.5, §3.4) |
| forged transfer | protected by secp256k1 ECDSA (classical; no post-quantum claim) |
| cross-chain / cross-net replay | protected (chain id in statement) |
| supply inflation beyond schedule | protected (coinbase exactness, conservation check) |
| 51 % rewrite of recent history | not protected by work alone — hash rate at launch is tiny; bounded to one hour by FINALITY_DEPTH and, for six months, by checkpoints |
| censorship by a majority miner | not protected (no protocol can); visible in /status (miner distribution) |
| long-range attack from genesis | protected by the pinned genesis id, the reorg limit and checkpoints |
| eclipse | basics only (chain-wire §5); a determined adversary controlling a node's peers can feed it a lighter chain until it reconnects |
| timestamp manipulation | bounded to 1.149× per attacker block (§1.5) |
| spam | fee floor, size caps, per-peer limits; no fee market, so sustained spam at 1 unit/byte is cheap for a whale and fills blocks — accepted on a canary |
| mempool / network DoS | bounded pools and rate limits (chain-wire §4–5); not load-tested at launch |
| key loss | no recovery; a neuron is its key |
| privacy | none on the chain: author, amounts and links are public. P1–P3 are shadow until rule set 2 switches on the pool (§11), whose formats genesis already fixes |
| settlement / ranking correctness | consensus: every full node recomputes φ* and the settlement of every epoch, and the epoch record is under state_root (chain-economy §5.6); a node that disagrees halts at the settlement block |
The work function: hemera is a Goldilocks Poseidon2 variant, GPU-friendly (quantus precedent, goldilocks-parano1d §P2). There is no rental market for hemera hash power, which removes the cheapest 51 % path (NiceHash-style) and leaves the expensive one (a GPU farm pointed at the chain). The measured CPU rate (90 kH/s per core, §1.2) makes the gap wide: a single GPU running a competent hemera kernel is expected to out-hash every CPU miner on the network at launch, so the first GPU is the majority miner until a second arrives. Against that the chain has the reorg limit and the checkpoints, nothing else; that is the honest security budget of a 1 %-per-year subsidy on a canary, and the reason both mitigations exist.
Threats and mitigations, in one list:
| threat | mitigation | residual |
|---|---|---|
| hash-rate rental / farm rewrite | FINALITY_DEPTH, checkpoints to sunset |
one hour of reorgable history |
| farm joins then leaves (difficulty cliff) | ASERT with H = 600 s | ≤ 66 min of slow blocks after a 100× drop |
| timestamp grinding | MTP(11), +120 s drift, parent-time ASERT | 1.149× per block |
| header spam | PoW checked before relay or storage | an attacker pays real work per header |
| tx spam | fee floor, 512 B cap, nonce window, per-peer rate | fills blocks at 1 unit/byte |
| block-size DoS | 256 KiB / 1,024 txs | none beyond cost |
| orphan-pool exhaustion | 1,024 entries, PoW-weight eviction | none |
| eclipse / partition | 8 outbound to distinct networks, hard-coded bootstrap, anchors | partition > 1 h needs an operator |
| checkpoint key compromise | key can only veto; sunset; operator switch | a compromised key can halt a node's progress on a fork until disabled |
| genesis disagreement | pinned chain id and block 0 id; byte-identical pipeline | none if the pipeline is deterministic (conformance §6) |
| state-root cost (bostrom) | launch bostrom only after bbg row 43 | pussy launches first |
9. node architecture
9.1 crate and placement
The chain is soft3 node --chain <name> in soft3/crate — the existing
node crate (rung 7 of the ladder: radio · foculus · tade), reusing node.rs
and the HTTP adapter, with a new chain module tree. Reasons: the ladder
places the network and its consensus at soft3, below cyb and cyber and above
cybergraph/bbg; the HTTP contract cyb and true-cyber consume already lives
here; and a separate chain crate would either sit on the same rung (no
gain) or pull radio below cybergraph (a violation). Dependencies point down
only: hemera (commit), bbg and cybergraph (graph), mudra and
neuron-id (language rung, identity), tok (conservation arithmetic),
tru (φ* and its gradient, chain-economy §4–§5), tade (framing),
radio (transport), foculus only for the shadow indexer (feature
shadow). cyb and cyber consume soft3; nothing in soft3 names
them.
soft3/crate/src/chain/
mod.rs Chain: open(home, name) → tip, state, mempool; Event bus
params.rs §0 constants, ACTIVATIONS, embedded chain ids and genesis ids
header.rs Header encode/decode (168 B), block_id, bits codec (§1.1–1.3)
pow.rs valid_pow, work, chainwork (u256 helpers, no floats)
daa.rs ASERT (§1.5), MTP
tx.rs kinds 0–3: encode/decode, txid, statement, verify (mudra)
pool/ §11: wide digest, record, rho, commitment, nullifier, tree node and tree, turnstile key, SPEND encoding, block statement, tags
tree.rs tx_root (§1.7)
genesis.rs tade genesis reader, apply, block 0, pipeline check
state.rs apply block on bbg (§3.4), conservation, nonce, maturity
store.rs headers (permanent), bodies, chainwork index, rejected set, bbg handle
select.rs fork choice, reorg limit, checkpoints (§5)
mempool.rs admission, nonce ordering, fee floor, eviction (chain-wire §4)
miner.rs template, nonce loop (CPU; pool template out), coinbase extra
wire/ radio: topics, sync, discovery, limits (chain-wire)
api.rs HTTP routes (chain-wire §6) on the existing http.rs server
economy/ chain-economy: epochs and snapshots, genesis weights, settlement over tru, emission split
shadow/ feature `shadow`: ticket/fold/privacy indexers over Event
Each file stays under 500 lines (quality doctrine); wire/ and shadow/ are
directories for that reason.
9.2 the three machines
Per cybernode/: cyberproxy (public entry, 8 GB), deimos (archive, 64 GB), jupiter
(RPC, 64 GB). Each runs one unit per chain:
| machine | unit | role | HTTP | QUIC |
|---|---|---|---|---|
| cyberproxy | soft3-pussy.service, soft3-bostrom.service |
public entry behind nginx (cyb.ai/pussy, cyb.ai/bostrom), full node, no mining, checkpoint relay |
127.0.0.1:7781 / :7782 | 0.0.0.0:7791 / :7792 |
| deimos | same units | archive node, miner (CPU; the GTX 1080 when a GPU kernel exists), checkpoint signer (key on this box only) | 127.0.0.1:7781 / :7782 | 0.0.0.0:7791 / :7792 |
| jupiter | same units | full node, miner, second bootstrap | 127.0.0.1:7781 / :7782 | 0.0.0.0:7791 / :7792 |
Homes /home/cyber/<chain>/ (bbg/, blocks/, genesis.tade, node key).
The three endpoint ids are the hard-coded bootstrap set; each node also
publishes its antenna and socket as cyberlinks from its own neuron
(chain-wire §5) so a fourth node can find them through the graph. The
chaosnet unit spacepussy-test.service on :7780 is untouched. Alerts: tip
age > 10 min, peer count < 2, conservation check failed, checkpoint older
than 2 h — on mimas like everything else.
10. open questions and defaults
Decisions this page could not settle alone, each with the default the implementation uses until the owner says otherwise.
Owner decisions 2026-10-15 (recorded by the kernel implementation,
crate/src/chain/): every default below stands except item 2. Item 2 was
decided "amount must be 0" on 2026-10-15 and is superseded by the order of
2026-10-17: a cyberlink with amount > 0 locks native stake on its
position, unlocked by kind 6 after MIN_LOCK (chain-economy §3); the
kernel's TxError::Box goes.
| # | question | default here | decided |
|---|---|---|---|
| 1 | subsidy rate (§3.5): 1 %/yr constant, 0.5 %, or a halving schedule | 1 %/yr constant, no halving | 1 %/yr, kept |
| 2 | locked cyberlink boxes (§2.4): lock until the cores add withdraw, or disallow amount > 0 entirely in phase 1 |
lock; withdraw arrives with rule set 2 | 2026-10-15 amount must be 0; superseded 2026-10-17: stake locks with the link, unlock after seven days (chain-economy §3) |
| 3 | genesis stake (§4.2): make delegated/undelegating balances liquid, or hold them dormant until staking activates | liquid | liquid, kept |
| 4 | the 8.97 T BOOT on the passport contract | dormant under legacy_owner, untouched |
dormant, kept |
| 5 | TOCYB × 666 → CYB | not executed; TOCYB carried as a coin; phase 3 | TOCYB as a coin, kept |
| 6 | FINALITY_DEPTH 120 (1 h) vs parano1d's 18 (9 min) |
120 — a canary with low hash rate should be slow to finalize | 120, kept |
| 7 | checkpoint sunset at 6 months vs owner-switched | hard sunset 525,600 blocks plus operator switch | sunset 525,600 + switch, kept |
| 8 | fee floor 1 unit/byte on both chains (very different unit values) | 1 unit/byte; revisit when a market exists | 1 unit/byte, kept |
| 9 | block time 30 s vs 60 s | 30 s | 30 s, kept |
| 10 | NeuronRecord.nonce in bbg vs chain-side nonce table outside the root |
in bbg, under the root | in bbg, kept |
| 11 | multisig / non-secp256k1 legacy accounts | dormant; a later rule set adds their claim | dormant, kept |
| 12 | the particle definition (row 19) | hemera(bytes), 32 bytes, as every crate computes today |
hemera(bytes), kept |
11. the pool (rule set 2, formats frozen at genesis)
The pool is the shielded money of
privacy, frozen: one tree of hemera
commitments, spends proven in zero knowledge by a hash-only zheng proof,
cyberlinks as public outputs of spends, one folded proof per block. It is
off at launch: rule set 1 knows none of its transaction kinds, and the
chain is public until rule set 2 activates; privacy is not retroactive
(proposal §1.13). What is on board at genesis is the material and the
formats of this section. The genesis p frame ends with the pool record
of §11.9, so the chain id commits to every constant below; the activation
of rule set 2 adds verifying keys (§11.10) and changes nothing written here.
Notation as in the rest of this page: hemera(x) is the flat sponge
hemera::hash (32 bytes), ‖ is concatenation, integers are
little-endian. Every value is computed through the hemera API, never from
pinned constants. The chain freezes hemera's profile #15 (x⁷ in every
round, 6 + 6 full rounds, 48 partial; hemera 0.4, release/0.4 7237a23);
every value quoted is computed against it (re-blessed 2026-10-16 from the
0.3 values, with the genesis particle; the definitions did not change).
Reference implementation: crate/src/chain/pool/; vectors:
chain-conformance §12.
11.1 wide digests and canonical limbs
Every consensus-critical digest of the pool — owner, rho, commitment,
nullifier, predicate binding, tree node, spend id, statement id, verifying
key set, tags — is wide: 64 bytes, eight Goldilocks elements. A 32-byte
hemera digest has about 85 bits of generic quantum collision resistance
(Brassard–Høyer–Tapp, 2^(n/3)); eight elements give about 170, above the
128 the proposal requires (§1.3: at least 48 bytes), and a format frozen at
genesis can never be widened. The 32-byte particle stays a locator — token
ids, data, link endpoints, the chain id, transparent card ids — never an
authority over value or program.
W(x) = xof(x)[0..64] // two squeezes of 32 bytes
W is hemera's own sponge, not a second hash: the plain mode of
hemera::Hasher absorbs x exactly as hemera(x) does, and W(x) is the
first 64 bytes of its extendable output (Hasher::finalize_xof) — the
first squeeze is hemera(x) itself, the second follows one more
permutation. Each 8-byte group is a canonical element. Domain separation
is the pool tag every W input begins with (§11.9); consensus never uses
the narrow digest of a pool-tagged input. Cost: one permutation more than
hemera(x).
Canonical limbs: every 32-byte and 64-byte field of every pool encoding
(records, deposits, spend_public, the statement) is read as 8-byte
little-endian limbs, and every limb must be < p = 2^64 − 2^32 + 1. A
decoder refuses a limb ≥ p: a field element x and x + p would name
one value twice. Integers (value, weight, amount, fee, counts,
lengths) are not limbs and take any value of their type.
11.2 record
record = token: [u8;32] ‖ value: u64 ‖ owner: [u8;64] ‖ rho: [u8;64] ‖ r: [u8;32] ‖ data: [u8;32] ‖ predicate: [u8;64]
| field | bytes | offset | meaning |
|---|---|---|---|
token |
32 | 0 | token id (§3.1), a locator |
value |
8 | 32 | amount of token, any u64 |
owner |
64 | 40 | W(D_OWNER ‖ sk), sk a 32-byte secret |
rho |
64 | 104 | uniqueness nonce, derived (§11.3), never chosen by a sender |
r |
32 | 168 | commitment randomness |
data |
32 | 200 | a particle; zero bytes = none |
predicate |
64 | 232 | predicate binding W(D_PRED ‖ program) over the nox program's canonical bytes; zero bytes = none |
296 bytes, fixed, every limb canonical.
11.3 owner, rho, commitment, nullifier
owner = W(D_OWNER ‖ sk) // 20 + 32 bytes in
commitment = W(D_CM ‖ record) // 17 + 296 bytes in
nullifier = W(D_NULL ‖ chain ‖ sk ‖ rho) // 24 + 32 + 32 + 64 bytes in
rho_j = W(D_RHO ‖ nf_0 ‖ j: u8) // output j of a spend whose first nullifier is nf_0; 18 + 64 + 1 in
rho = W(D_RHO ‖ txid ‖ 0: u8) // a deposited record, txid of its deposit (§2.1); 18 + 32 + 1 in
chain is the chain id: a nullifier of pussy is never one of bostrom.
The rho of every output is derived inside the proof from the spend's first
nullifier, and the rho of a deposit by every node from its txid; the two
seeds differ in length (64 and 32 bytes, the length is in the capacity),
so the derivations never meet. Since nullifiers are unique for the life of
the chain (§11.5), no two records ever share a rho, and no sender can give
two records one nullifier to make one of them unspendable. Inputs carrying
sk are hashed in constant time (hemera::Hasher::new_secret, the same
digest).
11.4 commitment tree and anchors
-
one tree of depth 40: positions
0 … 2^40 − 1, filled in append order — blocks in height order, transactions in body order, a transaction's commitments in their listed order. A transaction that would append past position2^40 − 1is invalid. -
a leaf is the commitment itself (a tagged wide digest); an unfilled position holds
EMPTY = W(D_EMPTY). -
a node is the wide digest of its tagged children:
node(L, R) = W(D_NODE ‖ L ‖ R) // 19 + 64 + 64 = 147 bytes inCost at hemera's 56-byte rate (7-byte packing): three absorbing permutations, the last carrying the padding, and one for the second squeeze — four per node, where the narrow node jet (
hemera::tree::hash_node, zheng#66) takes one over two four-limb children. A depth-40 path is 160 permutations natively and in the circuit. The construction uses only the sponge API; a dedicated wide node jet (children absorbed as elements, two permutations at width 16, one at width 24) would be a different format and can only be adopted with a re-blessing before genesis, never after. -
E_0 = EMPTY,E_i = node(E_{i−1}, E_{i−1});E_40is the root of the empty tree. The depth is fixed, so the root needs no flag of its own. A path is verified leaf to root; bitiof the position set means the sibling at leveliis on the left. -
root_after(b)is the tree root after every pool transaction of blockb;root_after(0) = E_40(genesis holds no commitment, and rule-set-1 blocks append none). -
anchor window: a spend in block
his valid only if itsanchorequalsroot_after(b)for somebwithmax(0, h − 1,000) ≤ b ≤ h − 1. A spend never anchors on commitments of its own block; a node keeps the last 1,000 roots. A membership proof against a historical root proves that a record existed, never that it is unspent; unspentness is the nullifier check of §11.5.
11.5 the nullifier set and the turnstile
The nullifier set is lifetime: every nullifier ever revealed stays in it, and it is never reset, pruned by epoch or rebuilt from a live window (an epoch reset accepts an already spent nullifier; proposal §1.10). A node may compact its storage only where an authenticated proof of non-membership over the whole history still rejects every old nullifier. A spend is invalid if any of its nullifiers is in the set or appears twice in its block.
T(τ) = hemera(D_TURNSTILE ‖ τ) // 24 + 32 = 56 bytes in, 32 bytes out
T(τ) is a raw key of bbg's balances dimension (§3.2) holding the pool's
counter for token τ: a key of the transparent ledger, 32 bytes like every
balance key. A transparent key hemera(owner ‖ τ) hashes 64 bytes and the
input length is in the capacity, so no transfer, coinbase, claim or genesis
frame can address T(τ); aiming one at it is a preimage search against a
fixed target among the chain's few genesis tokens, about 2^128 by Grover.
The counter is absent — zero — at genesis and is under state_root from
block 0.
| event | effect |
|---|---|
deposit of value of τ (§11.7) |
T(τ) += value |
withdrawal (to, τ, amount) of a spend |
T(τ) −= amount; balances[hemera(to ‖ τ)] += amount |
fee (τ_f, fee) of a spend |
T(τ_f) −= fee; paid to the block's miner through the coinbase |
A transaction whose debit would take any T(τ) below zero is invalid,
whatever its proof says. Hence, per token, at every height:
T(τ) = Σ deposits(τ) − Σ withdrawals(τ) − Σ spend fees(τ) ≥ 0
The pool's content can never exceed what entered it: a break of the proof
system or of hemera counterfeits at most T(τ) and never raises the supply.
Conservation (§3.4) is unchanged — deposits and withdrawals move value
between keys of one dimension, and the per-token sums include T(τ).
11.6 the SPEND public inputs
One relation, SPEND. Its public inputs, encoded:
spend_public = chain: [u8;32]
‖ anchor: [u8;64]
‖ n: u8 ‖ nullifier[64] × n
‖ m: u8 ‖ commitment[64] × m
‖ k: u8 ‖ (p[32] ‖ q[32] ‖ weight: u64 ‖ payout[64]) × k
‖ w: u8 ‖ (to[32] ‖ token[32] ‖ amount: u64) × w
‖ fee_token: [u8;32] ‖ fee: u64
‖ predicate[64] × (n + m)
‖ c: u8 ‖ (len: u16 ‖ note[len]) × c
Canonical form, checked by every decoder:
1 ≤ n ≤ 4inputs,0 ≤ m ≤ 4outputs,0 ≤ k ≤ 4cyberlinks,w ∈ {0, 1},0 ≤ c ≤ mnotes; a count over its cap is refused before anything it counts is read;- no nullifier twice and no commitment twice within one spend;
- every cyberlink has
p ≠ q; - a withdrawal has
amount > 0(no withdrawal is writtenw = 0); - the predicates are the bindings of the inputs in order, then of the outputs in order; zero bytes means none;
- note
ibelongs to outputi; every note haslen ≤ 2,048; notes are opaque to consensus (an ML-KEM-1024 envelope bound to its output commitment, by wallet convention, proposal §1.2); - every limb canonical (§11.1); no trailing bytes. The longest canonical encoding is 9,981 bytes.
A cyberlink output (p, q, weight, payout) is public: weight is a u64
that does not enter the value equation below; payout is an owner value
(§11.3) that receives what the link earns. The spend's name in the block
statement is
spend_id = W(D_SPEND ‖ spend_public)
The witness: the input records, their Merkle paths and sk, the output
records, the predicate programs' witnesses. Checks inside the proof, fixed
with the relation:
- every input record is canonical, has
owner = W(D_OWNER ‖ sk), and its commitment sits in the tree atanchor(§11.4); - every nullifier is
W(D_NULL ‖ chain ‖ sk ‖ rho)of its input; - conservation as integers, never modulo
p: every value,feeandamountis a u64 held as two 32-bit limbs, each range-checked< 2^32; per tokenτ, Σ input values and Σ output values +fee·[τ = fee_token] +amount·[τ = token of the withdrawal] are each summed limb by limb with explicit carries into a third limb (at most six terms a side, below 2^67), and the two sums are equal limb for limb (the u64 valuepis zero in the field and would pass a field equation); - every output commitment is
W(D_CM ‖ record)of its canonical output record, and outputj's rho isW(D_RHO ‖ nf_0 ‖ j); - every predicate of an input or an output, run on
spend_publicand its own witness, accepts (the nox machine relation,zheng/specs/machine.md); predicates only add constraints and never relax checks 1–4; - the public outputs are those the records and predicates declare.
Checks outside the proof, by every node: chain equals the chain id; the
anchor is in the window (§11.4); no nullifier is in the lifetime set or
repeated in the block (§11.5); the turnstile stays non-negative; fee_token
is the native token and fee ≥ len(tx) · MIN_FEE_PER_BYTE; the block proof
verifies (§11.8).
11.7 transaction kinds 4 and 5
| kind | name | body bytes | sig | total bytes |
|---|---|---|---|---|
| 4 | deposit | 280 | NSIG1 (102) | 384 |
| 5 | spend | 2 + len |
none | 4 + len, at most 9,985 |
deposit = from: neuron[32] ‖ nonce: u64 ‖ token: [u8;32] ‖ value: u64 ‖ owner: [u8;64] ‖ r: [u8;32] ‖ data: [u8;32] ‖ predicate: [u8;64] ‖ fee: u64
spend = len: u16 ‖ spend_public[len]
The envelope, txid and the signing statement are those of §2.1.
Deposit (transparent to commitment, no proof): the record without its rho,
which the node derives as W(D_RHO ‖ txid ‖ 0). Signed by from as kinds
1 and 2; the nonce rule of §2.5; fee ≥ 384 · MIN_FEE_PER_BYTE in the
native coin; value > 0; every limb canonical; from holds value of
token (the native coin also covers the fee and respects maturity, §2.2).
Effects: balances[hemera(from ‖ token)] −= value, T(token) += value,
the fee to the coinbase, commitment(record) appended to the tree,
nonce += 1. A deposit reveals that record's owner and rho; its later
nullifier still needs sk, so the spend of a deposited record is linkable
to the deposit by value and timing only. Wallets deposit to a one-time
sk and spend into fresh records.
Spend: no signature — authorization is knowledge of sk inside the proof;
len is the exact length of a canonical spend_public. Effects, in this
order: the nullifiers join the lifetime set; the commitments are appended;
the withdrawal and the fee leave the turnstile (§11.5); the cyberlinks are
public cyberlinks. The transaction's own proof travels in the mempool only
(chain-wire §4), never in a block. A spend is bounded by 9,985 bytes, not
by MAX_TX_BYTES; a deposit fits MAX_TX_BYTES.
Under rule set 1 the decoder knows neither kind (§2.1): a block carrying one is invalid.
11.8 the block-proof statement
A block of rule set 2 with at least one spend carries one folded proof (the
constant-size profile of zheng/specs/recursion.md) whose public input is
statement = chain: [u8;32] ‖ height: u64 ‖ vk_set: [u8;64] ‖ count: u32 ‖ spend_id[64] × count
statement_id = W(D_BLOCK ‖ statement)
vk_set = W(D_VK ‖ (len: u32 ‖ vk) × v)
spend_ids are listed in body order, one per kind-5 transaction; vk_set
digests the rule set's verifying keys in the order its activation entry
lists them. The statement is defined as the conjunction of the listed
spends' SPEND statements under those keys: a reference validator that
checks raw transaction proofs one by one reaches the same verdict on every
block. Nodes verify the block proof and never a transaction's proof. A
block without spends carries no proof.
11.9 domain tags
Chosen once, ASCII with a terminating NUL byte, never reused for any other
input; disjoint from the chain's soft3/chain/… tags (§1.7, §2.1).
| tag | bytes | length | hex |
|---|---|---|---|
D_OWNER |
soft3/pool/owner/v1\0 |
20 | 736f6674332f706f6f6c2f6f776e65722f763100 |
D_CM |
soft3/pool/cm/v1\0 |
17 | 736f6674332f706f6f6c2f636d2f763100 |
D_NULL |
soft3/pool/nullifier/v1\0 |
24 | 736f6674332f706f6f6c2f6e756c6c69666965722f763100 |
D_RHO |
soft3/pool/rho/v1\0 |
18 | 736f6674332f706f6f6c2f72686f2f763100 |
D_PRED |
soft3/pool/predicate/v1\0 |
24 | 736f6674332f706f6f6c2f7072656469636174652f763100 |
D_EMPTY |
soft3/pool/empty/v1\0 |
20 | 736f6674332f706f6f6c2f656d7074792f763100 |
D_NODE |
soft3/pool/node/v1\0 |
19 | 736f6674332f706f6f6c2f6e6f64652f763100 |
D_SPEND |
soft3/pool/spend/v1\0 |
20 | 736f6674332f706f6f6c2f7370656e642f763100 |
D_BLOCK |
soft3/pool/block/v1\0 |
20 | 736f6674332f706f6f6c2f626c6f636b2f763100 |
D_TURNSTILE |
soft3/pool/turnstile/v1\0 |
24 | 736f6674332f706f6f6c2f7475726e7374696c652f763100 |
D_VK |
soft3/pool/vk/v1\0 |
17 | 736f6674332f706f6f6c2f766b2f763100 |
D_TAGS |
soft3/pool/tags/v1\0 |
19 | 736f6674332f706f6f6c2f746167732f763100 |
tags = W(D_TAGS ‖ D_OWNER ‖ D_CM ‖ D_NULL ‖ D_RHO ‖ D_PRED ‖ D_EMPTY ‖ D_NODE ‖ D_SPEND ‖ D_BLOCK ‖ D_TURNSTILE ‖ D_VK)
Its value against hemera 0.4 is in chain-conformance §12.
11.10 what genesis commits to
The params frame of the genesis file (§4.1) ends with the pool record:
pool = format: u32 (= 1) ‖ depth: u8 (= 40) ‖ anchor_window: u32 (= 1,000) ‖ digest: u8 (= 64) ‖ tags: [u8;64] // 74 bytes
= 01000000 28 e8030000 40 ‖ tags
A reader rejects a genesis whose pool record differs in any byte from this
one. format = 1 names this section as a whole: the record, the
derivations, the encodings, the caps (4 inputs, 4 outputs, 4 cyberlinks,
2,048-byte notes), the tree node, limb conservation, the lifetime
nullifier set, the turnstile and the statement shape. Through the record
the chain id commits to them, and through the chain id every transaction
and header.
11.11 rule sets
- Rule set 1 (launch): kinds 4 and 5 are unknown and invalid;
T(τ)is zero for every token; the tree is empty and everyroot_after(b)isE_40; the nullifier set is empty. Nothing in rule set 1 reads or writes pool state, and everything it records is public forever. - Rule set 2 (the pool) activates by the activation table (§7.1) when the
gates of the proposal pass; the privacy promise holds from its
activation height. Its activation entry carries the verifying key set
of
SPENDand of the block proof — and nothing else of this section: no format, tag, width, depth, window or accounting rule changes with it. A verifying key set, once in a rule set, is never changed; a new one is a new rule set. - Where rule set 2 stores the commitment list and the nullifier set under
state_root(bbg's A and N dimensions, empty and committed today, §3.2) is its choice; the tree root of §11.4 is a function of the append order alone and is what anchors and proofs use.
12. acceptance
The chain is done when chain-conformance.md is green on the reference
implementation, two nodes on two machines mine and sync pussy-rc from the
real genesis file for 24 h with zero conservation failures, a third node
joins from the graph alone (bootstrap list emptied) and reaches the tip, a
rented-hash-rate rehearsal (one GPU box) produces a reorg that the reorg
limit and checkpoints bound as specified, every node agrees on every epoch
record of the 24 h run and settles bostrom's graph within SETTLE_BUDGET
(chain-economy §10), and cyb reads the chain through the HTTP surface of
chain-wire §6. Receipts go to soft3/audit/chain/.
See chain-wire for the network, chain-conformance for the vectors, native-node for the HTTP acceptance contract this chain inherits, and cyber/launch for the phase it serves.