Netlist format
Seven bytes per gate, a flat node space, and a topological constraint. This is the entire encoding.
Byte layout
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 0 | 1 byte | op | 0 = NAND, 1 = LATCH (pass-through) |
| 1 | 3 bytes | a | First input node, big-endian |
| 4 | 3 bytes | b | Second input node, big-endian |
Node numbering
0— constant 01— constant 12 … 2+nIn-1— circuit inputs, in order2+nIn+i— output of gatei
Outputs are the last nOut nodes of the sequence. There is no separate output table; the ordering is the contract.
Evaluation
nodes = [0, 1] + inputs
for (op, a, b) in gates:
x, y = nodes[a], nodes[b]
nodes.append((1 - (x & y)) if op == 0 else x)
outputs = nodes[-nOut:]
NAND is 1 - (x AND y). LATCH passes x through, which is how a design can hold a value without introducing a new gate type.
A worked example
The first seven bytes of the ADD4 netlist are:
00 000002 000006
op=0 (NAND) a=2 b=6
Node 2 is the first input, node 6 is the fifth input of a 9-input adder — the low bits of A and B. Its output becomes node 2 + 9 + 0 = 11.
Constraints
- Length must be a multiple of 7.
- Every referenced node must already exist:
a, b < 2 + nIn + ifor gatei. This keeps the list topological and forbids cycles. - Node indices are 24-bit, which caps a single netlist at roughly 16.7 million nodes.
Size and cost
A 40-gate shifter is 280 bytes. A 2,118-gate multiplier is 14,826 bytes. The netlist is stored on chain as bytes, so tapeout gas scales with it, and so does the calldata of the tapeout transaction.
Why a flat list
It is the smallest encoding that can be decoded by a contract and re-executed by a browser without a compiler. There is no graph serialisation, no labels, no hierarchy — just gates in evaluation order.