Vérification
Les trois rôles de vérificateur de Label 309, les états du verdict, la profondeur de finalité et le catalogue typé des erreurs : comment quiconque parvient à la même réponse à partir de la seule infrastructure publique.
Label 309 se vérifie, jamais ne s’affirme. Un publicateur ancre une empreinte de contenu sur Cardano sous le label 309 ; à partir de ce moment, l’affirmation tient sur ses propres octets, et quiconque dispose de la référence de transaction peut la contrôler. Cette page définit comment ce contrôle se déroule : les trois rôles de vérificateur, ce que chacun touche et ne touche pas, les états de verdict qu’ils émettent, la profondeur de confirmation en deçà de laquelle un verdict reste provisoire, et le catalogue typé des erreurs qui fait converger deux implémentations indépendantes vers le même échec pour la même entrée.
La propriété qui la définit est l’indépendance du service. Un vérificateur conforme atteint son verdict en n’utilisant que la chaîne publique, un explorateur ou une passerelle Cardano choisis par le vérificateur lui-même et — pour les affirmations de contenu et les enregistrements scellés — les passerelles de stockage adressé par le contenu que le vérificateur choisit également. Il ne contacte jamais le publicateur. Le standard ne nomme aucun fournisseur particulier ; la passerelle est une entrée que l’opérateur fournit.
Trois rôles, chacun une extension stricte
La vérification est organisée en couches. Chaque rôle fait tout ce que fait le rôle au-dessus de lui, puis ajoute une capacité. Un rôle inférieur est à lui seul un vérificateur complet et utile — il prouve simplement moins de choses.
| Rôle | Ajoute | Touche |
|---|---|---|
| Validateur structurel | conformité de schéma et de domaine sur les octets de l’enregistrement | rien — une fonction pure |
| Vérificateur public | résolution de chaîne, inclusion sur la chaîne, contrôle des signatures | un explorateur Cardano + des passerelles de contenu |
| Vérificateur destinataire | déchiffrement d’essai d’une charge utile scellée, recalcul de l’empreinte du texte en clair | la clé privée propre du vérificateur |
Validateur structurel — une fonction pure sur les octets
Le validateur structurel est une fonction unique qui va d’une chaîne d’octets à un résultat. Il n’effectue aucune E/S, aucun contrôle de signature cryptographique et aucun déchiffrement. Il ne voit jamais un réseau, une transaction ou une clé. À entrée identique, il renvoie la même sortie, à chaque fois, partout — ce qui est précisément ce qui lui permet de s’exécuter avant l’envoi au sein de l’outillage d’un publicateur, à l’intérieur d’un indexeur tiers ou d’un outil d’archivage confirmant la bonne formation à long terme, le tout sans serveur.
Son pipeline est fixe :
1. resource bounds — a local, non-normative guard on input size; never a
Label 309 conformance error.
2. canonical decode — decode with a canonical-CBOR decoder (RFC 8949 §4.2.1):
definite lengths, sorted map keys, no duplicate keys,
valid UTF-8. Any malformed or non-canonical input →
a single MALFORMED_CBOR.
3. schema parse — type, length, and the chunk/length bounds; a strict
object mode that rejects unknown fields.
4. domain rules — cross-field constraints the schema cannot express:
registry membership, the items-or-merkle rule, COSE
structural shape, URI reconstruction, envelope shape.
5. result — { valid, record } with optional warnings/info, or a
sorted list of typed issues.Le validateur est indépendant du profil : il analyse l’intégralité du schéma v1, quel
que soit le sous-ensemble sur lequel un vérificateur en aval entend agir. Les erreurs
invalident l’enregistrement ; les avertissements et les entrées d’information sont
remontés mais le laissent valide. Surtout, il confirme la forme d’un COSE_Sign1 —
tableau à quatre éléments, charge utile détachée (null), un en-tête protégé bien
formé — mais ne vérifie jamais la signature, et il ne rejette jamais un
enregistrement au seul motif que l’algorithme de signature en est un qu’il ne
reconnaît pas (ce cas est étiqueté SIGNATURE_UNSUPPORTED, de sévérité info, et
l’enregistrement reste valide). Vérifier la signature est l’affaire du vérificateur
public. Voir L’enregistrement pour le schéma que cette phase
impose.
Vérificateur public — chaîne, inclusion et signatures
Le vérificateur public superpose la chaîne au validateur structurel. Étant donné une référence de transaction Cardano, il :
- Résout un explorateur choisi par le vérificateur. La chaîne d’explorateurs est
une entrée ; le vérificateur les essaie dans l’ordre, en récupérant le CBOR brut
de la transaction sur la chaîne — jamais la projection JSON des métadonnées de
l’explorateur. La vue JSON effondre les types majeurs CBOR en une union JSON et
abandonne l’ordre des clés de la carte, le cadrage à longueur définie et le
discriminant octets/texte, si bien qu’un vérificateur qui réencoderait à partir
d’elle ne pourrait pas reproduire l’entrée de signature exacte octet par octet et
toute signature sur un enregistrement conforme échouerait. La réponse négative d’un
seul fournisseur ne fait pas autorité sur la chaîne — la transaction peut être
sur la chaîne et simplement inconnue de ce fournisseur — aussi le vérificateur
consulte-t-il tous les fournisseurs restants avant d’émettre
TX_NOT_FOUND; si tous les fournisseurs sont injoignables, il émetPROVIDER_UNAVAILABLE. - Lie les octets récupérés à la référence de transaction. Avant de lire quoi que
ce soit d’une transaction récupérée, le vérificateur recalcule
blake2b-256sur les octets du corps de la transaction récupérée — par définition du ledger, l’id de la transaction — et rejette la réponse à la moindre discordance avec l’empreinte demandée. Il recalcule ensuiteblake2b-256sur les octets des données auxiliaires récupérées et rejette à la moindre discordance avec l’auxiliary_data_hashdu corps désormais vérifié. Les deux condensés sont calculés sur les octets exactement tels que récupérés, jamais sur un réencodage. Une réponse qui échoue à l’un ou l’autre contrôle porte des octets manifestement erronés et est écartée ; si aucun fournisseur ne produit une réponse qui survit à la liaison, le rapport porteTX_INTEGRITY_MISMATCH. Après cette étape, chaque octet de l’enregistrement et de la transaction environnante est cryptographiquement engagé envers l’empreinte fournie par l’appelant — aucun explorateur ne peut substituer, amender ou tronquer l’enregistrement sans produire une seconde préimage de blake2b-256. - Désencapsule les données auxiliaires. Le ledger de l’ère Conway admet trois
encodages de données auxiliaires, tous valides : une carte de métadonnées nue et
sans tag, un tableau à deux éléments
[ metadata, scripts ], et une carte à tag 259 portant les métadonnées sous la clé0. Le vérificateur DOIT accepter les trois et discriminer uniquement d’après le type et le tag CBOR de premier niveau — une valeur à tag 259 est la forme à carte avec clé, un tableau sans tag est la forme à deux éléments, et une carte sans tag est toujours la carte de métadonnées elle-même. Il NE DOIT PAS inspecter les clés d’une carte pour deviner la forme ; toute autre forme de premier niveau, ou tout tag autre que 259, estMALFORMED_CBOR. Si la transaction liée ne porte aucune métadonnée sous le label 309, le vérificateur émetMETADATA_NOT_FOUND— un résultat attribuable à l’enregistrement, parce que la transaction liée elle-même prouve l’absence : aucun fournisseur n’aurait pu retirer les métadonnées sans faire échouer la liaison. - Réassemble le tableau de fragments du corps entier. La valeur du label 309 est le corps de l’enregistrement en CBOR canonique découpé en un tableau de chaînes d’octets de ≤ 64 octets. Le vérificateur concatène les éléments octet par octet et dans l’ordre — renvoyant les octets bruts, sans passe de réencodage — pour que le contrôle de CBOR canonique puisse encore détecter un encodage non conforme sur la chaîne.
- Valide structurellement le corps réassemblé (le rôle au-dessus). Un rejet du
validateur court-circuite le rapport avec le verdict
failed. - Contrôle la profondeur de confirmation (plus bas). Une transaction en deçà du
seuil s’arrête ici avec le verdict
pending. - Vérifie chaque signature au niveau de l’enregistrement sous Ed25519 strict. Il ne déchiffre pas. La résolution de la signature, la charge utile à séparation de domaine et les règles de vérification stricte sont spécifiées sur Signatures.
- Récupère le contenu et en vérifie l’empreinte, ne tenant l’enregistrement pour comptable que des octets qu’il peut attribuer à l’adresse de contenu propre d’un URI (plus bas). Il ne déchiffre pas.
Pourquoi le CBOR brut et non le JSON
Une signature est calculée sur le CBOR canonique, exact octet par octet, du corps de l’enregistrement. Une projection JSON des métadonnées est par construction à perte — elle ne peut pas faire l’aller-retour vers ces octets. Réencoder à partir du JSON brise toute signature sur un enregistrement conforme. Le CBOR brut de la transaction est la seule entrée faisant autorité pour tout contrôle cryptographique ; une vue JSON sert à l’affichage humain, une fois que la vérification a déjà réussi.
Vérificateur destinataire — déchiffrer et recalculer
Le vérificateur destinataire est un vérificateur public qui détient en outre une clé privée. Pour un enregistrement scellé qui lui est adressé, il déchiffre à l’essai les emplacements de clé sur la chaîne avec sa clé, récupère la clé de contenu en cas de réussite, déchiffre le texte chiffré, puis recalcule les empreintes du texte en clair par rapport à l’engagement sur la chaîne — bouclant ainsi la boucle entre les octets chiffrés et l’affirmation d’existence du contenu. Parce que tout enregistrement scellé porte au moins une entrée d’empreinte de contenu, ce recalcul a toujours quelque chose de concret à comparer. L’enveloppe scellée, les emplacements de clé et la construction de déballage sont spécifiés sur PoE scellée.
Avant que le destinataire ne touche la moindre primitive KEM ou AEAD, il réapplique les
mêmes contrôles de forme et de ressources de l’enveloppe que le validateur structurel a
déjà exécutés, rejetant d’abord une enveloppe structurellement invalide ou
surdimensionnée. Deux de ces gardes pré-primitives sont des bornes de ressources fixées
par le déploiement, et non des champs de sérialisation : les bornes de référence sont
MAX_SLOTS = 1024 emplacements et 65536 octets pour l’enveloppe enc décodée, toutes
deux bien au-dessus du plafond d’environ 16 KiB des métadonnées de transaction Cardano
qui borne tout enregistrement honnête, de sorte qu’un enregistrement dépassant l’une ou
l’autre est mal formé et est rejeté avec ENC_SLOTS_TOO_MANY ou
ENC_ENVELOPE_TOO_LARGE avant qu’une seule primitive ne s’exécute. Les déploiements
PEUVENT les resserrer.
Un contrôle de forme est déterminant pour la sécurité : le matériel d’encapsulation
DOIT être distinct au sein d’un même slots[] — toutes les valeurs epk pour
x25519, ou toutes les valeurs kem_ct pour mlkem768x25519. Un doublon au sein de
l’enregistrement est rejeté avec ENC_SLOTS_DUPLICATE_KEM_MATERIAL avant l’exécution
de toute primitive KEM ou AEAD, parce qu’un epk/kem_ct répété romprait l’unicité de
clé par emplacement sur laquelle repose l’enveloppe à nonce nul. La réutilisation de
clé entre enregistrements ou entre clés est une obligation du producteur et n’est pas
détectable par le vérificateur ; seul le doublon au sein de l’enregistrement l’est. Les
trois contrôles sont structurels — le validateur les impose sur tout enregistrement
(les codes du matériel dupliqué, du décompte des emplacements et de l’enveloppe décodée
sont des codes de Partie A) ; le destinataire les réexécute simplement en défense en
profondeur.
Le déballage lui-même se compose de deux étapes cryptographiques que le destinataire
reproduit à partir de l’enveloppe, jamais d’une entrée annexe quelconque. Il recalcule
d’abord l’empreinte de transcription des emplacements slots_hash une seule fois,
avant la boucle, et la maintient constante d’un emplacement à l’autre :
slots_hash = SHA-256("cardano-poe-slots-transcript-v1" || canonicalEncode(SLOTS_TRANSCRIPT)),
où la transcription fixe les champs d’en-tête, l’ensemble d’emplacements sur le fil
(chaque champ d’emplacement étant une chaîne d’octets unique — il n’y a pas de
découpage par champ à normaliser) et l’affirmation d’empreinte de l’élément via
hashes_hash. Lier hashes_hash est ce qui permet au destinataire de confirmer que
l’enveloppe a été scellée pour cette affirmation d’empreinte exacte à partir des
seuls octets sur la chaîne, avant toute récupération de texte chiffré — une enveloppe
greffée sur un élément doté d’une carte hashes différente échoue au MAC. Il itère sur
tous les emplacements sans rupture anticipée ; un emplacement n’est accepté que
lorsque la clé de contenu qu’il produit reproduit aussi le slots_mac sur le fil par
rapport à ce slots_hash constant. L’acceptation intègre par ailleurs un bit de
validité indépendant du secret : sur le chemin classique, un emplacement façonné pour
amener le secret partagé X25519 à la valeur entièrement nulle met ce bit à faux (une
comparaison à temps constant contre 0^32), la KEK est sélectionnée à temps constant
vers une valeur factice dérivée de 0^32 afin que la boucle effectue un travail
identique, et le bit conditionne l’acceptation de l’emplacement — un emplacement à ECDH
invalide ne peut jamais s’ouvrir, quels que soient son enveloppe ou son MAC.
L’ouverture de l’enveloppe et l’ouverture ultérieure du contenu sont toutes deux
atomiques : en cas d’échec du tag AEAD, elles ne renvoient aucun texte en clair, et
le candidat qu’elles restituent (la clé enveloppée, ou le texte en clair du contenu)
est une valeur factice fixe ou pseudo-aléatoire indépendante du texte chiffré en échec
— aucun texte en clair non vérifié n’est jamais libéré.
Une clé de destinataire PEUT légitimement correspondre à plus d’un emplacement : un
producteur peut sceller la même clé de contenu vers le même destinataire dans plusieurs
emplacements, chacun avec un matériel KEM frais par emplacement, pour gonfler le
décompte des destinataires — une technique de confidentialité valide, et distincte du
rejet de matériel d’encapsulation dupliqué, qui ne se déclenche que sur un epk/kem_ct
identique. Le vérificateur sélectionne la clé de la première correspondance et NE
DOIT PAS rejeter au seul motif que plusieurs emplacements ont correspondu. La seule
anomalie qu’il DOIT rejeter est constituée de deux emplacements correspondants qui
récupèrent des clés de contenu différentes (comparées à temps constant) : la boucle
porte un bit cek_conflict et fait surgir l’unique échec générique si une
correspondance ultérieure produit une clé qui diffère de celle sélectionnée. Il s’agit
de défense en profondeur — sous l’engagement de l’ensemble d’emplacements, une
correspondance à clé distincte est déjà irréalisable, aussi le contrôle échoue-t-il
simplement de façon sûre.
Ensuite, sur la clé de chiffrement du contenu récupérée, il dérive la clé de contenu
(une feuille HKDF de cette clé salée par enc.nonce) et ouvre le texte chiffré en
STREAM segmenté segment par segment, vérifiant le tag de chaque segment avant de
libérer le texte en clair de ce segment. L’AAD par segment est vide : tout le contexte
d’en-tête est déjà lié à la clé de manière transitive à travers slots_mac, de sorte
qu’inverser n’importe quel champ d’en-tête change ce que le destinataire dérive et le
flux ne s’ouvre pas. La troncature est détectée par le drapeau final — un segment final
manquant, des données après lui, un drapeau final sur un segment non final, ou un
segment non final trop court échouent tous en TAMPERED_CIPHERTEXT. Le format segmenté
n’impose aucun plafond cryptographique à la charge utile (le compteur de segments à 88
bits admet 2^88 segments) ; un maximum pratique est une politique de déni de service
du déploiement, appliquée de manière incrémentale à mesure que le flux est lu. Sur le
chemin à phrase secrète, le destinataire lit d’abord l’en-tête d’engagement initial de
32 octets et le compare à temps constant avant d’ouvrir le moindre segment.
Le chemin du destinataire est l’endroit où le catalogue d’erreurs justifie sa précision : il distingue le cas où aucun emplacement n’a accepté cette clé (destinataire erroné) du cas où un emplacement a accepté la clé mais où l’ensemble d’emplacements ou le texte chiffré a été falsifié. Ce sont des affirmations de sécurité différentes, qui portent des codes différents (plus bas). Un appelant non fiable, en revanche, reçoit exactement une seule forme d’échec générique quelle qu’en soit la cause — aucun emplacement ouvert, l’ensemble d’emplacements a été falsifié, ou le tag du contenu a échoué — et la réponse ne révèle jamais quel cas s’est produit, ni quel emplacement a correspondu ; les codes typés sont un diagnostic interne réservé à un appelant local de confiance.
Le minutage suit un modèle explicite unique. Le vérificateur PEUT retourner au contrôle de non-correspondance — avant le déchiffrement du contenu — de sorte qu’un non-destinataire et un destinataire prennent un temps mesurablement différent. Cette différence ne révèle que destinataire contre non-destinataire, jamais quel emplacement a correspondu ni le moindre matériel de clé. Un minutage uniforme entre un non-destinataire et un destinataire dont le texte chiffré ne s’ouvre pas N’EST PAS exigé, et une ouverture de contenu factice NE DOIT PAS être imposée — elle infligerait le coût du déchiffrement du contenu à tout passant. La garantie à temps constant qui tient bel et bien est celle entre emplacements : au sein de la passe d’une seule clé privée, la boucle parcourt tous les emplacements avec des comparaisons à temps constant, de sorte que rien ne fuite quel emplacement, le cas échéant, cette clé déballe.
Finalité : profondeur de confirmation
Le règlement de Cardano est probabiliste. Une transaction profonde d’un seul bloc peut
encore se retrouver orpheline à la suite d’une réorganisation courte ; une transaction
profonde de nombreux blocs est réglée avec une probabilité écrasante. Un vérificateur
qui qualifierait de valid un enregistrement profond d’un seul bloc permettrait à un
attaquant de réancrer un enregistrement contradictoire sur une bifurcation concurrente
et de récolter un verdict « valid » sur les deux — brisant en silence l’hypothèse
d’ajout seul sur laquelle repose toute la preuve.
C’est pourquoi un vérificateur rapporte l’enregistrement comme pending, et non
failed, tant qu’il se situe en deçà d’un seuil de profondeur de confirmation. Le
seuil d’usage général RECOMMANDÉ est de ≥ 15 blocs (environ cinq minutes). Le
seuil relève de la politique du vérificateur, et non d’une constante de sérialisation :
les déploiements traitant des enregistrements de grande valeur ou à caractère probatoire
DEVRAIENT l’élever vers la finalité ferme, et un vérificateur DOIT exposer le
seuil qu’il a utilisé afin que les consommateurs puissent y superposer une politique
plus stricte. Un enregistrement pending est bien formé et sur la chaîne ; il n’a
simplement pas encore réglé à une profondeur suffisante, et peut se résoudre en valid
lors d’une nouvelle tentative ultérieure.
La profondeur de confirmation, la hauteur de bloc et l’heure du bloc sont des faits
affirmés par l’explorateur que le vérificateur ne fabrique jamais. La liaison à la
référence de transaction rend le contenu de la transaction sans confiance requise,
mais les faits de chaîne à son sujet ne sont pas dérivables des octets — le CBOR de la
transaction ne porte ni horodatage ni hauteur. La profondeur se calcule comme
(hauteur du tip de l’explorateur qui résout) − (hauteur du bloc d’inclusion) + 1, de
sorte qu’une transaction dans le bloc de tip a une profondeur exactement égale à 1 ;
l’heure du bloc est l’horodatage POSIX (secondes entières, UTC) de l’emplacement du bloc
d’inclusion, pris dans le champ temporel de l’explorateur, jamais recalculé par le
vérificateur. Parce que ces faits reposent sur la parole de l’explorateur, un
vérificateur DEVRAIT les résoudre auprès d’au moins deux explorateurs indépendants
et signaler toute divergence ; les déploiements pour lesquels l’heure du bloc est
déterminante — notarisation légale, litiges sur des échéances — DOIVENT la
contre-vérifier. Le rapport porte la profondeur résolue à côté du seuil auquel elle a
été comparée, ainsi que block_time (avec block_slot lorsqu’il est disponible).
États du verdict
Un vérificateur conclut par l’un de quatre verdicts lisibles par machine, chacun
apparié un à un avec un code de sortie de processus, de sorte qu’un appelant — une
barrière de CI, un moniteur, un script — puisse distinguer un échec attribuable à
l’enregistrement d’un échec opérationnel transitoire sans analyser le rapport structuré.
La ligne directrice est l’attribution : condamner un enregistrement exige des
preuves que les octets propres de l’enregistrement — ou des octets liés de manière
attribuable à ses références — fournissent réellement. Aucun comportement fautif d’un
fournisseur ne peut fabriquer un failed.
| Verdict | Sortie | Signification |
|---|---|---|
| valid | 0 | tout contrôle exécuté par le vérificateur a renvoyé ok ; aucune anomalie de sévérité error n’est présente. |
| failed | 1 | un échec attribuable à l’enregistrement : le validateur structurel a rejeté les octets, une signature n’a pas vérifié, une empreinte attribuable n’a pas concordé, la transaction liée ne porte aucune métadonnée sous le label 309 (METADATA_NOT_FOUND), ou une règle de host refusé s’est déclenchée. |
| unverifiable | 2 | aucune erreur attribuable à l’enregistrement, mais un contrôle requis n’a pu s’exécuter ou n’a pu être attribué — la transaction n’a pas résolu, aucune réponse de fournisseur n’a survécu à la liaison (TX_INTEGRITY_MISMATCH), ou le contenu/texte chiffré engagé n’a pu être obtenu ni attribué. Le même enregistrement peut vérifier valid lors d’une nouvelle tentative ou sous une autre passerelle. |
| pending | 3 | structurellement bien formé et sur la chaîne, mais en deçà du seuil de profondeur de confirmation (INSUFFICIENT_CONFIRMATIONS) ; peut régler. Aucun résultat issu d’un enregistrement pending ne peut être présenté comme définitif. |
Les défaillances d’exécution de l’hôte du vérificateur qui ne sont pas attribuables à l’enregistrement utilisent les codes de sortie 4 et au-delà et ne correspondent à aucun verdict.
Un verdict valid NE DOIT PAS être rapporté lorsqu’une anomalie de sévérité
error est présente ; un enregistrement PEUT être valid avec une liste
warnings et/ou info non vide. Aucune des deux couches ne peut « adoucir » une erreur
en avertissement pour faire passer un enregistrement. Chaque verdict est réservé à son
propre cas : pending n’est jamais substitué à valid ou failed, et un échec
attribuable à un fournisseur est unverifiable, jamais failed.
Un plancher d’engagement régit la disponibilité : lorsque le contrôle de contenu
s’est exécuté mais que des échecs de disponibilité n’ont laissé aucun engagement de
contenu de l’enregistrement effectivement vérifié, le verdict est unverifiable, jamais
valid — un verdict valid signifie qu’au moins un engagement de contenu a été
contrôlé. Les résultats d’intégrité sont indifférents au plancher : des octets
attribuables qui échouent à un engagement produisent failed, quel que soit ce qui était
disponible par ailleurs.
Liaison à l’adresse de contenu et attribution
L’étape 8 (et, pour le vérificateur destinataire, le déchiffrement) récupère des octets auprès de passerelles de stockage adressé par le contenu que le vérificateur a choisies — et les passerelles ne sont pas de confiance. La ligne de verdict ci-dessus tient à une unique question à laquelle le vérificateur DOIT pouvoir répondre pour chaque flux d’octets récupéré : ces octets peuvent-ils être attribués à l’URI lui-même ? Les deux schémas sont adressés par le contenu, donc ils le peuvent :
ipfs://— recalculer le CID sur le contenu récupéré (le multihash directement pour un CID à codec brut ; les condensés bloc par bloc le long du chemin résolu pour un CID en forme de DAG).ar://— valider la transaction Arweave signée et recalculer l’arbre de Merkle des fragments par rapport à sondata_root; pour un élément de données ANS-104, recalculer le deep-hash, vérifier la signature du propriétaire et contrôler que le SHA-256 de la signature est égal à l’id de l’URI.
Les octets qui satisfont les condensés propres de l’enregistrement ne nécessitent aucun contrôle de liaison — l’engagement de l’enregistrement est au moins aussi fort que celui de la couche de stockage. Là où la liaison est appliquée, l’attribution décide de ce que signifie une discordance :
- Octets attribuables — liaison vérifiée, ou fournis hors bande par l’appelant —
sont imputés à l’enregistrement lorsqu’ils échouent à un engagement :
URI_INTEGRITY_MISMATCHpour le contenu d’un élément (un échec d’intégrité dur, quel que soit ce que contient un URI frère), la familleMERKLE_*pour une liste de feuilles,TAMPERED_CIPHERTEXTpour un blob de texte chiffré attribuable. Verdictfailed. - Octets non attribuables — liaison non vérifiée, ou vérifiée et échouée —
incriminent le fournisseur qui les sert, jamais l’enregistrement :
URI_PROVIDER_INTEGRITY_MISMATCH(avertissement). Le vérificateur poursuit avec les URI et passerelles restants ; une affirmation laissée sans octets attribuables se termine par un résultat de disponibilité (CONTENT_UNAVAILABLE,MERKLE_LEAVES_UNAVAILABLE,CIPHERTEXT_UNAVAILABLE), verdictunverifiable— exactement comme si rien n’avait été récupéré.
C’est la contrepartie, côté stockage, de la liaison à la référence de transaction : une
passerelle au comportement fautif ne peut dégrader que la disponibilité, jamais le
verdict. URI_INTEGRITY_MISMATCH et URI_PROVIDER_INTEGRITY_MISMATCH sont donc des
codes distincts — le premier condamne l’enregistrement, le second condamne un
fournisseur — et un vérificateur qui les confondrait laisserait une passerelle hostile
forger un failed. La re-vérification de l’empreinte du texte en clair après
déchiffrement n’a besoin d’aucun qualificatif d’attribution : un texte chiffré qui
s’ouvre sous l’enveloppe authentifiée est attribué par l’AEAD lui-même, de sorte qu’une
discordance d’empreinte de texte en clair à ce stade (URI_INTEGRITY_MISMATCH) est
toujours attribuable à l’enregistrement et force failed.
Le catalogue typé des erreurs
Chaque mode d’échec se résout en un code issu d’un unique catalogue fermé. Les codes
sont en SCREAMING_SNAKE_CASE, et une implémentation conforme DOIT émettre
exactement ces chaînes — jamais un code interne en minuscules d’un analyseur, jamais un
message en forme libre. Deux implémentations dans deux langages atteignant la même
entrée émettent le même code ; la liste normative complète est fixée octet par octet par
la suite de tests de conformité, et le catalogue est verrouillé (les codes ne s’ajoutent
que par amendement).
Modèle de sévérité
Chaque anomalie porte l’une de trois sévérités, et la distinction est déterminante :
- error — invalide le verdict. Un résultat
validne peut coexister avec aucunerror. - warning — une anomalie non fatale à l’exécution (une seule passerelle a échoué,
une liste de feuilles n’était disponible que partiellement) qui n’empêche pas le
valid. - info — un non-contrôle délibéré : un aspect que le vérificateur a choisi de ne pas évaluer (un champ hors de son profil, un algorithme optionnel non reconnu). Une entrée info n’est pas une erreur adoucie et n’est jamais utilisée comme telle.
Un code fait bande à part : INSUFFICIENT_CONFIRMATIONS se mappe sur le verdict
pending plutôt que sur une sévérité, parce que l’enregistrement est bien formé et
n’attend que le règlement.
Familles d’erreurs
Le catalogue se regroupe en familles. Un ensemble représentatif — non exhaustif — de codes :
| Famille | Sévérité | Codes représentatifs |
|---|---|---|
| CBOR malformé / non canonique | error | MALFORMED_CBOR, CHUNK_TOO_LARGE |
| Schéma | error | SCHEMA_TYPE_MISMATCH, SCHEMA_MISSING_REQUIRED, SCHEMA_UNKNOWN_FIELD, SCHEMA_EMPTY_RECORD |
| Algorithme non pris en charge | error | UNSUPPORTED_HASH_ALG, UNSUPPORTED_AEAD_ALG, UNSUPPORTED_KEM_ALG, UNSUPPORTED_MERKLE_COMMIT_ALG |
| Explorateur / métadonnées | error / pending | TX_NOT_FOUND, PROVIDER_UNAVAILABLE, TX_INTEGRITY_MISMATCH (→ unverifiable), METADATA_NOT_FOUND (→ failed) ; INSUFFICIENT_CONFIRMATIONS (→ pending) |
| Signature | error / info | MALFORMED_SIG_COSE_SIGN1, SIGNER_KEY_UNRESOLVED, SIGNATURE_INVALID, WALLET_ADDRESS_MISMATCH ; SIGNATURE_UNSUPPORTED (info) |
| Chiffrement / KEM / enveloppe | error | KEM_EPK_LENGTH_MISMATCH, KEM_CT_LENGTH_MISMATCH, WRAP_LENGTH_MISMATCH, ENC_SLOTS_DUPLICATE_KEM_MATERIAL, ENC_SLOTS_TOO_MANY, ENC_ENVELOPE_TOO_LARGE, ENC_REQUIRES_CONTENT_HASH |
| Résultat du déchiffrement | error | WRONG_DECRYPTION_INPUT_SHAPE, WRONG_RECIPIENT_KEY, TAMPERED_HEADER, TAMPERED_CIPHERTEXT, KDF_DERIVATION_FAILED |
| URI / contenu | error / warning | INVALID_URI, URI_TARGET_FORBIDDEN, URI_INTEGRITY_MISMATCH, CONTENT_UNAVAILABLE (→ unverifiable), CIPHERTEXT_UNAVAILABLE (→ unverifiable) ; URI_PROVIDER_INTEGRITY_MISMATCH, URI_FETCH_FAILED (avertissements) |
| Engagement de liste Merkle | error / warning / info | MERKLE_ROOT_MISMATCH, SCHEMA_MERKLE_LEAF_COUNT_MISMATCH ; MERKLE_LEAVES_UNAVAILABLE (dual) ; MERKLE_UNSUPPORTED (dual) |
| Indépendance du service | error | SERVICE_INDEPENDENCE_VIOLATION |
Les codes de réseau/politique (TX_NOT_FOUND, PROVIDER_UNAVAILABLE,
CONTENT_UNAVAILABLE, CIPHERTEXT_UNAVAILABLE) — ainsi que TX_INTEGRITY_MISMATCH,
dont la discordance est prouvable contre les fournisseurs plutôt que contre
l’enregistrement — sont de sévérité error dans la liste des anomalies (ils bloquent un
verdict valid) mais ne sont pas attribuables à l’enregistrement, de sorte
qu’ils se mappent sur unverifiable, jamais sur failed.
URI_PROVIDER_INTEGRITY_MISMATCH est l’avertissement par récupération sous le même
principe. Quelques codes portent une double sévérité — ENC_UNSUPPORTED,
MERKLE_UNSUPPORTED, OUT_OF_PROFILE_SKIPPED et MERKLE_LEAVES_UNAVAILABLE — se
lisant info/warning par défaut et se promouvant en error dans un contexte strict
(le rôle destinataire, l’escalade merkle-seul, le mode strict de bout en bout, ou le
plancher d’engagement).
Le chemin du destinataire est la famille la plus précise sur le plan diagnostique. Pour
un appelant local de confiance, un déchiffrement échoué se résout en l’un de trois
codes internes : WRONG_RECIPIENT_KEY signifie qu’aucun emplacement n’a accepté la clé
fournie (aucune clé de contenu n’a jamais été récupérée) ; TAMPERED_HEADER signifie
qu’une clé a été récupérée mais que la clé de contenu candidate n’a pas reproduit
slots_mac sur slots_hash (un emplacement, un champ d’en-tête, ou slots_mac
lui-même a été altéré) ; TAMPERED_CIPHERTEXT signifie que l’ensemble d’emplacements
était intact mais que le tag AEAD du contenu a échoué après récupération de la clé. Les
trois sont structurellement distinguables pour cet appelant local, et la frontière entre
eux ne laisse fuir aucun matériel de clé. Pour un appelant externe non fiable, les
trois s’effondrent en l’unique échec générique décrit plus haut, indiscernables par la
forme de la réponse. Sous le modèle de minutage, un retour anticipé permis sur la
non-correspondance sépare WRONG_RECIPIENT_KEY (un non-destinataire) des deux résultats
de falsification côté destinataire, lesquels ne portent entre eux aucune distinction
supplémentaire — de sorte que la précision diagnostique ne devient jamais un oracle
sélectif par emplacement ou par clé.
Comment les codes se mappent sur les quatre verdicts
Un code émis par le validateur structurel signifie que les octets de l’enregistrement ne
sont pas conformes. Le vérificateur public court-circuite le rapport avec le verdict
failed — sortie 1 — et la liste des anomalies du validateur, sans exécuter le moindre
travail supplémentaire de chaîne ou de cryptographie. Un code émis seulement après que
la validation structurelle a réussi — une signature qui n’a pas vérifié, une empreinte
attribuable qui n’a pas concordé, METADATA_NOT_FOUND sur la transaction liée — est
de même failed : chacun est attribuable à l’enregistrement, preuve que les octets
propres de l’enregistrement fournissent.
Un échec transitoire ou attribuable à un fournisseur relève d’un verdict différent : un
contenu qui n’a pu être récupéré ni attribué, un explorateur qui était injoignable, ou
un fournisseur qui a servi des octets échouant à la liaison à la référence de
transaction se mappent tous sur unverifiable — sortie 2 — parce qu’aucun n’est la
faute de l’enregistrement et que le même enregistrement peut vérifier valid lors d’une
nouvelle tentative. La distinction que le code de sortie préserve est donc à trois voies
parmi les états d’échec : failed attribuable à l’enregistrement (1), unverifiable
opérationnel ou attribuable à un fournisseur (2), et pending sous le seuil (3).
Quelques codes portent une sévérité dépendante du contexte. Un vérificateur lisant un
enregistrement plus riche que le profil qu’il déclare (par exemple un vérificateur de
seule empreinte rencontrant un élément scellé) rapporte le champ supplémentaire comme
info dans un contexte d’affichage et valide tout de même l’affirmation d’empreinte, ou
comme error dans un contexte d’audit strict de bout en bout. De même, un algorithme de
signature optionnel non reconnu est info — l’affirmation d’existence du contenu n’en
dépend pas — de sorte qu’une preuve publique de seule empreinte reste valid même
lorsqu’une signature à caractère consultatif n’est pas vérifiable.
L’indépendance du service n’est pas optionnelle
La vérification ne revient jamais vers le publicateur. Chaque appel sortant que réalise
un vérificateur conforme est dirigé vers une infrastructure que l’opérateur a choisie —
un explorateur Cardano pour la transaction, et des passerelles de stockage adressé par
le contenu pour tout octet ar:// ou ipfs://. Cela est imposé structurellement, et
non par une promesse de commentaire de code :
- Chaque appel réseau passe par un unique wrapper de sortie qui enregistre
url,method,status, le nombre d’octets et la finalité de chaque appel — succès, échec et nouvelle tentative confondus — dans une piste d’audit obligatoire sur le rapport. Un vérificateur incapable de produire cette piste ne peut prouver son indépendance. - Ce wrapper accepte une liste de hosts refusés fournie par le déploiement et fait
échouer de façon tranchante tout appel vers un host correspondant avec
SERVICE_INDEPENDENCE_VIOLATION. La liste est une entrée de l’opérateur — une suite de conformité la remplit avec les propres domaines de l’implémenteur — et non une constante de sérialisation de Label 309. - Un harnais de conformité exécute le vérificateur contre des transactions de fixture
figées dans un réseau où les propres domaines de l’opérateur ne résolvent nulle part,
et affirme que le vérificateur renvoie tout de même
valid. L’affirmation est faite à la couche réseau du système d’exploitation, et non en grepant le code source — un vérificateur atteignant un host interdit par une IP codée en dur passerait un balayage du source mais échouerait à ce test.
Le vérificateur a besoin d’un explorateur Cardano joignable et de rien de spécifique à l’implémenteur. Les passerelles de contenu, une clé privée de destinataire et une liste de feuilles hors chaîne sont des entrées optionnelles qui débloquent respectivement les contrôles de contenu, de destinataire et de Merkle. Aucune d’elles n’est un service que le standard nomme, et aucune d’elles n’est le publicateur.
Pages connexes
- L’enregistrement — le format de sérialisation par rapport auquel le validateur structurel effectue ses contrôles : le label 309, la forme de la carte, le réassemblage des fragments et le schéma CDDL.
- Signatures — la construction COSE_Sign1 au niveau de l’enregistrement, la charge utile à séparation de domaine et les règles de vérification stricte d’Ed25519.
- PoE scellée — l’enveloppe de chiffrement, les emplacements de clé du destinataire et le déballage que le vérificateur destinataire effectue.
PoE scellée
L’enveloppe de chiffrement de Label 309 : comment un expéditeur scelle un contenu vers une ou plusieurs clés de destinataire, tandis que la chaîne ne transporte que l’empreinte du texte en clair et les emplacements de clé enveloppés, jamais le texte en clair et jamais les destinataires.
Modèle de sécurité
Ce à quoi un vérificateur Label 309 fait confiance et ce à quoi il ne fait pas confiance : l’invariant de vérifiabilité autonome, les garanties de confidentialité de la PoE scellée, les règles cryptographiques normatives que toute implémentation doit respecter et les limites connues du format de sérialisation (wire format).