Skip to content

evidence: receipts from a second witness for checkpoints 1 and 2 - #143

Open
ogasurfproject-jpg wants to merge 4 commits into
agentrust-io:mainfrom
ogasurfproject-jpg:evidence/nenrin-witness-2026-10-20
Open

ogasurfproject-jpg wants to merge 4 commits into
agentrust-io:mainfrom
ogasurfproject-jpg:evidence/nenrin-witness-2026-10-20

Conversation

@ogasurfproject-jpg

Copy link
Copy Markdown
Contributor

What and why

LIMITATIONS.md and ROADMAP.md list these as open:

  • Checkpoint 2 has no witness receipt.
  • Submission to witnesses is not automated.
  • No receipt yet carries a signed witness time or a bound grade.
  • A second witness and split-view monitoring are future work.

This PR adds an evidence packet, docs/evidence/witness-2026-10-20-nenrin/, with receipts from a second, independently operated witness for both checkpoints. It also adds tests/test_witness_receipt_nenrin.py, which checks them offline with tools/verify_witness_receipt.py.

checkpoint 1 checkpoint 2
verified true true
grade_cryptographically_bound true (mmr-verified) true (mmr-verified)
witness_time_established false: more than 30 days old when witnessed true, iat 1792467378

Checkpoint 1 now has two witnesses, Action State and this one. As far as I know, checkpoint 2's receipt is the first under this registry where both limits read true.

The witness is HORIZON SHIELD (The HORIZONs Co., Ltd.), already a registered mirror. Its code is public: registry-witness-v0.

mmr-verified is signed only after the witness has done three things itself:

  • run this registry's two chain checks (consistency proofs, and the MMR rebuilt from the raw entries) with trace-verify's own functions;
  • pinned key bc133259…;
  • confirmed that every checkpoint it signed before is still on the same line, byte for byte.

Receipts are final: one per checkpoint, never reissued. The witness log is RFC 9162, and its tree heads carry consistency proofs. The first tree head is anchored to Bitcoin through the JIDEC ledger.

The packet README states what this does not establish. In particular, two witnesses on one checkpoint are a start on split-view detection, not proof of it.

Two offers, for the maintainers to accept or not

  1. Recurring witnessing. I can run this on every new checkpoint and open an evidence PR like this one. Later, if you prefer, it can be an endpoint compatible with tools/capture_witness_receipt.py (POST /checkpoints, GET /checkpoints/<log_id>, GET /v1/inclusion/<digest>).
  2. Mirroring in both directions. We already mirror this registry. In return, would AgenTrust hold a mirror of the NENRIN/JIDEC ledger? It is one GitHub Action in a repository of yours (BECOME_A_MIRROR.md), with no server and no secrets. Each log would then be independently held by the other's operator.

Registry impact

  • This PR does not modify any existing line under registry/

Checks

  • python -m unittest discover -s tests: 414 tests pass locally (8 new)
  • ruff check . passes
  • tools/validate_registry.py passes; nothing under registry/ or producers/ changes
  • Anchor format or verification semantics: unchanged
  • Commits are signed off (DCO)

Disclosure: I also reported #591 on trace-spec, and HORIZON SHIELD works on adjacent verification tooling. The witness key is in witness-key.json. Its private half never leaves the operator's machine.

Receipts from HORIZON SHIELD's registry-witness-v0 for both checkpoints at 555f27a, with an offline test. Checkpoint 2: witness_time_established and grade_cryptographically_bound are true.

Signed-off-by: Horizon <horizon@example.com>

@imran-siddique imran-siddique left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both receipts verify here: 7 of 7 checks each, output identical to verification-1.json and verification-2.json, and both checkpoints are byte-identical to line 1 of registry/2026/09/01.ndjson and 09/25.ndjson. 414 tests pass.

Three changes before merge. The witness key first appears in horizon-shield 65b0db6, 12 minutes before this PR, and the log holds only our two leaves, so the README should say that rather than "independent". The Bitcoin anchor has no proof in the packet: add it or drop the sentence. LIMITATIONS.md line 41 still says one checkpoint is witnessed.

