Skip to main content

sdcreceipt

Verify and settle VSL Settlement Receipts.

Verification needs no account, no network, and nothing from the issuer. That is the point of the tool: a claim that anyone can check a Receipt independently is worth exactly as much as the ability to do it.

Apache-2.0.

pip install sdcreceipt

Three verbs

# Check a Receipt you were sent. Offline.
sdcreceipt verify receipt.json --keys issuer-keys.json

# Set yourself up as a party: keypair + the document to publish.
sdcreceipt init --key-id https://vendor.example/.well-known/vsl-key.json

# Authorize a settlement you are a party to.
sdcreceipt trigger receipt.json --key vsl-party.pem \
    --key-id https://vendor.example/.well-known/vsl-key.json

verify exits 0 only if every check passed, so it composes in a shell without anyone parsing output.

There will not be a fourth verb. This is a client, not a product, and its value is in being small enough to read.


If you were sent a Receipt

You do not need an account with anyone.

pip install sdcreceipt
curl -O https://sdcstudio.axius-sdc.com/.well-known/sdcstudio-signing-keys.json
sdcreceipt verify receipt.json --keys sdcstudio-signing-keys.json

Every check is reported, not just the first failure:

PASS  schema: conforms
PASS  receipt_hash: matches the canonical content
PASS  signature[sdcstudio-signing-key-v1]: verifies over receipt_hash
PASS  trigger[https://vendor.example/.well-known/vsl-key.json]: verifies
PASS  settlement.complete: every listed party has triggered

VERIFIED

A Receipt carries hash commitments, never the payload. So verification tells you a conformant, authorized, dual-triggered exchange occurred, without anyone having to disclose what was exchanged. If you also hold the payload or the governance Receipt, pass them and those get checked too:

sdcreceipt verify receipt.json --keys keys.json \
    --payload manifest.xml --governance governance-receipt.json

If you need to become a party

A settlement identifies each party by a key_id that you control. That is deliberate: it means verifying your signature does not route through the issuer, so nobody has to stay alive for your old signatures to keep meaning something.

sdcreceipt init --key-id https://vendor.example/.well-known/vsl-key.json

That writes a private key (mode 0600) and a key document, and tells you the exact URL the document must be reachable at. Publishing one JSON file is the whole onboarding requirement.

Then, when you are sent a Receipt to authorize:

sdcreceipt trigger receipt.json --key vsl-party.pem --key-id <your key_id>

It prints a signed trigger and stops. Signing is inert; submitting is a side effect, so you send it yourself, or add --submit <url>.


★ Never take the verification key from the document

The set of keys you will accept is decided before you read the document, and the document cannot change it.

ds:RetrievalMethod in XML-Signature, jku and x5u in JOSE, and their equivalents elsewhere all say "here is where my key lives." That pointer was written by whoever produced the document, so following it asks the document to nominate the key that will judge it. A forged document nominates the forger's key and verification "succeeds."

The failure is quiet. A pointer can name a domain that was correct when the document was signed and has since lapsed; anyone who registers it can serve a key at that path, and nothing about the document looks wrong — because nothing about it is wrong. The verifier was asked where to look and did as it was told.

This tool cannot make that mistake: verify takes keys as arguments and has no code path that fetches one. That is a security property, not an inconvenience.

The same applies to party keys, with a corollary rather than an exemption. Those key_ids are URIs the counterparty controls, deliberately. Resolve them over HTTPS only, only for identifiers already recorded in a Receipt you trust, and keep a copy — a party who later loses a domain must not be able to change what their old signatures mean.


Conformance

tests/conformance/ ships the issuer's published vectors, and the suite runs this implementation against them.

Ten vectors. Every invalid one encodes a defect that was actually made, not a hypothetical: a DER signature where ES256 requires P1363, a signature over the hex text of receipt_hash rather than its raw bytes, a governance binding that does not match the evidence held, a trigger replayed from another Receipt sharing the same release condition, and so on. Failing one for the wrong reason does not count — the manifest names the check that must break.

pytest

On independence, honestly. Passing these vectors shows this tool agrees with the issuer's published expectations, and that it never drifted from them. It is not an independent re-derivation: this implementation and the issuer's share design and history. The vectors are most valuable to someone writing a verifier from the specification alone, which is what they are published for.

Building your own

You do not have to use this tool, and the specification does not depend on it. If you are writing a verifier:

Do not write a second canonicalizer. Use sdcgovernance or another conformant RFC 8785 implementation. A second implementation can disagree with the first, and the disagreement is silent: the bytes differ, so the hash differs, and the artifact reads as tampered with rather than misencoded. This tool re-exports sdcgovernance.jcs for exactly that reason and adds nothing.

Refuse rather than guess. Integers beyond ±(2⁵³−1) cannot round-trip through an IEEE 754 double, and NaN/Infinity have no JSON representation. Emitting something for those produces a hash that looks fine and fails only in someone else's verifier.

Report every check. Stopping at the first failure hides the case that matters most: a Receipt whose signature verifies but whose governance binding does not.

Check the curve. A signature verified against a key on an unexpected curve proves nothing about the party you believe signed.

Versioning

MAJOR tracks the SDC reference model, so a 4.x.x release targets SDC4. It starts at 4 rather than 0 because of that convention, not because there were three earlier versions. MINOR is features, PATCH is fixes. An SDC5 reference model would make this 5.x.x.

The same scheme is used by sdcvalidator, sdcgovernance and the rest of the family, so a version number tells you which reference model an artifact targets without looking anything up.

Note that the Receipt format version is separate and independent: a Receipt says "version": "1.0", which is the frozen wire format, not this package.

Dependencies

sdcgovernance for canonicalization and cryptography for ECDSA, both Apache-2.0-compatible libraries. jsonschema is optional and only needed for --schema.

These are library dependencies. Nothing here calls a service, and verify makes no network request at all.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sdcreceipt-4.0.0.tar.gz (22.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sdcreceipt-4.0.0-py3-none-any.whl (19.4 kB view details)

Uploaded Python 3

File details

Details for the file sdcreceipt-4.0.0.tar.gz.

File metadata

  • Download URL: sdcreceipt-4.0.0.tar.gz
  • Upload date:
  • Size: 22.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for sdcreceipt-4.0.0.tar.gz
Algorithm Hash digest
SHA256 8649505bd0aba323e6c2cd1978945f11e9865e55d059eb60a3a9e9910f35e60f
MD5 c6a269a5f02c70c8a97fab3793f5debf
BLAKE2b-256 acf2e62e9defe0feeac27acb9cddb9580b837189bee026defa5cf6bb2cb0c489

See more details on using hashes here.

Provenance

The following attestation bundles were made for sdcreceipt-4.0.0.tar.gz:

Publisher: release.yml on SemanticDataCharter/sdcreceipt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sdcreceipt-4.0.0-py3-none-any.whl.

File metadata

  • Download URL: sdcreceipt-4.0.0-py3-none-any.whl
  • Upload date:
  • Size: 19.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for sdcreceipt-4.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 156e6f7da7e57f9b78363ac9710880c08bd0c3f38fc7cc109e48218d4b7c40b0
MD5 35e5a47216c17692fc621891853c6fa0
BLAKE2b-256 367a20dcf1c4d86517457f28ab19185b2a6fa3a3b4e52cb2e9e63fabb7254690

See more details on using hashes here.

Provenance

The following attestation bundles were made for sdcreceipt-4.0.0-py3-none-any.whl:

Publisher: release.yml on SemanticDataCharter/sdcreceipt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

4.2.1

2 files

4.2.0

2 files

4.0.1

2 files

This release

4.0.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page