veil

Verify a card independently

Check a card’s signed versions, its place in the log’s index and the witnesses behind the log.

A lookup or summary helps you find the card. Fetch the full card to get its proof. The normal card page and the widget already perform these checks in the reader’s browser. An integration that displays its own verified verdict needs to check the proof itself.

Read format in GET /v1/log before choosing the checks. The live log, log.veil.rip/staging-1, is in format 2, and a format 2 log also names the Veil organisation in staffOrg. Format 1 is frozen on log.veil.rip/test-1: it stays readable and takes no new versions.

Format 2: the index path#

A format 2 card brings what these checks need: proof for the current version, index for the card’s index bundle, authority for the versions that change who can sign, and current with the current label, body and signature. The work does not grow with the length of the card’s history.

  1. Check the checkpoint in index.checkpoint.note: the log signature, the witness quorum from your trusted policy and its freshness. proof and index refer to that same checkpoint.
  2. Verify index.entry, the checkpoint’s last index entry, with its inclusion proof. Check index.value against that entry’s root with index.proof, then apply the entries of index.tail that concern this card.
  3. Check each item of authority from its log entry alone: its inclusion at position i, its label hash against the c that index.value.auth gives, and its signature by a key of the authority before it. Version 1 gives the card ID. Follow authorityNext until it is null.
  4. Check current: its label hash is the one in index.value.latest, a key of the authority in force signed it, the state shown has the root in its label, and the keys match the authority.
  5. For an organisation, check the member that label.signer names in each authority version and in the current one. That member held the role and signed with an active key of their own card at that log position.
  6. Check the staff statements in index.statements. The first is index.value.standing, each prev is the i of the next, and each one is signed by a member of the Veil organisation whose role allows its action. Read more pages from statementsNext until it is null.
  7. A closed card answers 410 with closed. Show it as closed only when that closing entry verifies.
text
veil-rubrica:identity-version:v2
<canonical label>

veil-rubrica:statement-entry:v2
<canonical entry without signature>

veil-rubrica:close-entry:v2
<canonical entry without signature>

Keep the token, the ID, the last verified version and its authority. On the next visit, reject an index that points to an older version or that changes authority versions you already verified. A full check reads every version from GET /v1/identities/{n}/versions, starting at version 1, and verifies each body, signature and operation without the index.

A composite signature requires both Ed25519 and ML-DSA-65 to verify. Check freshness using enough valid witness signatures to satisfy the quorum. A stale quorum can prove history while leaving the current state uncertain.

Format 1 on test-1#

These steps apply only to a card served by a log in format 1, today the frozen log.veil.rip/test-1. Reject a format 1 card when GET /v1/log says format 2.

  1. Verify the record signature over the identity-version prefix followed by the exact proof.record bytes.
  2. Recompute SHA-256 over salt and record. It must equal proof.commitment. For version 1 it also determines the card ID and fingerprint.
  3. Check that proof.entry commits to this card’s token and commitment. Recompute the RFC 6962 leaf hash and follow the inclusion proof to the checkpoint root.
  4. Check the log signature against its expected key and require the witness quorum from your trusted policy. Count each witness key once.
  5. Verify the version chain, including prev, signing-key authority and every commitment back to version 1. Follow pagination cursors until the chain is complete.
  6. Keep the last accepted checkpoint and check consistency before accepting a newer one. Reject a rollback or a conflicting root at the same size.
text
veil-rubrica:identity-version:v1

Read log resources#

GET /v1/log identifies the log used by this directory. Log resources live under that origin’s HTTPS URL. The full vkey string also contains a key ID and public key data, so it is not a page address.