Contenu et hachage
Comment Label 309 lie un enregistrement à son contenu : la table des empreintes, ce sur quoi l’empreinte porte son engagement et les engagements Merkle pour ancrer de nombreux éléments sous une seule racine.
L’empreinte du contenu est l’affirmation. Tout ce qu’un enregistrement Label 309 affirme au sujet de l’existence découle d’une empreinte cryptographique des octets du contenu, ancrée sur la chaîne sous le label de métadonnées 309. Cette page définit comment cette empreinte est transportée, sur quoi elle porte exactement son engagement et comment une seule racine de 32 octets peut tenir lieu d’un lot d’éléments de taille arbitraire.
La table hashes
Chaque élément d’un enregistrement porte une table hashes : une table CBOR qui
associe un identifiant d’algorithme à une empreinte brute de 32 octets.
hashes = {
"sha2-256": h'…32 bytes…', ; key = algorithm id, value = raw digest
}Les clés sont des identifiants de type chaîne de texte, tirés du registre des algorithmes de hachage ; les valeurs sont des chaînes d’octets brutes, jamais encodées en hexadécimal. La table doit contenir au moins une entrée, et chaque algorithme de hachage enregistré produit exactement 32 octets :
| Identifiant | Algorithme | Référence | Empreinte |
|---|---|---|---|
sha2-256 | SHA-256 | FIPS 180-4 | 32 o |
blake2b-256 | BLAKE2b-256 | RFC 7693 | 32 o |
Les deux identifiants sont d’implémentation obligatoire pour les vérificateurs, de sorte qu’un enregistrement à empreinte unique sous l’un ou l’autre se valide partout. Un vérificateur qui rencontre un identifiant non reconnu rejette l’enregistrement avec un code d’erreur stable, plutôt que d’ignorer l’entrée en silence. Le registre complet, y compris les emplacements réservés au post-quantique, se trouve dans Registres d’algorithmes.
Recourir à une table CBOR — plutôt qu’à des tableaux parallèles ou à une liste de
sous-objets {alg, digest} — a trois conséquences qui font partie du contrat du
format de sérialisation. Les algorithmes en double sont impossibles par
construction, car les clés d’une table CBOR sont uniques. L’ordre canonique est
automatique, parce que le CBOR canonique trie les clés selon leurs octets
encodés : ainsi, deux producteurs exprimant le même ensemble d’empreintes
émettent des tables identiques octet pour octet, et toute signature au niveau de
l’enregistrement qui les couvre reste stable. Enfin, la structure ne demande
aucune validation entrée par entrée : un validateur structurel se borne à
vérifier que chaque clé est enregistrée et que chaque valeur a la longueur
d’empreinte prévue par l’algorithme.
Ce sur quoi l’empreinte porte son engagement
L’empreinte porte son engagement sur les octets du contenu — la séquence
exacte d’octets que le producteur horodate. Chaque entrée d’une table hashes
doit être l’empreinte de cette même séquence d’octets sous l’algorithme indiqué ;
un enregistrement dont les entrées décrivent des textes en clair différents
n’est pas conforme. Lorsque les octets du contenu sont à la disposition d’un
vérificateur, celui-ci doit recalculer chaque empreinte et rejeter
l’enregistrement si l’une d’elles ne correspond pas.
Lorsqu’un enregistrement porte une enveloppe de chiffrement (enc), l’empreinte
lie le texte en clair, jamais le texte chiffré. C’est délibéré : une preuve
d’existence (Proof of Existence, PoE) existe pour qu’un auteur puisse, plus tard,
révéler le texte en clair et prouver qu’il existait à un instant donné. Hacher le
texte chiffré ne prouverait que l’existence d’un blob chiffré quelconque, ce qui
ne dit rien du contenu sous-jacent. Ainsi, un enregistrement scellé prouve
toujours précisément quel texte en clair a été horodaté : le destinataire
déchiffre, recalcule les empreintes du texte en clair et les confronte à
l’engagement inscrit sur la chaîne. Un élément porteur d’un enc doit donc
contenir au moins une entrée d’empreinte du contenu ; sans elle, il n’y aurait
aucune affirmation sur le texte en clair à recalculer.
Liaison au texte en clair, même lorsqu’il est scellé
L’empreinte inscrite sur la chaîne d’un enregistrement scellé est l’empreinte du texte en clair.
Le texte chiffré lui-même réside à une URI ar:// ou ipfs:// adressée par contenu, de sorte que
les octets que renvoie une passerelle de stockage sont à l’épreuve de la falsification au regard
de l’adresse, sans qu’il faille faire confiance à la passerelle ; un destinataire déchiffre et
recalcule l’empreinte du texte en clair pour boucler la boucle jusqu’à l’affirmation inscrite sur
la chaîne.
Une seule empreinte, ou plusieurs
Une empreinte unique du contenu est pleinement conforme. Pour toutes les
empreintes de 256 bits du registre, les meilleures attaques connues sur la
seconde préimage se situent à 2^256, ou tout près, en régime classique : une
seule empreinte de 256 bits bien conçue couvre déjà le modèle de menace réaliste
sur toute la durée d’archivage d’un enregistrement, et les validateurs
structurels n’émettent aucun avertissement pour les enregistrements à entrée
unique.
Un producteur peut ajouter une seconde entrée issue d’une famille de
conception indépendante, à titre de défense en profondeur facultative — en
associant sha2-256 (SHA-2 : construction Merkle–Damgård) à blake2b-256
(BLAKE2 : une construction HAIFA reposant sur une permutation dérivée de ChaCha).
Comme les deux familles ne partagent aucune filiation structurelle, un
enregistrement qui porte les deux n’est affaibli que si les deux familles
tombent sous la cryptanalyse en même temps. Le coût est d’une empreinte
supplémentaire de 32 octets, accompagnée de son court identifiant, par élément ;
le choix appartient au producteur et n’est jamais obligatoire.
Engagements Merkle par lots
Une empreinte unique du contenu ancre un contenu unique. Pour ancrer une
collection de taille arbitraire — un ensemble de 500 artefacts d’intégration
continue, un flux d’événements IoT, un lot de journaux d’audit —, Label 309
définit un tableau merkle[] de premier niveau. Chaque entrée porte son
engagement sur une liste ordonnée de feuilles de 32 octets, au moyen d’une seule
racine de 32 octets publiée sur la chaîne ; les feuilles ordonnées elles-mêmes
résident hors chaîne.
merkle = [
{
"alg": "rfc9162-sha256",
"root": h'…32 bytes…', ; canonical root over the ordered leaves
"leaf_count": 4, ; binds the on-chain root to the leaf-list size
"uris": [ … ], ; OPTIONAL — where the off-chain leaves list lives
},
]L’algorithme d’engagement enregistré est rfc9162-sha256 : le Merkle Tree Hash
de la RFC 9162 §2.1.1, avec SHA-256 comme empreinte sous-jacente. C’est une
construction d’engagement sur une liste, distincte du registre des empreintes de
contenu — une racine Merkle porte son engagement sur la structure d’une liste de
feuilles, tandis qu’une empreinte sha2-256 porte son engagement sur des octets
de texte en clair —, et c’est pourquoi elle réside dans son propre tableau plutôt
qu’à l’intérieur de hashes. Le leaf_count inscrit sur la chaîne lie la racine
à la taille de la liste hors chaîne, ce qui exclut une substitution qui
reconstruirait un arbre de taille différente partageant la racine pour quelque
position de feuille.
Construction de l’arbre
La construction distingue les feuilles des nœuds internes au moyen d’un préfixe
de séparation de domaine d’un octet — 0x00 pour les feuilles, 0x01 pour les
nœuds internes —, de sorte qu’un attaquant ne puisse forger un nœud interne qui
entre en collision avec une feuille. Pour une liste ordonnée
L = (d_0, …, d_{n-1}) de valeurs de 32 octets avec n ≥ 1, le Merkle Tree Hash
est défini de façon récursive :
MTH(L) = SHA-256(0x00 || d_0) when n == 1
MTH(L) = SHA-256(0x01 || MTH(L[0:k]) || MTH(L[k:n])) when n > 1
where k is the largest power of 2 strictly less than nUne conséquence cruciale : une feuille unique se hache comme
SHA-256(0x00 || d_0), et non comme la feuille nue. La racine d’un arbre à
une seule feuille n’est donc jamais égale à la feuille elle-même. Les producteurs
qui souhaitent horodater un contenu unique doivent utiliser directement une
entrée sha2-256 ou blake2b-256, et non un arbre Merkle à une seule feuille.
Un arbre vide (n == 0) est interdit.
La construction est sensible à l’ordre — permuter les feuilles produit une racine différente —, si bien que les producteurs doivent traiter la liste de feuilles comme une séquence ordonnée et en préserver l’ordre tout au long de la publication, de l’archivage et de toute génération de preuve ultérieure.
La liste de feuilles hors chaîne
La racine est inutile sans la liste de feuilles ; aussi les producteurs
conservent-ils les feuilles ordonnées hors chaîne. L’artefact canonique est un
document cardano-poe-merkle-leaves-v1, encodé en CBOR canonique
(RFC 8949) : une racine de 32 octets, le tableau ordonné des feuilles de 32
octets et le nombre de feuilles.
leaves-list = {
"format": "cardano-poe-merkle-leaves-v1",
"tree_alg": tstr, ; registered list-commitment algorithm id
"root": bytes .size 32, ; raw 32 bytes, not hex
"leaves": [ + bytes .size 32 ], ; ordered raw 32-byte leaves
"leaf_count": 1..4294967295, ; 1 .. 2^32-1; MUST equal the length of `leaves`
? "leaf_alg": tstr, ; informative; no verification semantics
}Un vérificateur résout la liste hors chaîne, recalcule la racine à partir de ses
leaves selon la construction ci-dessus et la confronte octet pour octet à la
merkle[i].root inscrite sur la chaîne ; le leaf_count du fichier doit être
égal à la fois au leaf_count inscrit sur la chaîne et à len(leaves). Ce
conteneur en CBOR canonique est la seule forme normative de la liste de
feuilles — il n’existe ni projection JSON ni sérialisation alternative —, de
sorte que deux implémentations qui échangent une liste de feuilles échangent
toujours des documents comparables octet pour octet.
Preuves d’inclusion
L’intérêt du regroupement par lots est la divulgation sélective : prouver qu’un
élément figurait dans la liste engagée sans republier — ni même révéler — le
reste. Une preuve d’inclusion pour une feuille est la liste ordonnée des
empreintes des nœuds frères le long du chemin allant de cette feuille jusqu’à la
racine : un chemin de frères en O(log n). Un vérificateur replie la feuille et
les frères en remontant l’arbre conformément à la RFC 9162 et accepte la preuve
si, et seulement si, la racine reconstruite est égale octet pour octet à la
racine publiée.
Comme les arbres de la RFC 9162 ne sont pas complétés jusqu’à une puissance de deux, une feuille du bord droit d’un arbre déséquilibré peut avoir un chemin plus court qu’une feuille du côté plein. La vérification qui fait foi est donc algorithmique — le repliement reproduit-il la racine ? —, jamais une comparaison de la longueur de la preuve.
Pourquoi le regroupement par lots compte
Une seule transaction et une seule racine de 32 octets peuvent tenir lieu de milliers, voire de
millions de feuilles. Quiconque détient une preuve en O(log n) peut démontrer par la suite « cet
élément figurait dans ma liste », tandis que chaque feuille non divulguée demeure privée : la
racine ne révèle rien des feuilles sur lesquelles elle porte son engagement.
L’enregistrement
Le format de sérialisation (wire format) de Label 309 : où réside l’enregistrement sous le label de métadonnées 309, la forme de sa map, les règles du CBOR canonique, le découpage en chunks pour le transport et le schéma CDDL.
Registres d’algorithmes
Les registres d’identifiants nommés pour les empreintes, les AEAD, les KEM, les KDF et les signatures — et la règle d’agilité qui rend la migration post-quantique additive plutôt que cassante.