Skip to content

feat(fpga): trinet_node.t27 -- TRI-NET MAC32 job core with SipHash-2-4 receipts (E2b) - #8373

Merged
dmitrii-f-t27 merged 5 commits into
masterfrom
spec/trinet-node
Oct 9, 2026
Merged

dmitrii-f-t27 merged 5 commits into
masterfrom
spec/trinet-node

Conversation

@dmitrii-f-t27

@dmitrii-f-t27 dmitrii-f-t27 commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Closes #8356

Part of #8327 (E2: TRI-NET node over UDP on the AX7203). Refs #6655. Consumes the payload of EthRx (#8370).

Pull Request Checklist

  • PR title follows semantic convention
  • PR body includes Closes #8356
  • Tests added: t27c test-report specs/fpga/trinet_node.t27 passes 6/6, 0 vacuous
  • Spec sealed with this tree's t27c 0.5.2, --verify all MATCH

Description

specs/fpga/trinet_node.t27 (module TrinetNode) is the job core of the TRI-NET node. The wire format is the one gHashTag/trinity-fpga src/trinet/protocol.zig defines and fpga/portable/trinet_node_core.v implements over UART; only the transport moves to UDP:

  • request AA 55 OP NONCE[4] W[8] X[8] TRIG (24 bytes); receipt A5 Y STATUS NONCE[4] NODE_ID[4] TAG[8];
  • OP 1 MAC32: Y = sum of w*x over 32 trit pairs (01 = +1, 10 = -1, 00/11 = 0); OP 2 sets the write-once key;
  • TAG = SipHash-2-4 over OP NONCE W X Y NODE_ID (26 bytes), keyed with the node key, the zero key while none is set, or the new key in the request that sets it.

Hardware structure (so that 125 MHz closes):

  • the dot product is five clocks of field folds over agree/oppose bit masks, not one chain of 32 adders;
  • a SipHash half round takes two clocks: the two 64-bit sums go to registers, then rotate/XOR/write; every step changes a word from its own old value and the sums only, so one state bank is enough;
  • the step code (tq), the A/B choice (fa) and the sum-step flag (fs) are decoded one clock early, so the adder's operand is one LUT, v0 ^ (fa ? v1 : v3).

One receipt takes 59 clocks after the frame ends (about 2.1 million receipts per second at 125 MHz).

Testing

level what result
spec t27c test-report (Zig 0.16): paper vector a129ca6149be45e5, dot product, seven receipts from protocol.zig, busy drop, not-a-request, frame rejected by EthRx 6/6, 0 vacuous
generated RTL gen-verilog output (sha256 ead9d72e..., the sealed one) in Icarus Verilog 13.0, driven like EthRx; receipts from protocol.zig itself (zig run gen.zig), not from the spec PASS: 7 receipts equal in y, status, nonce, tag; busy drop counted; no-magic and 20-byte datagrams start nothing; a rejected frame starts nothing
negative control the same testbench on a copy of the RTL with NODE_ID + 1 FAIL 8, as it must
OOC timing yosys 0.69 synth_xilinx -flatten -abc9 -nowidelut -nosrl, nextpnr-xilinx 0.9.7, xc7a200tfbg484-2, 125 MHz seeds 1/2/3: 127.24 / 134.26 / 131.08 MHz post-route, all PASS; 3592 cells, 199 CARRY4, 1230 FF

How the timing got there (seed 1): one chain of 32 adders in the dot product 12.75 MHz; two-half add64 91.84; one 64-bit chain 112.66; carry-select forms 112.68 and 91.10 (synthesis merged them back into a chained pair); two-clock half round 115.19; step code registered 130.29 (but seed 3 118.61); one bank and a one-bit A/B select 127.24 / 134.26 / 131.08 on seeds 1/2/3.

The testbench and vector generator are outside the repo (hand-written .v/.py need an owner-approved entry in tools/policy/foreign-exceptions.txt); sha256: testbench 2fb108fe..., gen.zig 8c33ae5a..., protocol.zig copy 52afc0d5....

