Skip to content

Write an independent receipt verifier in a language that isn't Python #119

Description

@bkd-dotcom

What this is

A Signetry remediation receipt is a signed record of what an AI agent was allowed to
change and what evidence gated it. The whole point is that a receipt outlives the tool that
issued it — an auditor in 2032 should be able to verify a receipt written in 2026 without
licensing anything from us.

So the spec and its conformance suite are Apache-2.0, carved out of this repository's
BUSL-1.1 licence on purpose
:

Writing a competing issuer or an independent verifier against this spec is a supported
use, not a tolerated one.

Today there is exactly one verifier and we wrote it. That's a weak claim. A second
implementation, in a language that isn't Python, is what turns "the format is portable" from
an assertion into a fact.

The deliverable

A standalone verifier — Go, Rust, TypeScript, Java, C#, Ruby, anything — that reads a receipt
JSON on stdin or as an argument, plus a pinned public key, and exits non-zero when the receipt
should be refused.

It lives in your own repository under your own licence. Nothing to vendor here. The PR to
this repo is one row added to an ## Independent implementations table in
tests/conformance/README.md
(create the section if you're first): language, link, which vectors pass.

It's verifiable from day one — the vectors are committed and the keys are published

key_A seed = SHA-256("signetry-conformance-vector-key-A")   # 32 raw bytes
key_B seed = SHA-256("signetry-conformance-vector-key-B")

Public on purpose. They are test keys — never sign anything real with them. Every vector
carries an expect block and a _note saying what it proves, so you can develop against the
files without asking anyone anything.

Two vectors are the whole exercise

An implementation that only checks cryptography passes most of the suite and fails these two.
They're where the format's guarantees actually live:

Vector Why it's hard
resigned-other-key.json A self-consistent envelope signed with the attacker's own keypair, embedded public key swapped to match. Every internal check passes. It must still fail against the pinned key. Verifying a signature against the key carried inside the same document is a no-op — the attacker supplies both halves.
auto-merge-true.json A correctly signed receipt claiming auto_merge: true is non-conforming. Signature validity and format conformance are separate questions, and "Signetry never merges on its own judgement" is only a checkable property if the verifier actually checks it.

Two more that catch the same instinct: no-canonical-hash.json (a genuine signature with the
hash stripped is not verified — absence of evidence is not evidence) and
ephemeral-no-pinned-key.json (a dev-key receipt with no key to pin against must be
refused, not reported green).

And canonicalization.json will bite you early: canonical bytes are recursive-key-sorted, no
whitespace, raw Unicode. The usual failure is a serializer that escapes non-ASCII by
default — Python's json.dumps does, hence ensure_ascii=False. Whatever your language does
by default, check it.

Acceptance criteria

  • Runs standalone: receipt in, exit code out. No dependency on signetry-core.
  • All 8 vectors in tests/conformance/vectors/ produce the outcome their expect block
    states — including refusing resigned-other-key.json and rejecting
    auto-merge-true.json as non-conforming.
  • Reproduces canonicalization.json's expected bytes exactly.
  • Your repo's README shows the command and the 8 results.
  • PR here adding your row to ## Independent implementations in
    tests/conformance/README.md.

If a vector is ambiguous, that's a spec bug and I want to hear it

If you can read §8.1
or §9
two ways, open an issue instead of guessing. A second implementer finding the spec unclear is
the most valuable bug report this repo can receive — that's what a second implementation is
for.

Comment with the language you're taking so two people don't build the same one.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or requesthelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions