REVIEWITDocumentation
This page is generated from REVIEWIT_SignOff_Artifact/SPEC-Verification-v1.md — it cannot be corrected by hand.Correcting the contract corrects the page. Editing it here would be lost at the next generation.GENERATED ON 5 September 2026 · REVIEWIT-SignOff-Verification/1 · 242451e5
Generated referenceUp to date · generated on 5 September 2026

Verifying an offline proof

Machine translation, not yet reviewedThis page was translated by a model from the French version, which is authoritative. Read the French version.

01What this document allows #sec_e0af9bcf

REVIEWIT produces, at each signature, a sealed attestation from which a verification package can be extracted: a file that contains everything needed to redo the demonstration elsewhere.

This document is the complete specification of this format. It is published for a specific reason: to allow a third party to verify a proof without us, and even without believing us. It describes the canonicalization, the construction of trees, and the verification of inclusion proofs accurately enough for an auditor, an information systems department, or an independent firm to write its own verifier and obtain the same verdict as ours.

This is the highest form of the guarantee that REVIEWIT announces. A platform that would say « trust us, it's sealed » would demand exactly what this document renders unnecessary.

02Who it is for #sec_c1bc9732

For a technical reader: the person who will verify a proof, or the one who will write the tool that verifies it. It is not necessary to read an audit report, nor to use REVIEWIT.

An auditor who only wishes to obtain a verdict does not need to read this text: the « Verify a proof » screen of the Workspace Center and the command line tool apply this contract, without deviation. This document exists for those who refuse to rely on either — and they are right to be able to do so.

03What you need #sec_48297a56

Four elements, and they do not come from the same place:

  1. The verification package — the file itself. It is given to you with the proof that is opposed to you, or you download it from REVIEWIT.
  2. A verifier — the one you write from this document, or the one that REVIEWIT makes available. Both must render the same verdict; if they diverge, it is a defect, and it concerns us.
  3. The public keyring of the authority — served by this portal at the address /.well-known/seal-keyring.json, and delivered with the security annex of your contract. It carries the public keys with which the signature of the seal is controlled, and only it. Everything else — the fingerprint, the Merkle roots, the chaining, the inclusion proof — is verified without any key, from the file alone.
  4. The root key fingerprint — carried by the security annex signed with your contract. It, and it alone, establishes that the keyring you have downloaded is indeed ours (§8.3).

04What the file alone establishes, and what it does not #sec_192edcae

Without a keyring, a package remains entirely verifiable in its internal coherence: that the manifest produces the announced fingerprint, that the lists produce the attested roots, that a given element is indeed within the sealed scope.

What the file alone does not establish is that this content has been sealed by us. A package can declare itself sealed without being so: this declaration is worth nothing as long as the authority's signature has not been controlled with its public key. A compliant verifier must therefore distinguish these two findings and never present the second as acquired from the first.

051. Canonicalization, version 1 #sec_53b1cef4

A canonical document is a UTF-8 JSON without BOM, without space or line break, such that:

  1. the keys of an object are sorted by ordinal order of the code points;
  2. strings are normalized Unicode NFC; only ", \ and control characters are escaped; non-ASCII is not escaped;
  3. the only numbers are 64-bit signed integers; no floating point; a proportion is expressed for ten thousand;
  4. instants are in universal time, in the format yyyy-MM-ddTHH:mm:ss.ffffffZ — six decimal places, the seventh truncated; civil dates in the format yyyy-MM-dd;
  5. a non-applicable value is absent; there is no null, no empty string standing in for absence;
  6. byte sequences are in lowercase hexadecimal.

A document containing a null, a floating point number, or a duplicated key is not a canonical document and is rejected.

062. Hashing #sec_9d21b1bf

SHA-256, identifier "SHA-256" carried in cryptography.hash of the manifest.

073. Tree diagram, version 1 #sec_3b2d707a

ElementDefinition
Domain prefixesleaf 0x00, node 0x01, empty tree 0x02, root 0x03
LeafH(0x00 ‖ salt ‖ content) — the salt is 32 bytes, unique to each leaf
NodeH(0x01 ‖ left ‖ right)
Odd levelthe orphan node is promoted as is to the upper level, never duplicated
Commitmentcanonical object `{"domain":{"empty":2,"leaf":0,"node":1,"root":3},"hash":"SHA-256","leafCount":n,"schema":1,"tree":"scope","decisions"}`
Published rootH(0x03 ‖ commitment ‖ raw root) for n ≥ 1
Empty batch rootH(0x02 ‖ commitment) with leafCount = 0

Order of leaves. Composite key (SHA-256(identity), identity), compared byte by byte in unsigned lexicographic, the second term only breaking ties of the first. Two identical identities in a batch are a refusal.

Two trees. scope: the leaf content is the canonical stable identity {"criterion":…,"object":…,"type":…}. decisions: the content is the canonical decision (§5). Same order, same position for the same item.

Salts. Derived by SEAL from the cryptography.secretGeneration generation, by (tree, position). The secret is not included in any packet.

084. Proof of inclusion #sec_b535f3ee

{"commitment":{…},"content":hex,"path":[{"side":"left"|"right","sibling":hex} | {"promoted":true} …],"position":p,"root":hex,"salt":hex,"schema":1}

Verification: recalculate the leaf, go up the path requiring at each level exactly what the structure imposes — a sibling on the right side when index has a neighbor, a promotion when index is the last of an odd level —, then H(0x03 ‖ commitment ‖ node) and compare to the attested root. A path shorter or longer than the structure is a refusal.

095. Manifest, version 1 #sec_9dbbc182

