Guides · Partie 6 sur 6
Certificats d’inclusion
Vous avez publié une racine de Merkle sous le label 309, ainsi que la liste des feuilles hors chaîne qui la sous-tend. Cette racine est un engagement parfaitement valable — mais ce n’est pas quelque chose que vous pouvez remettre à un collègue, joindre à un contrat ou verser à un dossier judiciaire. C’est précisément cette remise que réalise un certificat d’inclusion : un petit fichier autonome qui rattache une ou plusieurs feuilles à la racine publiée, intègre chaque nœud frère nécessaire pour redériver cette racine et nomme la transaction Cardano dont le temps de bloc atteste l’ensemble. Quiconque peut le vérifier hors ligne, par rapport à n’importe quel explorateur, sans compte et sans rien devoir accorder comme confiance à celui qui l’a produit.
Si vous connaissez OpenTimestamps, c’est la même idée — un reçu portable de
preuve d’existence — avec deux différences délibérées. L’autorité d’horodatage
est le temps de bloc de la blockchain Cardano, non un serveur calendrier. Et
la preuve est générée et vérifiée entièrement côté client : aucune
passerelle, aucun serveur émetteur, aucune confiance en nous à quelque étape que
ce soit. C’est l’équivalent, pour la preuve d’existence, d’un fichier .ots,
ancré sur Cardano et vérifiable de manière autonome.
Ce qu’un certificat prouve — et ce qu’il ne prouve pas
Un certificat formule exactement deux affirmations cryptographiques, chacune vérifiable indépendamment par quiconque :
- Inclusion. Une feuille
leafdonnée occupe la positionindexd’un arbre de Merkle SHA-256 RFC 9162 de tailletree_sizedont la racine estroot. On le prouve en recalculant la racine à partir de la feuille, de son index, de la taille de l’arbre et du chemin de frères intégré. C’est autonome — le seul fichier de certificat suffit. - Ancrage. Cette
rootapparaît mot pour mot dans le champmerkle[].rootde l’enregistrement label 309 porté par la transactiontx_hash. On le prouve en lisant cette transaction sur n’importe quel explorateur Cardano public et en comparant les octets. Il faut le fichier de certificat plus un explorateur — rien d’autre.
Ensemble, ils prouvent que le contenu de la feuille existait à ou avant le
temps de bloc de tx_hash.
Ce qu’un certificat ne prouve PAS
Le temps est affirmé par la blockchain publique, non lié cryptographiquement à l’intérieur de la preuve — exactement comme avec OpenTimestamps et Chainpoint, vous faites confiance au temps de bloc de la chaîne, jamais au producteur du certificat. Un certificat n’est pas un horodatage électronique eIDAS « qualifié » (RFC 3161 / une TSA qualifiée) ; c’est un horodatage ancré sur la blockchain — un élément de preuve corroborant fortement une affirmation temporelle, dans la même catégorie que les autres horodatages sur blockchain, et la formulation du fichier le dit exactement. Il ne dit rien sur qui a rédigé le contenu (c’est une signature d’enregistrement facultative — voir Signatures), et il ne prouve pas que le contenu n’était pas connu plus tôt. Il prouve l’existence à une échéance, non la paternité et non la nouveauté.
Pourquoi la preuve n’est pas signée
Un reçu COSE IETF strict est un COSE_Sign1 dont la charge utile est la racine
de Merkle, signé par une autorité quelconque. Ici, l’autorité est la
blockchain, non une clé que nous détenons — signer la racine avec notre clé
réintroduirait donc une confiance dans le serveur et romprait la propriété de
vérifiabilité autonome sur laquelle repose tout le standard. À la place, le
certificat émet la structure CBOR de preuve d’inclusion IETF exactement telle
qu’elle est spécifiée, et porte l’ancrage blockchain à la place de la
signature. La mathématique de la preuve est identique octet pour octet à
l’encodage IETF ; elle est délibérément non signée et ancrée sur la blockchain.
Le certificat JSON
L’artefact principal est label-309-inclusion-certificate-v1 : un fichier JSON
lisible aussi bien par l’humain que par la machine. Un fichier couvre une OU
plusieurs feuilles, et chaque élément intègre son chemin de frères complet, de
sorte que le fichier se revérifie pour toujours — sans récupération Arweave,
sans passerelle, sans avoir besoin du publicateur d’origine.
{
"format": "label-309-inclusion-certificate-v1",
"generated_at": "2026-06-16T12:00:00.000Z", // informational only, never trusted
"anchor": {
"chain": "cardano",
"network": "mainnet",
"tx_hash": "…64hex…",
"metadata_label": 309,
"block_time": 1781611200, // POSIX seconds — explorer-asserted
"block_time_iso": "2026-06-16T12:00:00.000Z",
"block_height": 12345678, // optional; explorer-asserted
"explorer_urls": [
"https://cardanoscan.io/transaction/…",
"https://adastat.net/transactions/…"
]
},
"merkle": {
"tree_alg": "rfc9162-sha256",
"root": "…64hex…",
"tree_size": 1024, // === the on-chain leaf_count
"leaves_list_uri": "ar://<txid>" // optional source reference
},
"items": [
{
"leaf": "…64hex…", // the content hash committed as a leaf
"leaf_alg": "sha2-256", // how to hash a file to reproduce `leaf`
"index": 42,
"proof": ["…64hex…", "…64hex…"], // siblings, leaf→root; [] for a single-leaf tree
"verified": true, // proof recomputes to merkle.root at build time
"label": "contract.pdf" // optional note/filename
}
],
"claim": "Each listed hash was included in a Merkle tree whose root was published on the Cardano blockchain in the referenced transaction under metadata label 309; therefore each hash provably existed on or before the stated block time.",
"verification": {
"method": "RFC 9162 (Certificate Transparency) SHA-256 inclusion proof. For each item, recompute the Merkle root from leaf+index+tree_size+proof and compare to merkle.root; then confirm merkle.root equals the merkle[].root in the label 309 record of anchor.tx_hash on any public Cardano explorer.",
"requires_trust_in_cardanowall": false,
"time_asserted_by": "Cardano blockchain (block time), via public explorers"
}
}Quelques détails qu’il est bon de connaître :
root,leafet chaque entrée deproof[]sont des valeurs brutes de 32 octets rendues en hex. Les producteurs émettent en minuscules ; un vérificateur accepte l’une ou l’autre casse et rejette tout caractère non hexadécimal ou toute chaîne de longueur impaire.- Le
"verified": truestocké est le résultat du producteur au moment de la construction. Un vérificateur ne s’y fie jamais — il recalcule la preuve lui-même et rend son propre verdict. Une feuille introuvable dans l’arbre est consignée avec"verified": falseet un champ"error", jamais écartée en silence, afin que le fichier reste honnête sur ses échecs. block_timeest l’horodatage POSIX, affirmé par l’explorateur, du bloc qui l’englobe.block_time_isoen est le rendu UTC — pour la commodité seulement.
La preuve d’inclusion CBOR (alignée COSE / RFC 9162)
À côté du JSON, chaque élément peut être exporté sous la forme d’un artefact
.cbor compact dont la structure de preuve est identique octet pour octet à
draft-ietf-cose-merkle-tree-proofs.
Cela signifie que n’importe quel vérificateur de structures de données
vérifiables RFC 9162 / COSE peut lire directement la mathématique de la preuve
— le noyau d’interopérabilité est standard, non maison. Il ne porte aucun temps
de bloc absolu ni aucun texte juridique (cela vit dans le JSON) ; il n’est que
le noyau portable de la preuve, et il est ancré sur la blockchain et non signé
pour la raison ci-dessus.
La preuve d’inclusion IETF nue — bstr .cbor [tree_size, leaf_index, inclusion_path], la valeur 1 de la structure de données vérifiable (vds)
pour RFC 9162 SHA-256 — est extractible à elle seule pour un vérificateur COSE
pur ; l’ancrage Cardano est porté à côté sous la forme d’une petite map à la
place de la signature Sign1.
Construire et vérifier avec l’outillage
Le format de certificat fait partie de l’outillage public et indépendant de
toute passerelle : le SDK @cardanowall/sdk-ts (avec ses jumeaux octet pour
octet en Python et en Rust), la cardanowall CLI et les surfaces de
vérification dans les applications. La mathématique de construction et de
vérification est pure et hors ligne — seule la résolution de faits frais de la
chaîne touche le réseau.
Avec la CLI
certificate build prend la liste des feuilles, les cibles (hex de feuille brut
ou fichiers à hacher) et la transaction dont elle résout les faits d’ancrage.
certificate verify rejoue la preuve d’inclusion par élément et affiche
l’ancrage qu’il vous reste à confirmer sur la chaîne :
# Build a certificate for two files against a published root.
cardanowall certificate build \
--leaves-list leaves.cbor \
--tx <tx-hash> \
--file contract.pdf --file exhibit-a.png \
--out contract.cert.json
# Re-verify the proofs offline — no network, no trust in the producer.
cardanowall certificate verify contract.cert.jsonLe code de sortie 0 signifie que la preuve de chaque élément se recalcule en
la racine ; un code non nul signale un échec d’inclusion, une entrée erronée ou
une erreur d’E/S — il s’intègre donc directement dans votre CI. Chaque élément
isolé peut aussi être extrait dans la forme canonique
{ tree_alg, tree_size, index, leaf, proof[] } et contrôlé avec
cardanowall merkle verify.
Avec le SDK TypeScript
L’API certificate est pure — vous récupérez les octets de la liste des
feuilles avec le fetch propre à la plateforme et les lui passez ; le chemin
cryptographique n’atteint jamais le réseau :
import { certificate, merkle } from '@cardanowall/sdk-ts';
// `leaves` comes from decodeLeavesList(...) over the fetched leaves-list bytes.
const cert = certificate.buildInclusionCertificate({
anchor, // chain facts resolved from the tx
merkle: { treeAlg: 'rfc9162-sha256', root, treeSize: leaves.length },
leaves,
targets: [{ leaf, leafAlg: 'sha2-256', label: 'contract.pdf' }],
});
// Pure re-verification from the certificate alone — no Arweave, no chain.
const result = certificate.verifyInclusionCertificate(cert);
console.log(result.ok); // true when every item's proof recomputes to root
console.log(result.anchorClaim); // the anchor you confirm on a public explorer
// Each item also re-verifies through the plain Merkle predicate.
const item = cert.items[0];
const ok = merkle.merkleSha2256VerifyInclusion(
leafBytes, item.index, cert.merkle.tree_size, proofBytes, rootBytes,
);verifyInclusionCertificate rend le verdict de la preuve et renvoie l’ancrage
affirmé ; confirmer cet ancrage sur la chaîne est votre étape distincte et
explicite — l’objet résultat le dit. Le même module est reproduit octet pour
octet dans les SDK Python (certificate) et Rust (certificate).
Dans le navigateur, sur une page de transaction
Un enregistrement label 309 portant un engagement merkle[] affiche un panneau
d’inclusion sur sa page de transaction. Collez une ou plusieurs empreintes en
hex, ou déposez les fichiers d’origine pour les hacher côté client ; la page
récupère la liste des feuilles directement depuis le stockage adressé par
contenu dans votre navigateur, recalcule chaque preuve, montre un verdict
vert/rouge par élément et propose au téléchargement le JSON, le CBOR et un PDF
imprimable. Le PDF intègre le JSON complet en pièce jointe, de sorte qu’il est
lui-même l’artefact vérifiable par machine — non une simple image de
celui-ci. Rien de tout cela ne touche un serveur privé.
L’algorithme de vérification, de bout en bout
Pour vérifier un certificat de manière indépendante — dans votre propre code, sans aucun outil de notre part — faites exactement ceci :
- Rejetez les champs mal formés. Chaque entrée
root/leaf/proof[]doit être de l’hex de longueur paire se décodant en 32 octets ;tree_sizeet chaqueindexdoivent être des entiers sûrs avecindex < tree_sizeet1 ≤ tree_size ≤ 2³² − 1. - Recalculez la racine de chaque élément. Selon RFC 9162 §2.1.3.2, repliez
la feuille (
leaf = SHA-256(0x00 ‖ leaf_digest)) avec son chemin de frères (node = SHA-256(0x01 ‖ L ‖ R)), en scindant à la plus grande puissance de deux strictement inférieure à la taille courante du sous-arbre, et comparez le résultat àmerkle.rootoctet pour octet. Un arbre à une seule feuille a une preuve vide. - Confirmez l’ancrage sur la chaîne. Récupérez
anchor.tx_hashsur n’importe quel explorateur Cardano public, lisez ses métadonnées label 309 et confirmez quemerkle.rootest égal aumerkle[].rootde l’enregistrement. Le temps de bloc que vous y lisez est l’horodatage que le certificat affirme.
Les étapes 1 et 2 sont la partie autonome — elles ne quittent jamais votre machine. L’étape 3 est l’unique lecture réseau, et elle se fait vers un explorateur que vous choisissez, jamais vers le producteur du certificat.
Un fichier, vérifiable pour toujours
Parce que chaque frère du chemin est intégré, un certificat continue de se vérifier longtemps après que la liste des feuilles, la passerelle d’origine ou le producteur ont disparu. Les deux contrôles — recalculer la racine à partir du fichier, confirmer la racine sur la chaîne — sont tout ce dont quiconque aura jamais besoin. Voir Traitement par lots avec Merkle pour savoir comment la racine et la liste des feuilles sont construites au départ, et Vérification pour le modèle de vérificateur complet dans lequel s’inscrit le contrôle côté chaîne.