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.
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.
| Field | Meaning |
|---|---|
schema | avow.receipt/v1 |
payload | Your JSON record, in plain text |
payload_hash | SHA-256 of the RFC 8785 canonical payload |
public_key | Ed25519 public key that signed it |
signature | 64-byte Ed25519 signature |
{
"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
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)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.pubRead and write receipts
import { verifySignature } from "@gainratio/avow";
await verifySignature(receipt, pinnedPublicKey);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.