Say how new the witness is instead of calling it independent; put the Bitcoin anchor in the packet (JIDEC entry 127 and its OpenTimestamps proof, block 972264) with an offline test; update LIMITATIONS.md for the second witness.

Signed-off-by: Horizon <horizon@example.com>
@ogasurfproject-jpg

Copy link
Copy Markdown
Contributor Author

@imran-siddique Thank you. All three are in 04f60f8:

  1. The README no longer says independent. It says the witness key first appears in horizon-shield 65b0db6, 12 minutes before this PR, that the witness log holds only these two leaves, and that the same operator runs a registered mirror.
    1. The anchor is in the packet: jidec-127.txt (JIDEC ledger entry 127, which names the first tree head's line SHA-256 and the witness key) and jidec-127.txt.ots, attested at Bitcoin block 972264 (merkle root 81b695d0..., 2026-10-20 05:09:57 UTC). A new offline test checks the line hash, that the record names it, and that the proof commits to the record's SHA-256. Checking the header itself needs a node or an explorer, and the README says so.
    1. LIMITATIONS.md now describes both packets and says only one of the two witnesses has a track record.
      tests/test_witness_receipt_nenrin.py: 9 passed; ruff check . clean.

@dinakarjs dinakarjs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rechecked 04f60f8. The packet now discloses the witness/key's short history and common mirror operator, contains the JIDEC entry and OTS file, and updates LIMITATIONS.md. Both receipts verify offline with the documented distinction between signed grade, signed witness time and registry continuity. Nine packet tests pass; the full unittest discovery and Ruff also exit successfully in a fresh Python 3.12.14 environment installed from the three CI locks. The full run emits socket ResourceWarnings; these are not counted as failures.

Evidence boundary: test_bitcoin_anchor_chain_offline checks the record/head hashes, OTS file-digest prefix and presence of an attestation tag/height. It does not deserialize/evaluate the complete OTS operation path or authenticate the Bitcoin header. I have not independently checked that header, so I am not certifying the stated mainnet upper-bound time. A useful follow-up is a parsed operation-chain check plus a corrupted-operation negative, with header authenticity still a separate external check. The original maintainer's evidence acceptance/re-review remains open; receipt verification is not a split-view-monitoring claim.

@ogasurfproject-jpg

Copy link
Copy Markdown
Contributor Author

@imran-siddique when you have time, could you take another look? Your three points from 20 October are all in 04f60f8:

  1. README: "independent" is gone from the packet. A new section says the witness key first appears in horizon-shield 65b0db6, 12 minutes before this PR, that the witness log holds only these two leaves, and that the same operator runs a registered mirror.
  2. Bitcoin anchor: the packet now carries jidec-127.txt and jidec-127.txt.ots. The proof attests at block 972264; its commitment equals that block's merkle root (81b695d0...) at blockstream.info. A new offline test checks the line hash, that the ledger entry names it, and that the proof commits to the entry's SHA-256.
  3. LIMITATIONS.md: the paragraph now reads "Two checkpoints have witness receipts; one witness has a track record", and describes the second witness as above.

@dinakarjs rechecked 04f60f8 on 21 October: #143 (review)

Copy link
Copy Markdown
Contributor

Completed the bounded operation-chain follow-up proposed in my review: dinakarjs#1. It is a one-commit author-adoption companion based on your exact 04f60f8 head, so it does not duplicate your upstream submission. Cherry-pick candidate: a973b0a.

Five new tests evaluate the captured SHA256/append/prepend operations and compare the resulting Bitcoin leaf with your reported root. A changed operand preserves the old digest/tag/height checks but changes the computed result. Full unittest discovery: 420 tests, OK; Ruff passes. Fixed-result, append-as-prepend and skip-hash mutations each cause two assertion failures, no errors. Small sibling-branch controls check the evaluator independently of this packet.

The helper is deliberately fixture-only, with bounded sizes/depth and unsupported operations refused. The README explicitly preserves the separate requirement to authenticate the Bitcoin header/chain; this is not independent confirmation of mainnet time. Please adopt if useful, or retain it as a follow-up after this packet is accepted. Your ownership and the original maintainer re-review remain unchanged.

@ogasurfproject-jpg

Copy link
Copy Markdown
Contributor Author

@dinakarjs thank you for a973b0a: the five tests pass here against the 04f60f8 packet, changing the expected root makes the root test fail, and the root it computes is the one the opentimestamps library and blockstream.info give us for block 972264. While Imran's re-review is in progress on 04f60f8 we will keep this PR's head unchanged, and we will take your commit in, with your authorship, as a follow-up once the packet is accepted.

@rajnisht7 rajnisht7 left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the earlier findings are addressed on 04f60f8, the README disclosure, the JIDEC/OTS files, and the LIMITATIONS update all look good.

however there is still one consistency issue:

docs/evidence/witness-2026-10-20-nenrin/jidec-127.txt still says HORIZON SHIELD “operates an independent witness” whereas updated README correctly states that nothing in the packet shows a track record or independence beyond a different operator and key, and LIMITATIONS.md was also updated accordingly. So the packet currently asserts both things at once.

This matters because jidec-127.txt is the exact document whose SHA-256 is committed by the OTS proof and listed in SHA256SUMS. The file itself also says it cannot be altered after anchoring and that corrections should be later entries. A simple wording edit would break the cryptographic linkage, so the characterisation needs to be reconciled in a way that preserves the anchor (e.g. a superseding JIDEC/OTS entry that cites this one, or another approach that keeps the packet internally consistent).

A couple of smaller notes (non blockers):

  • ROADMAP.md still treats a second operator / continuous witnessing as future work. Worth bringing it in line with the new packet once the above is fixed.

  • The offline Bitcoin test correctly checks the captured structure, commitment, tag and height, but does not evaluate the full OTS operation chain or authenticate the Bitcoin header. The README already documents that boundary, so this is fine as-is; the deeper operation-chain work can stay a follow-up.

…tness; ROADMAP names the second operator

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Horizon <horizon@example.com>
@ogasurfproject-jpg

Copy link
Copy Markdown
Contributor Author

@rajnisht7 thank you, that is a real inconsistency, and you are right that editing jidec-127.txt would break the anchor.

jidec-127.txt and its proof stay exactly as anchored. I have appended JIDEC entry 143 as a correction that cites entry 127 by title and claim SHA-256 (6d8ff0fb…). It replaces "operates an independent witness" with the README's wording: a second witness, a party other than the registry operator with its own key, with no track record or independence shown beyond that. Its proof is in the packet as jidec-143.txt and jidec-143.txt.ots (Bitcoin block 972850), and SHA256SUMS and the README now list both entries.

ROADMAP.md now says that a second operator has receipts for checkpoints 1 and 2, taken by hand, and that continuous submission and split-view monitoring remain open.

The offline Bitcoin test is unchanged, as you suggested; the full OTS operation chain stays a follow-up.

Commit: 7aec547

@rajnisht7 rajnisht7 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for addressing the issue, a couple of things still needs addressed:

  • jidec-143.txt says “stamped to Bitcoin block 972264”, but jidec-143.txt.ots actually attests block 972850 (confirmed with ots info). README also says 972850. Since the document is already anchored, this needs another append-only correction rather than editing the file.
  • test_bitcoin_anchor_chain_offline still only checks jidec-127.txt / .ots, it will be good to add the same offline structural checks for jidec-143 (SHA-256 matches manifest, OTS commits to that digest, expected attestation / height 972850). Full OTS chain validation can stay a follow-up.
  • ROADMAP still says receipt-bound witness time/grade is future work and that “the captured receipt authenticates a root, not the response’s grade or an observation time.” Checkpoint 2 in this packet has both grade_cryptographically_bound and witness_time_established true. LIMITATIONS already explains the distinction, kindly soften the ROADMAP wording so it doesn’t imply the capability doesn’t exist.
  • non-blocking: test_reported_grade_must_match_the_signed_one currently tests the opposite

@drk-ram drk-ram left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-checked the packet at 7aec5472d3398a9a505dc0e4550f0b22159cc779, including the OpenTimestamps proof bytes, not only the README.

Both receipts are in the shape tools/verify_witness_receipt.py accepts, and the limits in verification-1.json and verification-2.json match what this packet is allowed to claim. Grade is bound on both (mmr-verified). Witness time is established only on checkpoint 2 (signed_iat 1792467378). registry_continuity_established and full_checkpoint_envelope_witnessed stay false. Checkpoint 1's signing digest 41138372adb1921186ca6a0dbc3433a0ea2f6475cb863205603ab1231968f99a matches the September 7 packet. The disclosure that this key first appears in horizon-shield 65b0db6, that the log holds only these two leaves, and that the operator also runs a registered mirror, is the right disclosure. Under draft-durga-pquip-pqc-agentic-delegation-00 and TR-2026-05 (DOI: 10.5281/zenodo.23776217), two signatures are not a quorum, and a witness that also holds a mirror of the log is not a second failure domain for split-view detection. The packet says that. Do not let a later summary upgrade it.

The open defect is the correction anchor.

I decoded both proofs offline. jidec-127.txt.ots commits to 6d8ff0fbc1e2d3d0e3ef2e03b22be891c0cd380dba80d16153861894ec4ced67 and carries the Bitcoin attestation height varint e8ab3b (972264). jidec-143.txt.ots commits to 79837a3a2e557c34ec194f940ca2fd1f1934eb0874fed8b48d84738dde5b4eed and carries b2b03b (972850). Those match the README. This is a structural read of the proof bytes, not a Bitcoin-node confirmation of the block header. The line "stamped to Bitcoin block 972264" inside jidec-143.txt sits in the "what it corrects" block and names entry 127's stamp, which is 972264, not 143's own proof. I am not asking you to edit an anchored file to fix a misreading of that line. I am asking you to make the distinction machine-checked. A reader of this packet, including the previous review on this PR, already confused the two heights, and the test does nothing to stop a substituted correction proof.

tests/test_witness_receipt_nenrin.py test_bitcoin_anchor_chain_offline binds the tree-head line hash, entry 127's digest, and the 972264 varint. It never opens jidec-143.txt or jidec-143.txt.ots. A truncated or swapped correction proof still passes the suite this PR adds as the offline control. Extend that test the same way, still offline: SHA-256 of jidec-143.txt equals 79837a3a2e557c34ec194f940ca2fd1f1934eb0874fed8b48d84738dde5b4eed, the proof starts with the OpenTimestamps magic, version 1, hash op 0x08, the following 32 bytes are that digest, and the attestation payload contains b2b03b for height 972850. If the README is edited so that 972264 is explicitly entry 127's height and 972850 is explicitly entry 143's, regenerate SHA256SUMS for README.md in the same commit. Do not edit jidec-143.txt. It is the anchored record.

That is the change I need before this packet can be treated as checked evidence. The quorum boundary above is a limit to preserve, not a request to collect more witnesses in this PR.

…y (972264, 972850)

The offline tests now open jidec-143.txt and jidec-143.txt.ots: the record's SHA-256, the OpenTimestamps header and the digest after it, and exactly one Bitcoin attestation at 972850. The height named in the "What it corrects" block of jidec-143.txt must be the height of entry 127's proof, not entry 143's. A swapped, truncated or height-swapped correction proof fails. The README states each entry's height with its role, SHA256SUMS is regenerated for README.md and checked by a test. jidec-143.txt and both proofs are not edited. From the review of drk-ram on agentrust-io#143.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Horizon <horizon@example.com>
@ogasurfproject-jpg

Copy link
Copy Markdown
Contributor Author

@drk-ram Thank you. You are right: the suite never opened the correction's proof, and the two heights were easy to confuse. The changes are in d102bbd. jidec-143.txt and both proofs are not edited.

  1. test_bitcoin_anchor_chain_offline keeps its checks on entry 127. A new test_correction_anchor_offline does the same for entry 143: the SHA-256 of jidec-143.txt is 79837a3a2e557c34ec194f940ca2fd1f1934eb0874fed8b48d84738dde5b4eed, the proof starts with the OpenTimestamps magic, version 1 and hash op 0x08, the next 32 bytes are that digest, and the Bitcoin attestation payload is b2b03b (972850).
  2. test_the_two_heights_are_separate: each proof holds exactly one Bitcoin attestation, 972264 in jidec-127.txt.ots and 972850 in jidec-143.txt.ots. The only height named in jidec-143.txt sits in its "What it corrects" block next to entry 127's SHA-256, and the test requires it to equal the height of entry 127's proof and to differ from entry 143's. The README table must match both proofs.
  3. test_swapped_or_altered_correction_proof_rejected: these all fail the check: entry 127's proof in place of entry 143's and the reverse, entry 143 checked against 972264, entry 143's proof with b2b03b replaced by e8ab3b (its digest still matches), the proof truncated at three points, a second attestation appended, and an altered record.
  4. README: a new section, "Two anchors, two heights", gives each entry its role, record SHA-256, proof and height, and says that the 972264 line inside jidec-143.txt names entry 127's anchor. SHA256SUMS is regenerated for README.md in the same commit, and test_sha256sums_match_the_packet checks every line of it.

To check: python -m unittest discover -s tests -p test_witness_receipt_nenrin.py -v runs 13 tests. Copy jidec-127.txt.ots over jidec-143.txt.ots and four of them fail. At 7aec547 the nine tests still passed with that swap.

These are still structural reads of the proof bytes. The operation chain evaluation stays with the follow-up from dinakarjs, and the block header still needs a node or an explorer. The quorum boundary in the packet is unchanged.

@drk-ram drk-ram left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up verification of exact head d102bbd9e9190cf8aec1e8c51d530a947fed87f0, against my review of 7aec5472d3398a9a505dc0e4550f0b22159cc779.

The correction-anchor gap is closed. The follow-up changes only the packet README, its SHA256SUMS entry and tests/test_witness_receipt_nenrin.py. jidec-143.txt and both OpenTimestamps proofs are unchanged.

The new correction test opens entry 143's actual record and proof, requires SHA-256 79837a3a2e557c34ec194f940ca2fd1f1934eb0874fed8b48d84738dde5b4eed, checks the OpenTimestamps magic, version 1 and SHA-256 hash opcode 0x08, and binds the following 32 bytes to that record digest. Its Bitcoin attestation is required to be exactly height 972850 (b2b03b). Entry 127 retains its separate digest and 972264 (e8ab3b) control.

test_the_two_heights_are_separate also binds the README table to both proofs and checks that the 972264 line in entry 143's “What it corrects” block identifies entry 127's anchor, not entry 143's own proof. The checksum test covers the complete packet inventory, including the updated README.

Local verification on the reviewed head:

  • python -m unittest discover -s tests -p test_witness_receipt_nenrin.py -v: 13 passed.
  • Independently substituted entry 127's proof for entry 143's through an in-memory file-read override: 4 tests failed, 0 errors, specifically the correction-anchor, separate-heights, altered-proof and packet-checksum tests. The genuine bytes pass all thirteen.
  • git diff --check 7aec5472..HEAD: passed.

The negative controls also reject a changed attestation height with the original digest intact, truncation, duplicate attestations and an altered record. This is the machine-checked distinction I requested, without rewriting the anchored correction.

The approval is limited to this packet and its stated checks. These remain structural proof-byte reads, not full OpenTimestamps operation-chain evaluation or Bitcoin block-header confirmation. The packet still does not establish registry continuity, a full-envelope witness or an independent witness quorum; the mirror/operator disclosure remains material.

Approving this exact head.

This branch has not been deployed

No deployments
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.

5 participants