Blocks of the root object (sorted keys): actors, context, cryptography, decisions, governance, header, qualification, scope, snapshot, statement.

  • header: attestation, canonicalization (1), complementRank, lot, originLot (absent for the initial lot), schema (1).
  • decisions[i]: actor, decidedAt, exceptionUntil, identity, justification, origin (human | defaultRule | systemClosure | nonDecidedUncovered), previous, rule (id, motive, version — present if and only if the origin is not human), verdict.
  • qualification: closure, conflictOfInterest, coverage (complete), decisionMode, origins (four counts, calculated).
  • governance.indicators: the four integers with collected:true, or {"collected":false}.
  • cryptography: hash, preflight ({"state":"unavailable"} or reference), secretGeneration, trees.scope and trees.decisions (commitment, root).

Sealed form. The sealed fingerprint — the one the anchor carries — is SHA-256 of the canonical form where scope and decisions are replaced by their commitment {"count":n,"hash":SHA-256(canonical list)}. The lists only travel in the complete packet; the Merkle roots already commit them.

106. Packets #sec_de906bc8

FieldCompletePunctual
specificationREVIEWIT-SignOff-Verification/1idem
kindcompletepunctual
attestationsealed formsealed form
digestSHA-256(attestation)idem
scope.items, decisionscomplete lists, in canonical order—
salts.scope, salts.decisionsall salts, by position—
proof—one proof, with the salt of the single leaf disclosed
sealing{"state":"unanchored"}; or anchored with domain, segment, rank, anchoredAt, seal:"pending"; or sealed with in addition seal.reference, seal.sealedAtidem

117. Procedure #sec_9a00ec24

  1. Re-read the packet as a canonical document (§1); refuse otherwise.
  2. Check specification.
  3. Recalculate SHA-256(attestation) and compare it to digest, and to the fingerprint held elsewhere if applicable.
  4. Check header.schema, header.canonicalization, cryptography.hash.
  5. Complete: check the commitments of the two lists; check that at each position the decision carries the identity of the item; reconstruct each tree from the list and the salts (§3) and compare root and leafCount to cryptography.trees.
  6. Punctual: check that the proof targets the attested root and leafCount for its tree; check the proof (§4).
  7. Read sealing.state and return it as is: this version does not verify the anchor or the seal, and an unanchored packet is not opposable.

A packet is valid when all executed checks succeed. This does not establish that it is sealed.

128. Public keyring and root key anchoring #sec_71a42b6e

The seal of a packet is verified with the public key of the authority, published in a keyring: a JSON file, independent of the packets, that the third party holds.

{
  "keys": [ { "kid": "signing:1", "alg": "ecdsa-p256-sha256", "spki": "<DER SubjectPublicKeyInfo, base64>" } ],
  "attestation": {
    "version": "seal.keyring.v1",
    "count": 1,
    "digest": "<hex>",
    "alg": "ecdsa-p256-sha256",
    "rootKid": "keyring-root:1",
    "rootSpki": "<DER SubjectPublicKeyInfo de la racine, base64>",
    "signature": "<base64>"
  }
}

The packet names its key, the keyring provides it. sealing.seal.keyId designates the entry to use. An entry is never removed from a keyring: removing it would make all the proofs it has sealed unverifiable.

8.1 Fingerprint of the content

Retain entries bearing both kid, alg, and spki — an incomplete entry does not confer any key and does not enter the calculation. Sort them by kid, in ordinal comparison on code points. Form one line per entry, kid | alg | spki followed by a line break U+000A. The fingerprint is the SHA-256 of the UTF-8 concatenation of these lines, in lowercase hexadecimal.

The creation date of an entry, if it appears, does not enter the calculation: it is a display snapshot.

8.2 Vector signed by the root

seal.keyring.v1|<nombre d'entrées retenues>|<empreinte du contenu>

Signed in text form, encoded in UTF-8, by the root key, according to attestation.alg. The admitted suites are those of the seal: ecdsa-p256-sha256 (ASN.1 DER signature, RFC 3279) and rsa-pkcs1-sha256. An unknown algorithm is a refusal, never an admission.

8.3 What the third party holds, and why the root

The anchor of the device is the fingerprint of the root key — SHA-256 of its DER SubjectPublicKeyInfo, in lowercase hexadecimal — carried by the security annex that the client signs with its contract.

It concerns the root, never the file. A keyring grows: each rotation of the sealing key adds an entry to it. A fingerprint of the file would therefore expire at the first rotation, and an auditor holding the correct, expired file would see an authentic proof fall. The root, on the other hand, does not change; the signed annex is never reopened.

8.4 Procedure for verifying a keyring

  1. Recalculate the fingerprint of the content (§8.1) and the number of retained entries, and compare them to attestation.digest and attestation.count. Recalculate first, verify the signature afterwards: checking the signature on the declared fingerprint would let through a keyring whose keys have been changed while keeping the signed block.
  2. Verify attestation.signature on the vector (§8.2) with attestation.rootSpki.
  3. Compare the fingerprint of attestation.rootSpki to the one carried by the annex.

Six outcomes, and only one is opposable:

OutcomeWhat is established
Anchored keyringVerified signature and root conforming to the annex. Only opposable state.
Signed, root not checkedNo annex fingerprint provided: internal consistency only — anyone can sign a keyring with their own root.
Signed by another rootThe file is not the one designated by the annex.
AlteredThe content no longer produces the attested fingerprint.
Invalid attestationThe declared root did not sign this content.
Not anchoredNo attestation block — a keyring prior to the device. This is not a fault; it is a file without an anchor.

An unanchored keyring always allows a seal to be checked. What it does not allow is to establish where the public key used comes from — and a verified signature with a key of unknown provenance establishes nothing.

Esc
↑↓ navigate↵ openSee all results →