Review Notes

  • Not shown here: the reply frame (E2c), RGMII capture on silicon and a run on the board (E2d). No integrated timing yet; OOC only.
  • 4e36b2b closed only two of three seeds (seed 3 118.61 MHz: four LUT levels before the adder, from the v/q bank select and an 8-bit step compare). f8c5f52 removes the second bank and decodes the A/B choice as one bit; all three seeds now close, the smallest margin is 2.24 MHz (seed 1). Integrated timing in E2d is the real check.
  • tools/elab_baseline.txt gets trinet_node 0: the module elaborates clean in iverilog (fpga-conformance reads a module without a row as NEW).
  • Inherited red checks on master (has_at duplicate, a home path in the t27b-loop skill, unlisted t27b specs) are fixed in gates: record has_at as a deliberate copy; no home path in the t27b-loop skill (#8361) #8362; this PR does not merge while they are red.

…4 receipts (E2b)

Closes #8356

TrinetNode takes the UDP payload EthRx hands out one byte per clock, runs one
MAC32 job or key request per datagram and produces the 19-byte v2 receipt (Y,
STATUS, NONCE, NODE_ID, SipHash-2-4 TAG) bit for bit as protocol.zig defines it.

- The dot product is five clocks of field folds over agree/oppose bit masks,
  not one chain of 32 adders.
- A SipHash half round takes two clocks: the two 64-bit sums go to registers,
  then rotate/XOR/write the other bank. The step code is decoded one clock
  early (tq). 59 clocks per receipt.
- test-report 6/6, 0 vacuous: the SipHash paper vector, the dot product, seven
  receipts from protocol.zig (unkeyed, setkey, keyed, locked, +32, -32,
  reserved codes), busy drop, not-a-request, a frame EthRx rejected.
- Seal from this tree's t27c 0.5.2, verify MATCH.
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-09 21:42:24 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 48
PRs with All Checks Green 2
READY 0
FAILING 48
PENDING 0
NO CHECKS YET 0

These columns do not partition: 0 + 48 + 0 + 0 = 48, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=557cd271f4e3 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

… close 125 MHz

Refs #8356

Seed 3 of 4e36b2b reached 118.61 MHz: four LUT levels sat in front of the
sum adder, the v/q bank select and an 8-bit compare of the step code. With the
sums in registers the second bank is not needed any more: every step changes a
word from its own old value and sum0/sum1 only. The bank (256 FF), ph and the
bank helpers go; fa (half A or B) and fs (a sum step) are decoded a clock
early, so the adder's operand is one LUT, v0 ^ (fa ? v1 : v3).

OOC xc7a200tfbg484-2, 125 MHz, seeds 1/2/3: 127.24 / 134.26 / 131.08 MHz,
3592 cells (was 4753). test-report 6/6, 0 vacuous; seal MATCH; trinet_node
elaborates clean in iverilog, so tools/elab_baseline.txt gets a 0 row.
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-09 21:58:27 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 49
PRs with All Checks Green 1
READY 1
FAILING 49
PENDING 0
NO CHECKS YET 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=557cd271f4e3 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-09 22:02:04 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 47
PRs with All Checks Green 3
READY 1
FAILING 47
PENDING 0
NO CHECKS YET 0

These columns do not partition: 1 + 47 + 0 + 0 = 48, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=557cd271f4e3 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@dmitrii-f-t27

Copy link
Copy Markdown
Contributor Author

compile-proofs (Coq) is red here for a cause outside this PR:

  • It runs on proofs/trinity/**.v. This PR changes none of them (gh pr diff --name-only: the spec, its seal, tools/elab_baseline.txt). The run came from the push of the master merge f504fab, which carried master's proof files.
  • Run https://github.com/gHashTag/t27/actions/runs/37996784625: Error: The reference lra was not found in the current environment, then Cannot find a physical path bound to logical path CorePhi for the rest (13 of 13 files).
  • The same workflow failed on every recent run, among them the t27c-v0.5.2 tag (2026-10-09 07:41) and t27c-v0.5.1 (2026-10-08).
    Needed: a Coq environment with lra (Coq.micromega) and the CorePhi load path in coq-proofs.yml. It is not a required check. It is outside this PR's boundary (E2b: trinet_node.t27 -- TRI-NET MAC32 job core with SipHash-2-4 receipts (AX7203) #8356), so this PR does not change it.

Refs #8356

t27b-native-ratchet on f504fab (run 37996789959): the reference passes
specs/fpga/trinet_node.t27 and so does t27b; the ledger did not name it.
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-09 22:14:12 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 47
PRs with All Checks Green 3
READY 1
FAILING 47
PENDING 0
NO CHECKS YET 0

These columns do not partition: 1 + 47 + 0 + 0 = 48, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=557cd271f4e3 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-09 22:19:30 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 48
PRs with All Checks Green 2
READY 1
FAILING 48
PENDING 0
NO CHECKS YET 0

These columns do not partition: 1 + 48 + 0 + 0 = 49, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=557cd271f4e3 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

E2b: trinet_node.t27 -- TRI-NET MAC32 job core with SipHash-2-4 receipts (AX7203)

1 participant