Credential claim
Scope
A claim is the statement a professional makes about a credential they hold. This document defines the fields, the canonical form, the identifier and the signature. It does not define how a claim is stored, served or found, because the identifier is a digest and the document is therefore location independent.
The document
{
"rvw": 1,
"subject": "0xa805a67f59cccc9869d5dcb4ffc02fc697b5819d",
"trade": "real-estate-agent",
"jurisdiction": "AU-QLD",
"authority": "au-qld-fair-trading",
"licence": "4102938",
"legal_name": "Northpier Property Pty Ltd",
"domain": "northpier.example",
"register": "https://register.example.qld.gov.au/licence/4102938",
"issued": "2026-11-09T00:00:00Z",
"expires": "2027-05-09T00:00:00Z"
}Values are UTF-8 strings or integers. Floating point numbers are not allowed anywhere in a claim, which is what makes canonicalisation trivial and identical in every language.
Fields
| Field | Required | Meaning |
|---|---|---|
| rvw | Yes | Document type. Always the integer 1 for a claim. |
| subject | Yes | The identity key making the statement, as a lowercase hex address. |
| trade | Yes | A lowercase trade identifier such as real-estate-agent or conveyancer. Free text, matched by consumers, not policed here. |
| jurisdiction | Yes | ISO 3166 country, optionally with a subdivision, such as AU-QLD or GB-SCT. |
| authority | Yes | An identifier for the issuing body. See the limits in section 8. |
| licence | Yes | The licence reference exactly as the authority writes it, including letters and leading zeros. |
| legal_name | Yes | The registered name the licence is held under. |
| domain | No | The business domain used for the binding in RVW-2. Omit it if there is none. |
| register | No | A stable public address where this licence can be looked up, if one exists. |
| issued | Yes | RFC 3339 UTC. Not in the future. |
| expires | Yes | RFC 3339 UTC. At most twelve months after issued. |
Unknown fields are preserved and included in the digest. A consumer ignores what it does not understand, and never drops a field before hashing.
Fields deliberately absent: identity document numbers, personal addresses, phone numbers, dates of birth, anything held by a human and not by a business. Rule five.
Canonical form
Object keys sorted by Unicode code point, recursively. No whitespace outside strings. UTF-8. No floats. That is the whole definition, and it is what the standard shell tools already produce:
jq -cS . claim.json | tr -d '\n' | shasum -a 256{"authority":"au-qld-fair-trading","domain":"northpier.example",
"expires":"2027-05-09T00:00:00Z","issued":"2026-11-09T00:00:00Z","jurisdiction":"AU-QLD",
"legal_name":"Northpier Property Pty Ltd","licence":"4102938",
"register":"https://register.example.qld.gov.au/licence/4102938","rvw":1,
"subject":"0xa805a67f59cccc9869d5dcb4ffc02fc697b5819d","trade":"real-estate-agent"}
(one line of 371 characters, wrapped here only to fit)Identifier
The claim identifier is the SHA-256 of the canonical bytes, lowercase hex. SHA-256 rather than keccak because every language, every shell and every government IT department already has it, and a person checking this by hand should not have to install anything.
claimId = fba0fc855026ba9758a1bbb2a41b3a4a5ebe54be5aca29b07c034d5c0e04ae10That digest is the real digest of the document in section 2. The tool on the verify page reproduces it in the browser, and the shell command above reproduces it on your machine.
Signature
The subject signs EIP-712 typed data over the identifier and the window. The document itself is not signed directly, so a signature can be carried without the document and still bind to it.
EIP-712 typed data
domain = {
name: "Revow",
version: "1",
chainId: 1
}
Claim(
bytes32 claimId,
uint64 issuedAt,
uint64 expiresAt
)
claimId = sha256(canonical claim document)
issuedAt = the issued field, as a unix timestamp
expiresAt = the expires field, as a unix timestamp
For the document above, signed by the subject key:
digest = 0x16553507701ee06320612aa0913000d308a55c7d20197997f247a214e3511f87
signature = 0xfc53b87067d4e4fdfbfadff6746d2992ced057c21305884402e41877f38c8c393e
e58c490a53c338e03ac954fe55902bd7fcc087fde965d6d0560199466ff3141cNo verifyingContract is set, because a claim is not bound to a deployment. A consumer that recovers an address other than the subject rejects the claim outright.
Publication
A claim document and its signature are published wherever the subject chooses: their own domain, a payment page, an object store, a content addressed network, an email attachment. The digest is the name, so the location carries no authority and may change at any time.
What a claim does not prove, and known weaknesses
A claim proves that a key made a statement. It proves nothing about the licence. A fraudster can sign a claim quoting a real licence number in under a minute, and the only thing standing between that claim and a reader is the evidence layered on top of it.
The authority field is the weakest part of this document. There is no global naming of issuing bodies, and a lab-maintained list would make Revow a namespace operator, which rule four forbids. The current answer is that consumers match on jurisdiction and trade and treat authority as a hint. This is open problem OP-5 and it is not solved.