Skip to content
autonym.dev
ContentsHide contents

Conformance

Test vectors

spec 1.0-draft-1

Status: informative. Document version 1.0-draft-1. Every file in this folder except this page is generated by the reference implementation, and its build fails if any differs from what the code produces. Do not edit them by hand.

These vectors let an implementation check, offline and without an Autonym account, that it canonicalises, signs and verifies the A5.4 signed objects exactly as the specification requires: disclosures (A5.3), receipts (A9), purge instructions and acknowledgements (A10).

The keys are synthetic and published with their private parts. They were generated for these vectors and the media worked example only, belong to no provider or recipient, and must never be trusted anywhere else. Anyone can sign anything with them, so a signature they verify proves nothing outside these tests.

Files

File What it proves Checks
keys.json Two provider keys, one retired with exp, and one recipient key, each with its private part. key_sets gives their public parts as the provider's and the recipient's key sets, the form key-set.json defines; the retired key stays in the set with its exp. Each kid is the RFC 7638 thumbprint KEY-01
jcs.json RFC 8785 canonical JSON: member names sorted by their 16-bit code units, characters outside ASCII, escapes, integers and the number form, each with the exact canonical text, its UTF-8 in hexadecimal and its SHA-256; and inputs strict parsing refuses, including numbers beyond what binary64 holds SIGN-01
disclosure.json Signed disclosures: one signed by the active provider key, one signed by the later-retired key before its exp, and the edge of the 60-second clock allowance SIGN-01, KEY-01
receipt.json A receipt hash chain across a key rotation, each receipt with its provider, the canonical request derived from the request as received, the hash of the disclosure it records and its hash input. Both verify a year later from the provider's published key set alone SIGN-01, LOG-01, LOG-02, KEY-01
purge.json The purge instruction token, a compact JWT signed by the provider, and the recipient's signed acknowledgement over its canonical JSON SIGN-01, PURGE-01
negative.json Signed objects a verifier must reject, each breaking one A5.4 rule: tampering, duplicate members, numbers and strings that are not I-JSON, alg:none and HS256, unknown and ambiguous key IDs, crit and other header members, wrong typ, unusable keys, retired keys, expiry, time bounds, issuer binding and receipt hashes SIGN-01, KEY-01, LOG-01, LOG-02, PURGE-01

Using a vector

A detached-signature vector gives typ, the exact received text (the object with its proof), and verify: the key set (a name from key_sets in keys.json, or an inline key set when the vector needs one that key-set.json refuses), the trusted issuer and the verifier's clock reading now. Verify text as A5.4 describes and compare the outcome with expected: either valid: true with the kid and the signed time, or valid: false with a reason.

A positive vector also shows each step: the object without proof (unsigned), its canonical text (jcs) and that text's SHA-256, the protected_header and the detached jws. A receipt vector adds its hash input and chain link, its request as received with its canonical form, and the disclosure whose hash it records.

The purge instruction token is stored as its three parts in the RFC 7515 flattened JSON form; a recipient receives protected.payload.signature. Verify it at its iat with the provider's key set: the header has exactly alg, kid and typ:autonym-purge+jwt, and the payload is claims.

The reasons in negative.json and jcs.json are labels for the rule each vector breaks. An implementation need not use them; it must reject every negative vector.

Reason A5.4 rule
duplicate_member, not_i_json, malformed_json Parse strictly before canonicalisation: repeated member names, in the object or its protected header; text that is not I-JSON; text that is not JSON
malformed_proof The proof member and the detached JWS: unpadded base64url in its one canonical spelling
critical_header, header No protected header member other than alg, kid and typ; crit named separately
algorithm Only ES256
type typ compared exactly
header_mismatch Proof metadata agrees with the protected header
unknown_key, key_id Exactly one trusted key has the header's kid, and the kid is its key's thumbprint
key The matching key follows key-set.json: no private member, no key_ops, no lifetime member other than exp, canonical spellings
signature The ES256 signature over the canonical bytes; RFC 7518 section 3.4 makes it exactly 64 bytes
retired The signed time is before the key's exp
issuer The object's provider is the trusted issuer
hash A receipt's hash is the A9 hash of its content
time_bounds, not_yet_valid, expired A disclosure's deadline, issue time and expiry

A verifier may also refuse a member named __proto__; no vector depends on whether it does.

What is not covered

The vectors cover canonical JSON and the signed objects listed above. They do not cover the signed export (A11.1), whose receipts are represented here only by the carried receipt in negative.json, the optional encrypted export (A11.2), purge-token rejections, or anything a provider must do at run time, such as checking current grant authority.

Stability

The files change only deliberately. Regenerating them reproduces the same bytes: the keys are kept, and because ES256 signatures are randomised, each signature is kept while it still verifies over its object, so only a change to a signed object signs it afresh. The reference implementation's tests pin each file's SHA-256, so a vector changes only by a deliberate edit. An implementation identifies the bytes it tested against by their digests in the edition manifest, and any change to a vector is recorded in the change history.

The reference implementation verifies every vector with its own verifier and, independently, with Python's jwcrypto and rfc8785 packages, reading only these files.

Checking the files

Every file of the test vectors, as published in edition 1.0-draft-1. Download them without changing them: the edition manifest identifies each file by its SHA-256, so a reformatted, minified or re-encoded copy is a different file.

File Bytes SHA-256
disclosure.json 22575 1a319ac2ba86f7ffc0725e0e7790552fff083d5c53c7a73dc23e39805ee9f765
jcs.json 11872 0e6966918b3aa47a43672f36dd43c3b638f987738f9d0117a770c669847490de
keys.json 3849 ee56df0c7b3033beba0a5e8a726ff636fee91f0ad1333701c98909a6a85bb835
negative.json 87309 883f90b639fd77925f006f88a7d6e3b053bb3b8a0a3008fd15b50e472c20ea39
purge.json 4386 452a0b7c1519094f99ba8a3d41c0a38f0c07df2f94d6df4dab74ff5946c0cac5
receipt.json 12731 a7b95204207f9cbfb45430a83092e4822dd43eca1e5b5ef4941d14f0eff62cee

To fetch them and check every digest against the edition manifest, with curl, jq and sha256sum:

bash
base=https://autonym.dev/downloads/autonym-standard/1.0-draft-1
for f in disclosure jcs keys negative purge receipt; do curl -sfO "$base/conformance/vectors/$f.json"; done
curl -sf "$base/manifest.json" | jq -r '.files[] | select(.path | test("^conformance/vectors/[^/]+\\.json$")) | "\(.sha256)  \(.path | ltrimstr("conformance/vectors/"))"' | sha256sum -c

Each file should print OK. Then verify every vector with your own JOSE and RFC 8785 implementation, as using a vector describes: each positive vector verifies with the key ID and signed time it gives, and each negative vector is rejected. The independent verifier described above ships with the reference implementation, which is not released yet, so it is not published here.

References to other standards and projects describe intended technical alignment only and do not imply endorsement or partnership.