Verify a Receipt Without Asqav
A receipt that only its issuer can validate is self-attestation. This page walks a security reviewer through checking Asqav's verification stack on their own machine: the published open-source verifier, the public conformance vectors, and the tamper checks. None of it needs an Asqav account, an API key, or a call to Asqav. Plan on about ten minutes.
The point of the exercise is durability. Receipts conform to an open specification submitted to the IETF (draft-marques-asqav-compliance-receipts), the verifier is MIT-licensed in the public asqav-sdk repository, and the expected verdict for every test vector is pinned in that same repository. Evidence you hold today verifies with or without Asqav.
What you need
- Python 3.10 or newer
git- No Asqav account
Step 1: install the published verifier
pip install "asqav[verify]"
The verify extra pulls two dependencies: dilithium-py, a pure-Python implementation of ML-DSA (NIST FIPS 204) whose verify path uses only standard-library SHAKE, and cryptography for the Ed25519 formats. Nothing compiles. The verifier itself ships inside the package at asqav/verifier/, so you can read every line of what you are about to run.
Step 2: fetch the open conformance corpus
git clone https://github.com/jagmarques/asqav-sdk
The corpus lives at asqav-sdk/verifier/conformance-vectors/: 44 vectors across five receipt formats (asqav-native, ACTA, AERF, AgentReceipts, AuthProof). It includes valid receipts, forged signatures, tampered payloads, and broken chain links. Each vector directory carries the receipt under test, its key material, and an expected.json naming the verdict the verifier must produce.
Step 3: run the whole corpus
ASQAV_CONFORMANCE_VECTORS=asqav-sdk/verifier/conformance-vectors \
python -m asqav.verifier.oracle.runner
The runner prints one line per vector and asserts that the actual verdict matches the expected one:
[ ok] asqav-01-genesis-permit expect=PASS got=PASS
[ ok] asqav-04-tamper-sig expect=FAIL got=FAIL
...
=> 44/44 vectors matched expected outcome
Exit code 0 means every vector matched. 23 of the 44 vectors expect FAIL; a verifier that waves everything through cannot pass this corpus.
Step 4: verify one receipt by hand
cd asqav-sdk/verifier/conformance-vectors
python -m asqav.verifier.oracle asqav-01-genesis-permit/receipt.json \
--keys asqav-01-genesis-permit/jwks.json
The output is a JSON report with a per-axis breakdown (structure, signature, chain) and an overall verdict of PASS. The signature axis is the one that carries third-party trust: the tool reproduces the canonical bytes, resolves the public key from the key file you passed, and runs the signature math locally.
Step 5: prove it rejects tampering
Do not take the FAIL vectors on faith. Open asqav-01-genesis-permit/receipt.json, flip payload.decision from allow to deny, and rerun the command from step 4. The verdict drops to FAIL and the signature axis reports the mismatch, because the bytes you edited are not the bytes that were signed.
The corpus pins the same behaviour with dedicated vectors (asqav-04-tamper-sig, authproof-02-forged-sig, aerf-04-tamper-chain, and others). This step lets you reproduce it with your own hands instead.
What this proves, and what it does not
Running the corpus on your machine proves:
- the receipt format is verifiable from published material alone: the specification, the verifier source, and the key files are all public;
- the verifier rejects forged signatures, tampered payloads, and broken chain links, and the expected verdicts are pinned in the open repository rather than asserted in prose;
- the verifier never reports PASS without actually verifying a signature. One vector in the corpus (
asqav-05-hash-mode-prod, a real production ML-DSA-65 receipt) expects INCOMPLETE when the post-quantum dependency is absent, pinning that the tool downgrades instead of false-passing.
It does not, on its own, verify a receipt from your production account. For that, see independent verification: the asqav audit-pack export bundle ships your receipts in the same canonical envelope, with the verify key and anchor certificate material, so the procedure above scales to your own evidence.
Where everything lives
- Verifier source:
python/src/asqav/verifier/in theasqav-sdkrepository (MIT license) - Conformance vectors:
verifier/conformance-vectors/ - Receipt specification: draft-marques-asqav-compliance-receipts on the IETF Datatracker
- Public verify keys:
GET /.well-known/jwks.json
See independent verification for verifying your own production receipts offline, and the security page for how Asqav holds keys and what the cloud stores.