Open source · Python + TypeScript · MIT

Receipts anyone can check offline.

Avow turns a JSON record into a small signed file. Give the checker your public key once. They can confirm the record is unchanged — and who signed it — on their own machine, without a server, an account, or a network connection.

Verify a real receipt in this page

The receipt below is the example from the Avow README. “Verify” runs Ed25519 verification and the SHA-256 fingerprint check in your browser. “Tamper” changes one value and verifies again. No data leaves this page.

  • Public key and signature are embedded in the receipt.
  • The payload is canonicalised with RFC 8785 before it is checked.
  • A changed byte changes the hash and the signature check fails.

Read the implementation before trusting the demo.

avow.receipt/v1browser verifier

Press “Verify receipt” to check the signature.

A checksum is not a signature

Teams often have to show later what they decided: that a release was approved, that tests passed, that a setting was what they say it was. Usually that record sits in a database or a log the team controls. An auditor, customer, or regulator has to take their word that nobody edited it.

A plain checksum does not fix that. Anyone who can change the record can recompute the checksum too. Avow gives the record a signature, so verification needs only a public key that was handed out ahead of time.

Try it in four commands

Python 3.12 or newer. Install the CLI extra, create a key, sign a record, and verify it.

pip install "avow[cli]>=0.5.1"

avow keygen --out signing.key
echo '{"release": "checkout-api 2.4.1", "approved_by": "dana", "tests_passed": true}' > decision.json
avow sign --payload decision.json --key signing.key --out receipt.json
avow verify --receipt receipt.json --public-key signing.key.pub
avow.keygen.ok
avow.sign.ok
avow.verify.ok

Then change the approver and verify again:

sed 's/dana/mallory/' receipt.json > tampered.json
avow verify --receipt tampered.json --public-key signing.key.pub
echo "exit code: $?"
avow.payload_hash_mismatch
exit code: 2

What is inside a receipt

A receipt is ordinary JSON. The payload stays readable; the signature proves it has not changed.

FieldMeaning
schemaavow.receipt/v1
payloadYour JSON record, in plain text
payload_hashSHA-256 of the RFC 8785 canonical payload
public_keyEd25519 public key that signed it
signature64-byte Ed25519 signature
Receipts are not encrypted. If the record contains a secret, encrypt or redact it before signing. Avow proves integrity and signer identity, not confidentiality.
{
  "schema": "avow.receipt/v1",
  "payload": {
    "approved_by": "dana",
    "release": "checkout-api 2.4.1",
    "tests_passed": true
  },
  "payload_hash": "sha256:64a25947…",
  "public_key": "47c7e147…",
  "signature": "20e8b0a7…"
}

Why canonical JSON?

Two JSON documents can mean the same thing but have different whitespace or key order. RFC 8785 (JCS) defines one canonical byte sequence, so the signature is stable across languages and implementations.

Python and TypeScript, same receipts

PYTHON

Library

from avow import generate_signing_key, public_key_hex, sign_payload, verify_receipt

private_key = generate_signing_key()
public_key = public_key_hex(private_key)
receipt = sign_payload({"decision": "approved"}, private_key)
verify_receipt(receipt, expected_public_key=public_key)

Python examples

CLI

Keygen, sign, verify

avow keygen --out signing.key
avow sign --payload decision.json \
  --key signing.key --out receipt.json
avow verify --receipt receipt.json \
  --public-key signing.key.pub

CLI reference

TYPESCRIPT

Read and write receipts

import { verifySignature } from "@gainratio/avow";

await verifySignature(receipt, pinnedPublicKey);

TypeScript examples

What Avow does not do

Not a timestamp authority

The receipt proves who signed a record and that it has not changed. It does not independently prove when it was signed.

Not encryption

The payload is plain text. Use encryption or redaction first if the record is confidential.

Not key management

You generate and distribute keys. Losing a private key means you cannot sign new receipts with it; losing a public key means verifiers cannot check.

Questions

Do verifiers need to install Avow?

The CLI and Python library can verify locally. The receipt format is documented, so an independent implementation can verify with the same Ed25519 and RFC 8785 rules.

What happens if one value changes?

The canonical payload hash changes, so avow verify exits with avow.payload_hash_mismatch (exit code 2). A valid signature over a different payload still fails the expected hash.

Can I verify with someone else’s key?

Yes. Verification takes the expected public key. A receipt signed by a different key is refused with avow.signer_mismatch.

Which Python versions are supported?

Python 3.12 or newer for the CLI and library. The TypeScript package targets Node 22.13+ and browsers.

Is Avow a compliance product?

No. It is an open-source integrity primitive. It can support an audit workflow, but it does not by itself make a process compliant.