Skip to content

t27c: verify the die's DNA inside a signed receipt -- R3-2 slice 2 tool half (Refs #7452) - #7484

Merged
gHashTag merged 7 commits into
masterfrom
claude/die-receipt-verify-7452
Oct 7, 2026
Merged

gHashTag merged 7 commits into
masterfrom
claude/die-receipt-verify-7452

Conversation

@gHashTag

@gHashTag gHashTag commented Oct 7, 2026

Copy link
Copy Markdown
Owner

R3-2 slice 2, tool half: t27c now verifies the die's DNA as part of a signed receipt.

Refs #7452 (contract: #7455, stacked here; slice 1: #7446). Epic #6655, round #7332.

What changes

  • specs/verified/die_binding.t27 gains receipt_version (a receipt is v2 exactly when its device_dna is text) and dna_read_allowed (the reader runs only with exactly one JTAG cable attached: openocd opens the first FTDI cable it finds, W838).
  • die_binding.t27 reaches t27c through gen-rust: bootstrap/gen/rust/verified/die_binding.rs, wired with #[path], and drift-tested in bootstrap/tests/signed_receipt_reader.rs.
  • A receipt whose device_dna is text signs the v2 message (SIGNED_FIELDS_V2), so the DNA is inside the signed bytes. Changing one hex digit or nulling the field fails as AUTH_BAD_SIGNATURE (new test the_device_dna_is_inside_the_signed_bytes).
  • run-record prints the die level (NAMED / NONE) from die_level and the run fold, and states plainly that no level is device-rooted: the DNA is a public name, not a die-held secret.

Own-language budget

Hand Rust here is glue only: main.rs +4, service.rs +39/-6, the reader test +5/-3. Every decision comes from the generated module.

Evidence (Railway lab, rebased head f943ba3)

  • t27c test-report specs/verified/die_binding.t27: 13/13 pass, 0 vacuous.
  • 7 hand mutants all fail a test: three version swaps, plus four cable rules (>= 1, <= 1, != 0, true).
  • seal --verify MATCH for device_dna, die_binding and signed_receipt.
  • Cargo tests: r3_signed_receipt / r2_silicon_receipt / run_record 17 pass, signed_receipt_reader 14 pass, run_record_reader 6 pass.

Not in this PR

The producer, which reads the DNA on the bench and writes it into the silicon receipt, is the next slice.

🤖 Generated with Claude Code

gHashTag and others added 7 commits October 7, 2026 17:56
…Refs #7439)

specs/verified/device_dna.t27 pins every decision about the 7-series
device DNA read with no user bitstream: IR length 6, FUSE_DNA 0x32 (64-bit
register) and XSC_DNA 0x17 between ISC_ENABLE 0x10 and ISC_DISABLE 0x16
(57-bit register); how the raw shift decodes to the DNA (first shifted bit
is the most significant, the order openFPGALoader --read-dna prints);
well-formedness (not all zero, not all one, XSC fill ones, FUSE tail as
observed); fixed-width hex; and when a FUSE read and an XSC read name one
die.

Oracle: 14 live reads of each instruction on the attached XC7A200T over two
transports (libftdi MPSSE and openocd), all identical; decoded DNA
050d58218fd9854. 13 tests, 0 vacuous; 20 of 20 hand mutants killed on the
Railway lab.

The reader is the openocd command line in the spec header: the Only-t27 gate
refuses a new or edited .py, and the read needs no new code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
t27c test-report: 13 tests, 13 pass, 0 vacuous. Seal written by
t27c seal --save on the lab (t27c-bootstrap@0.4.0+cfda070b2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tract (Refs #7439)

The v2 receipt message adds device_dna after full_idcode under a new
domain line. The producer writes it only when FUSE_DNA and XSC_DNA name
one die before and after the run; the verifier counts it only inside
verified bytes. distinct_dies3 gives R3-3 its die count.

Honest ceiling: the DNA is a name, not a secret, so DIE_NAMED is the
signer's claim. DIE_ROOTED_LEVELS stays 0. signed_receipt.t27's comment
that called a signed DNA read device-rooted is corrected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#7439)

A receipt is v2 exactly when its device_dna is text, so stripping or
adding the field changes the signed bytes. The DNA reader runs only when
exactly one JTAG cable is attached (openocd opens the first FTDI cable it
finds, W838). Both checks run at runtime: test-report 13/13, 0 vacuous;
7 hand mutants (version swap x3, cable rule x4) all fail a test.
Resealed on the Railway lab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
die_binding.t27 reaches t27c through gen-rust
(bootstrap/gen/rust/verified/die_binding.rs, drift-tested). A receipt
whose device_dna is text signs the v2 message (SIGNED_FIELDS_V2), so the
DNA is inside the signed bytes: change one hex digit or strip the field
and verification fails with AUTH_BAD_SIGNATURE. run-record prints the
die level (NAMED / NONE) from die_level and the run fold; no level is
device-rooted, because the DNA is a public name, not a secret.

Hand Rust is glue only: main.rs +4, service.rs +39/-6, reader test +5/-3.
The producer (reading the DNA on the bench) is the next slice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gHashTag
gHashTag enabled auto-merge (squash) October 7, 2026 11:00
This was referenced Oct 7, 2026
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-07 12:13:35 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)=c3821827b257 != 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.

1 participant