How TNet works
TNet v1 is Requant's work function: an eight-layer int8 network with exact integer requantization between layers. A miner runs many input rows through the network; pieces of the output rows are lottery tickets; a node checks a winning ticket by recomputing one row. This page describes the construction as specified in spec/07 and frozen in ADR 0016.
In one paragraph
Every epoch has eight fixed 8192 × 8192 int8 weight matrices, derived from a seed on the chain. For a block header and a nonce, the miner derives up to 65,536 input rows of 8192 int8 values, multiplies them through the eight layers and, after each layer, rounds the int32 results back to int8 with an exact fixed-point rule. Each output row is cut into 32 pieces of 256 bytes; each piece is hashed with the header, nonce, row and piece index, and a hash below the network target wins the block. The block carries the nonce, the row and piece indices and the 256-byte piece. A node recomputes that single row through the eight layers, compares the piece and checks the hash.
The construction
Epoch weights. For layer l = 0 … 7:
W_l = int8( expand( SHA256("abacus/tnet-w" || epoch_seed || LE32(l)), n·n ) )
expand is a SHA-256 counter stream. The matrices are stored row-major.
Inputs for one attempt. For a header digest and a 64-bit nonce:
s = SHA256("abacus/tnet-x0" || header_digest || LE64(nonce))
X_0 = int8( expand(s, b·n) ) # b rows of n int8 values
X_l = requant( X_{l-1} · W_{l-1} ) # l = 1 … 8
Requantization. After each layer the exact int32 product is mapped back to int8:
requant(y) = clamp( (y·M + 2^23) >> 24, −128, 127 )
This is round-half-up fixed-point scaling, computed exactly. It is the nonlinear step that stops the eight layers from being merged into one matrix.
Tickets. Row i of the last layer is cut into n/w = 32 pieces c of w = 256 bytes:
h = SHA256( X_8[i, c·w … (c+1)·w] || 0x54 || header_digest || LE64(nonce) || LE32(i) || LE32(c) )
A ticket (nonce, i, c) wins if h, read as a 256-bit number, is at most the block target.
Frozen parameters
| Parameter | Value | Meaning |
|---|---|---|
n | 8192 | layer width; weight matrices are 8192 × 8192 |
L | 8 | number of layers |
w | 256 bytes | ticket width; 32 tickets per row |
M | 2505 | requantization multiplier, round(2^24 / (74·√8192)), which keeps the spread of activations constant from layer to layer |
B | 65,536 | maximum row index per nonce |
| Weights per epoch | 512 MiB | eight 8192 × 8192 int8 matrices |
Rows are independent, so a miner may process any number of rows per GPU pass; results are identical at any batch size.
What one ticket costs
- One full attempt (65,536 rows) is
L·b·n²≈ 3.5 × 10^13 multiply-accumulates and yields 2,097,152 tickets. - One ticket costs
L·n·w≈ 16.8 million multiply-accumulates, whatever strategy is used. Processing rows in batches is the cheapest way; mining single rows was measured at 42–51× more expensive per ticket. - One verification recomputes one row:
L·n²≈ 537 million multiply-accumulates.
What a block carries
The work data in a block is (nonce, i, c, piece): 8 + 4 + 4 + 256 = 272 bytes. This is the proof of work only. The block header, the difficulty target, the transactions and the epoch weights are not part of the 272 bytes.
The piece is included so that the cheap check comes first: a node hashes the piece with the header and compares it with the target before recomputing anything. A forged header therefore costs its author a full SHA-256 grind before it can cost a node a recomputation.
How a node verifies
- Check that the hash of the piece, header and indices meets the target.
- Recompute row
iof the attempt: derive its input from the header and nonce, multiply through the eight layers with the epoch weights, requantize after each layer. - Compare piece
cof the recomputed row with the piece in the block, byte for byte.
The verifier keeps the weights transposed so that each output value is a contiguous int8 dot product. The Requant node, a portable build that selects AVX2 at run time, verifies a claim in 11.2 ms on 8 threads and 21.7 ms on one thread of an AMD Ryzen 7 8745HS laptop processor (SPEC.md; details in measurements).
Why this shape
| Requirement | How TNet meets it |
|---|---|
| Work runs on tensor cores | 86.7–88.2% of an attempt is int8 matrix multiplication on the measured GPUs |
| Cheap verification | One row instead of 65,536; no proof system |
| No reuse across attempts | Every input row is derived from the header and nonce; weights change every epoch |
| No shortcut from linearity | Exact rounding between layers; one error after the first layer changes 55% of the last layer's values |
| Nothing to grind for free | The only free inputs are the nonce and the indices, each of which costs a full row computation |
| Reproducible everywhere | Integer arithmetic only; GPU kernels match the Rust and Python references byte for byte |
On the Requant chain
- Requant uses TNet v1 unchanged. The research construction compares leading zero bits of
h; Requant compareshwith a 256-bit target (SPEC.md). - Epochs. The weights change every 1440 blocks, about one day at 60-second blocks. Epoch
etakes its seed from a block 60 blocks before it starts:seed_e = H("requant/epoch", LE64(e) || id(block e·1440 − 60)), so every node derives the next weights (about 7 s on one core) before they are needed. The first epoch's seed comes from the chain identifier. - Memory. A node keeps the 512 MiB of weights in a file read through the operating system's page cache, so the node process itself stays small.
- Requantization in the node is written as
clamp(floor((y·2505 + 2^23) / 2^24), −128, 127), the same function as above. - Consensus parameters, the header format and difficulty adjustment are in the chain rules.
Test vectors and references
- Frozen test vectors: spec/vectors (rows 0, 1, 255 and 65535 at the frozen parameters, and a small n = 256 instance checked in Python).
- Rust reference: tnet.rs; Python reference: tnet.py; the Requant node's own implementation is in crates/tnet.