Verifizierung
Die drei Verifizierer-Rollen von Label 309, die Verdikt-Zustände, die Bestätigungstiefe und der typisierte Fehlerkatalog, also wie jede prüfende Stelle allein aus öffentlicher Infrastruktur zur selben Antwort gelangt.
Label 309 wird verifiziert, nicht behauptet. Wer veröffentlicht, verankert einen Inhalts-Hash unter label 309 in der Cardano-Blockchain; von da an steht der Anspruch allein auf seinen eigenen Bytes, und jede Stelle, die über die Transaktionsreferenz verfügt, kann ihn überprüfen. Diese Seite beschreibt, wie diese Prüfung abläuft: die drei Verifizierer-Rollen, was jede einzelne anfasst und was nicht, die Verdikt-Zustände, die sie ausgeben, die Bestätigungstiefe, unterhalb derer ein Verdikt vorläufig bleibt, und den typisierten Fehlerkatalog, der dafür sorgt, dass zwei unabhängige Implementierungen bei derselben Eingabe denselben Fehler melden.
Die entscheidende Eigenschaft ist die Dienstunabhängigkeit. Ein konformer Verifizierer erreicht sein Verdikt allein über die öffentliche Chain, einen vom Verifizierer selbst gewählten Cardano-Explorer oder ein entsprechendes Gateway und, für Inhalts- und versiegelte Ansprüche, über inhaltsadressierte Speicher-Gateways, die der Verifizierer ebenfalls selbst auswählt. Er kontaktiert nie die veröffentlichende Stelle. Der Standard nennt keinen bestimmten Anbieter; das Gateway ist eine Eingabe, die der Betreiber bereitstellt.
Drei Rollen, jede eine strikte Erweiterung
Die Verifizierung ist in Schichten aufgebaut. Jede Rolle leistet alles, was die Rolle über ihr leistet, und fügt eine Fähigkeit hinzu. Eine niedrigere Rolle ist für sich genommen ein vollständiger, nützlicher Verifizierer, sie weist schlicht weniger nach.
| Rolle | Fügt hinzu | Fasst an |
|---|---|---|
| Struktureller Validator | Schema- und Domänenkonformität über die Bytes des Datensatzes | nichts, eine reine Funktion |
| Öffentlicher Verifizierer | Chain-Auflösung, On-Chain-Aufnahme, Signaturprüfungen | einen Cardano-Explorer und Inhalts-Gateways |
| Empfänger-Verifizierer | Probeentschlüsselung versiegelter Nutzdaten, Neuberechnung des Klartext-Hashes | den eigenen privaten Schlüssel des Verifizierers |
Struktureller Validator: eine reine Funktion über die Bytes
Der strukturelle Validator ist eine einzige Funktion von einer Byte-Zeichenkette zu einem Ergebnis. Er führt keinerlei I/O, keine kryptografischen Signaturprüfungen und keine Entschlüsselung durch. Er sieht nie ein Netzwerk, eine Transaktion oder einen Schlüssel. Bei gleicher Eingabe liefert er jedes Mal, überall, dieselbe Ausgabe. Genau das erlaubt es, ihn vor der Übermittlung im Werkzeugkasten der veröffentlichenden Stelle, in einem Drittanbieter-Indexer oder in einem Archivierungswerkzeug laufen zu lassen, das die langfristige Wohlgeformtheit bestätigt, und das alles ohne Server.
Seine Verarbeitungskette ist festgelegt:
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.Der Validator ist profilunabhängig: Er parst das vollständige v1-Schema, unabhängig
davon, auf welcher Teilmenge ein nachgelagerter Verifizierer tätig werden will.
Fehler lassen den Datensatz scheitern; Warnungen und Info-Einträge werden ausgewiesen,
lassen ihn aber gültig. Entscheidend ist: Er bestätigt die Form eines COSE_Sign1,
also ein Array aus vier Elementen, abgetrennte (null) Nutzdaten, einen wohlgeformten
geschützten Header, verifiziert aber nie die Signatur, und er verwirft einen
Datensatz nie allein deshalb, weil das Signaturverfahren eines ist, das er nicht
kennt (das wird mit SIGNATURE_UNSUPPORTED gekennzeichnet, Schweregrad info, und
der Datensatz bleibt gültig). Die Signatur zu verifizieren ist Aufgabe des
öffentlichen Verifizierers. Welches Schema dieser Durchlauf durchsetzt, ist unter
Der Datensatz beschrieben.
Öffentlicher Verifizierer: Chain, Aufnahme und Signaturen
Der öffentliche Verifizierer legt die Chain über den strukturellen Validator. Bei einer gegebenen Cardano-Transaktionsreferenz tut er Folgendes:
- Er löst einen vom Verifizierer gewählten Explorer auf. Die Explorer-Kette ist
eine Eingabe; der Verifizierer probiert sie der Reihe nach durch und ruft dabei das
rohe On-Chain-Transaktions-CBOR ab – nie die Metadaten-JSON-Projektion des
Explorers. Die JSON-Sicht fasst CBOR-Haupttypen zu einer JSON-Union zusammen und
verwirft die Reihenfolge der Map-Schlüssel, die Rahmung mit definiter Länge sowie
die Unterscheidung zwischen Bytes und Text, sodass ein Verifizierer, der daraus neu
kodierte, die byte-exakte Signiereingabe nicht reproduzieren könnte und jede
Signatur eines konformen Datensatzes scheitern würde. Die negative Antwort eines
einzelnen Anbieters ist nicht chain-maßgeblich – die Transaktion kann on-chain
und diesem Anbieter lediglich unbekannt sein –, sodass der Verifizierer jeden
verbleibenden Anbieter konsultiert, bevor er
TX_NOT_FOUNDausgibt; ist jeder Anbieter nicht erreichbar, gibt erPROVIDER_UNAVAILABLEaus. - Er bindet die abgerufenen Bytes an die Transaktionsreferenz. Bevor der
Verifizierer irgendetwas aus einer abgerufenen Transaktion liest, berechnet er
blake2b-256über die abgerufenen Transaktionskörper-Bytes neu – per Ledger-Definition die Transaktions-ID – und weist die Antwort bei jeder Abweichung vom angefragten Hash zurück. Danach berechnet erblake2b-256über die abgerufenen Auxiliary-Data-Bytes neu und weist bei jeder Abweichung vom nun verifiziertenauxiliary_data_hashdes Körpers zurück. Beide Digests werden über die Bytes exakt so, wie sie abgerufen wurden berechnet, nie über eine Neukodierung. Eine Antwort, die eine der beiden Prüfungen nicht besteht, trägt nachweislich falsche Bytes und wird verworfen; liefert kein Anbieter eine Antwort, die die Bindung übersteht, trägt der BerichtTX_INTEGRITY_MISMATCH. Nach diesem Schritt ist jedes Byte des Datensatzes und der umgebenden Transaktion kryptografisch an den vom Aufrufer gelieferten Hash gebunden – kein Explorer kann den Datensatz austauschen, ändern oder abschneiden, ohne ein blake2b-256-Second-Preimage zu erzeugen. - Er entpackt die Auxiliary Data. Das Ledger der Conway-Ära lässt drei
Auxiliary-Data-Kodierungen zu, alle gültig: eine nackte ungetaggte Metadaten-Map,
ein zweielementiges
[ metadata, scripts ]-Array und eine Tag-259-Map mit den Metadaten unter Schlüssel0. Der Verifizierer MUSS alle drei akzeptieren und ausschließlich anhand des CBOR-Haupttyps und -Tags auf oberster Ebene unterscheiden – ein Tag-259-Wert ist die Form mit Schlüssel-Map, ein ungetaggtes Array ist die zweielementige Form, und eine ungetaggte Map ist stets die Metadaten-Map selbst. Er DARF die Schlüssel einer Map NICHT prüfen, um die Form zu erraten; jede andere Form auf oberster Ebene oder jeder andere Tag als 259 istMALFORMED_CBOR. Trägt die gebundene Transaktion keine label-309-Metadaten, gibt der VerifiziererMETADATA_NOT_FOUNDaus – ein dem Datensatz zurechenbares Ergebnis, denn die gebundene Transaktion selbst beweist die Abwesenheit: Kein Anbieter hätte die Metadaten entfernen können, ohne die Bindung zu verfehlen. - Er setzt das Chunk-Array über den gesamten Körper wieder zusammen. Der Wert unter label 309 ist der kanonisch CBOR-kodierte Datensatzkörper, aufgeteilt in ein Array von Byte-Zeichenketten mit jeweils ≤ 64 Byte. Der Verifizierer verkettet die Elemente byteweise in ihrer Reihenfolge und gibt die rohen Bytes zurück, ohne sie neu zu kodieren, sodass die kanonische CBOR-Prüfung eine nichtkonforme On-Chain-Kodierung weiterhin erkennen kann.
- Er validiert strukturell den wieder zusammengesetzten Körper (die Rolle über
ihm). Eine Ablehnung durch den Validator schließt den Bericht mit dem Verdikt
failedkurz. - Er prüft die Bestätigungstiefe (siehe unten). Eine Transaktion unterhalb des
Schwellenwerts hält hier mit dem Verdikt
pendingan. - Er verifiziert jede Signatur auf Datensatzebene unter striktem Ed25519. Er entschlüsselt nicht. Die Auflösung der Signatur, die domänengetrennten Nutzdaten und die strikten Verifizierungsregeln sind unter Signaturen festgelegt.
- Er ruft Inhalt ab und prüft Hashes, wobei er den Datensatz nur für Bytes zur Rechenschaft zieht, die er der eigenen Inhaltsadresse einer URI zurechnen kann (siehe unten). Er entschlüsselt nicht.
Warum rohes CBOR, nicht JSON
Eine Signatur wird über das byte-exakte kanonische CBOR des Datensatzkörpers berechnet. Eine JSON-Projektion von Metadaten ist konstruktionsbedingt verlustbehaftet und kann nicht verlustfrei zu diesen Bytes zurückführen. Ein erneutes Kodieren aus JSON bricht jede Signatur eines konformen Datensatzes. Das rohe Transaktions-CBOR ist die einzige maßgebliche Eingabe für jede kryptografische Prüfung; eine JSON-Sicht dient der Darstellung für Menschen, nachdem die Verifizierung bereits bestanden wurde.
Empfänger-Verifizierer: entschlüsseln und neu berechnen
Der Empfänger-Verifizierer ist ein öffentlicher Verifizierer, der zusätzlich einen privaten Schlüssel besitzt. Bei einem versiegelten Eintrag, der an ihn adressiert ist, entschlüsselt er probeweise die On-Chain-Schlüsselslots mit seinem Schlüssel, gewinnt bei Erfolg den Inhaltsschlüssel zurück, entschlüsselt den Chiffretext und berechnet anschließend die Klartext-Hashes neu, um sie gegen die On-Chain-Verpflichtung zu prüfen. So schließt sich der Kreis zwischen den verschlüsselten Bytes und dem Anspruch auf die Existenz des Inhalts. Da jeder versiegelte Eintrag mindestens einen Inhalts-Hash-Eintrag trägt, hat diese Neuberechnung stets etwas Konkretes zum Vergleich. Der versiegelte Umschlag, die Schlüsselslots und die Konstruktion zum Entpacken sind unter Versiegelte PoE festgelegt.
Bevor der Empfänger ein KEM- oder AEAD-Primitive anfasst, wendet er erneut dieselben
Form- und Ressourcenprüfungen des Umschlags an, die der strukturelle Validierer bereits
ausgeführt hat, und weist zuerst einen strukturell ungültigen oder übergroßen Umschlag
zurück. Zwei dieser vorgelagerten Schutzmaßnahmen sind deployment-festgelegte
Ressourcengrenzen, keine Wire-Felder: Die Referenzgrenzen sind MAX_SLOTS = 1024 Slots
und 65536 Bytes für den dekodierten enc-Umschlag, beide weit über der
~16-KiB-Metadatengrenze von Cardano, die jeden ehrlichen Datensatz deckelt, sodass ein
Datensatz, der eine der beiden überschreitet, fehlgeformt ist und vor dem Lauf eines
einzigen Primitives mit ENC_SLOTS_TOO_MANY oder ENC_ENVELOPE_TOO_LARGE
zurückgewiesen wird. Deployments DÜRFEN sie verschärfen.
Eine Formprüfung ist sicherheitstragend: Das Kapselungsmaterial MUSS innerhalb eines
slots[] eindeutig sein, also alle epk-Werte bei x25519 oder alle
kem_ct-Werte bei mlkem768x25519. Eine Dublette innerhalb des
Datensatzes wird mit ENC_SLOTS_DUPLICATE_KEM_MATERIAL zurückgewiesen, bevor irgendein
KEM- oder AEAD-Primitive läuft, denn ein wiederholtes epk/kem_ct würde die
Eindeutigkeit des Slot-Schlüssels brechen, auf die sich der Null-Nonce-wrap stützt.
Schlüsselwiederverwendung über Datensätze oder Schlüssel hinweg ist eine Erzeugerpflicht
und nicht verifizierer-erkennbar; nur die Dublette innerhalb des Datensatzes ist es. Alle
drei Prüfungen sind strukturell: Der Validierer setzt sie bei jedem Datensatz durch (die
Codes für doppeltes Material, Slot-Anzahl und dekodierten Umschlag sind Part-A-Codes);
der Empfänger führt sie schlicht als Verteidigung in der Tiefe erneut aus.
Das Entpacken selbst sind zwei kryptografische Schritte, die der Empfänger aus dem
Umschlag reproduziert, nie aus einer Nebeneingabe. Zuerst berechnet er den
Transkript-Hash der Slots slots_hash einmal, vor der Schleife, und hält ihn über
jeden Slot konstant:
slots_hash = SHA-256("cardano-poe-slots-transcript-v1" || canonicalEncode(SLOTS_TRANSCRIPT)),
wobei das Transkript die Header-Felder, die On-Wire-Slot-Menge (jedes Slot-Feld ein
einzelner Byte-String – es gibt keine Stückelung pro Feld zu normalisieren) und den
Hash-Anspruch des Elements über hashes_hash festschreibt. Die Bindung von
hashes_hash ist es, die dem Empfänger erlaubt, allein aus On-Chain-Bytes zu
bestätigen, dass der Umschlag für genau diesen Hash-Anspruch versiegelt wurde – noch
vor jedem Chiffretext-Abruf; ein Umschlag, der auf ein Element mit einer anderen
hashes-Map gespleißt wurde, scheitert am MAC. Er iteriert alle Slots ohne
vorzeitigen Abbruch; ein Slot wird nur dann akzeptiert, wenn der Inhaltsschlüssel, den
er ergibt, auch den On-Wire-slots_mac über diesen konstanten slots_hash reproduziert. Die Annahme bezieht zudem ein
geheimnisunabhängiges Gültigkeitsbit ein: Auf dem klassischen Pfad setzt ein Slot,
der das gemeinsame X25519-Geheimnis auf den Nullbyte-Wert treiben soll, dieses Bit auf
falsch (ein Konstantzeitvergleich gegen 0^32), der KEK wird in konstanter Zeit auf
einen aus 0^32 abgeleiteten Dummy ausgewählt, sodass die Schleife identische Arbeit
leistet, und das Bit steuert die Annahme des Slots: Ein Slot mit ungültigem ECDH kann
nie öffnen, unabhängig von seinem Wrap oder MAC. Sowohl das Öffnen des Wrap als auch das
spätere Öffnen des Inhalts sind atomar: Bei einem Fehlschlag des AEAD-Tags geben sie
keinen Klartext zurück, und der Kandidat, den sie zurückreichen (der umhüllte Schlüssel
oder der Inhalts-Klartext), ist ein fester oder pseudozufälliger Dummy, der vom
fehlgeschlagenen Chiffretext unabhängig ist; nie wird unverifizierter Klartext
freigegeben.
Ein Empfängerschlüssel DARF rechtmäßig mehr als einen Slot treffen: Ein Erzeuger
darf denselben Inhaltsschlüssel an denselben Empfänger in mehreren Slots versiegeln,
jeweils mit frischem KEM-Material pro Slot, um die Empfängeranzahl aufzufüllen, eine
gültige Datenschutztechnik und verschieden von der Ablehnung doppelten Kapselungsmaterials,
die allein bei einem identischen epk/kem_ct greift. Der Verifizierer wählt den
Schlüssel des ersten Treffers und DARF NICHT allein deshalb ablehnen, weil
mehrere Slots getroffen haben. Die einzige Anomalie, die er ablehnen MUSS, sind zwei
treffende Slots, die unterschiedliche Inhaltsschlüssel wiederherstellen (in
konstanter Zeit verglichen): Die Schleife führt ein cek_conflict-Bit mit und fördert
den einzelnen generischen Fehlschlag zutage, falls irgendein späterer Treffer einen
Schlüssel ergibt, der vom ausgewählten abweicht. Das ist Verteidigung in der Tiefe: Unter
dem Commitment auf die Slot-Menge ist ein Treffer mit abweichendem Schlüssel bereits
unmöglich, sodass die Prüfung schlicht „fail closed“ fällt.
Dann leitet er auf dem zurückgewonnenen Inhaltsverschlüsselungsschlüssel den
Inhaltsschlüssel ab (ein HKDF-Blatt dieses Schlüssels, gesalzen mit enc.nonce) und
öffnet den Chiffretext des segmentierten STREAM Chunk für Chunk, wobei er den Tag
jedes Chunks verifiziert, bevor er dessen Klartext freigibt. Die AAD pro Chunk ist leer:
Aller Header-Kontext ist bereits transitiv über slots_mac an den Schlüssel gebunden,
sodass das Umkippen eines Header-Felds ändert, was der Empfänger ableitet, und der Stream
sich nicht öffnen lässt. Eine Abschneidung wird durch das Final-Flag erkannt – ein
fehlender finaler Chunk, Daten danach, ein Final-Flag auf einem nicht-finalen Chunk oder
ein zu kurzer nicht-finaler Chunk scheitern allesamt als TAMPERED_CIPHERTEXT. Das
segmentierte Format erlegt keine kryptografische Nutzlast-Obergrenze auf (der
88-Bit-Chunk-Zähler lässt 2^88 Chunks zu); ein praktisches Maximum ist eine
Denial-of-Service-Richtlinie des Deployments, inkrementell durchgesetzt, während der
Stream gelesen wird. Auf dem Passphrase-Pfad liest der Empfänger zuerst den führenden
32-Byte-Commitment-Header und vergleicht ihn in konstanter Zeit, bevor er irgendeinen
Chunk öffnet.
Beim Empfängerpfad zahlt sich die Präzision des Fehlerkatalogs aus: Er unterscheidet den Fall, in dem kein Slot diesen Schlüssel angenommen hat (falscher Empfänger), vom Fall, in dem ein Slot den Schlüssel angenommen hat, aber das Slot-Set oder der Chiffretext manipuliert wurde. Das sind unterschiedliche Sicherheitsaussagen, und sie tragen unterschiedliche Codes (siehe unten). Ein nicht vertrauenswürdiger Aufrufer erhält jedoch genau eine generische Fehlschlag-Form, unabhängig von der Ursache, also kein Slot geöffnet, das Slot-Set wurde manipuliert oder das Inhalts-Tag scheiterte, und die Antwort verrät nie, welcher Fall eingetreten ist, noch welcher Slot getroffen hat; die typisierten Codes sind eine interne Diagnose allein für einen vertrauenswürdigen lokalen Aufrufer.
Das Timing folgt einem expliziten Modell. Der Verifizierer DARF an der Kein-Treffer-Prüfung zurückkehren, bevor die Inhaltsentschlüsselung beginnt, sodass ein Nicht-Empfänger und ein Empfänger messbar unterschiedlich lange brauchen. Dieser Unterschied verrät allein Empfänger-versus-Nicht-Empfänger, nie welcher Slot getroffen hat, und kein Schlüsselmaterial. Ein einheitliches Timing zwischen einem Nicht-Empfänger und einem Empfänger, dessen Chiffretext nicht aufgeht, ist NICHT erforderlich, und ein Dummy-Inhaltsöffnen DARF NICHT vorgeschrieben werden, denn es würde jedem Passanten die Kosten der Inhaltsentschlüsselung auferlegen. Die Konstantzeit-Garantie, die gilt, ist die Über-alle-Slots-Garantie: Innerhalb des Durchlaufs eines einzelnen privaten Schlüssels läuft die Schleife mit Konstantzeitvergleichen über alle Slots, sodass nichts darüber durchsickert, welchen Slot dieser Schlüssel entpackt, falls überhaupt einen.
Finalität: die Bestätigungstiefe
Die Cardano-Abwicklung ist probabilistisch. Eine Transaktion, die einen Block tief
liegt, kann durch eine kurze Reorganisation noch verwaisen; eine Transaktion, die
viele Blöcke tief liegt, hat sich mit überwältigender Wahrscheinlichkeit gefestigt.
Ein Verifizierer, der einen nur einen Block tiefen Datensatz als valid einstufen
würde, ließe einem Angreifer die Möglichkeit, einen widersprüchlichen Datensatz auf
einer konkurrierenden Fork neu zu verankern und für beide ein "valid"-Verdikt
einzusammeln, womit die Annahme des reinen Anhängens, auf der der gesamte Nachweis
beruht, stillschweigend zerbräche.
Deshalb meldet ein Verifizierer den Datensatz als pending, nicht als failed,
solange er unterhalb einer Schwelle für die Bestätigungstiefe liegt. Die
EMPFOHLENE Schwelle für den allgemeinen Gebrauch beträgt ≥ 15 Blöcke (rund
fünf Minuten). Die Schwelle ist eine Richtlinie des Verifizierers, keine
Wire-Konstante: Einsätze, die hochwertige oder beweisrelevante Datensätze behandeln,
SOLLTEN sie in Richtung harter Finalität anheben, und ein Verifizierer MUSS
die von ihm verwendete Schwelle ausweisen, damit Verbraucher darüber eine strengere
Richtlinie legen können. Ein pending-Datensatz ist wohlgeformt und on-chain; er hat
sich lediglich noch nicht tief genug gefestigt und kann sich bei einem späteren
erneuten Versuch zu valid auflösen.
Bestätigungstiefe, Blockhöhe und Blockzeit sind vom Explorer behauptete Tatsachen,
die der Verifizierer nie fabriziert. Die Bindung an die Transaktionsreferenz macht
den Inhalt der Transaktion vertrauenslos, aber die Chain-Tatsachen über sie sind
nicht aus den Bytes ableitbar – das Transaktions-CBOR trägt weder Zeitstempel noch
Höhe. Die Tiefe wird als (Tip-Höhe des auflösenden Explorers) − (Höhe des einschließenden Blocks) + 1 berechnet, sodass eine Transaktion im Tip-Block exakt die
Tiefe 1 hat; die Blockzeit ist der POSIX-Zeitstempel (ganze Sekunden, UTC) des Slots
des einschließenden Blocks, dem Zeitfeld des Explorers entnommen, nie vom Verifizierer
neu berechnet. Weil diese Tatsachen auf dem Wort des Explorers beruhen, SOLLTE ein
Verifizierer sie aus mindestens zwei unabhängigen Explorern auflösen und jede
Abweichung sichtbar machen; Einsätze, für die die Blockzeit beweistragend ist – rechtliche
Beurkundung, Fristenstreitigkeiten –, MÜSSEN sie gegenprüfen. Der Bericht trägt die
aufgelöste Tiefe neben der Schwelle, gegen die sie verglichen wurde, sowie block_time
(mit block_slot, sofern verfügbar).
Verdikt-Zustände
Ein Verifizierer schließt mit einem von vier maschinenlesbaren Verdikten ab, jedes
eins-zu-eins mit einem Prozess-Exit-Code gepaart, sodass eine aufrufende Stelle, etwa
ein CI-Gate, ein Monitor oder ein Skript, ein dem Datensatz zurechenbares Scheitern von
einem vorübergehenden betrieblichen Scheitern unterscheiden kann, ohne den
strukturierten Bericht parsen zu müssen. Der leitende Grundsatz ist die
Zurechenbarkeit: Einen Datensatz zu verurteilen, erfordert Beweise, die die eigenen
Bytes des Datensatzes – oder Bytes, die zurechenbar an seine Referenzen gebunden sind –
tatsächlich liefern. Kein Fehlverhalten eines Anbieters kann ein failed fabrizieren.
| Verdikt | Exit | Bedeutung |
|---|---|---|
| valid | 0 | jede vom Verifizierer ausgeführte Prüfung lieferte ok; kein Problem mit Schweregrad error liegt vor. |
| failed | 1 | ein dem Datensatz zurechenbares Scheitern: der strukturelle Validator hat die Bytes abgelehnt, eine Signatur ließ sich nicht verifizieren, ein zurechenbarer Hash stimmte nicht überein, die gebundene Transaktion trägt keine label-309-Metadaten (METADATA_NOT_FOUND) oder eine Deny-Host-Regel hat ausgelöst. |
| unverifiable | 2 | kein dem Datensatz zurechenbarer Fehler, aber eine erforderliche Prüfung ließ sich nicht ausführen oder nicht zurechnen – die Transaktion löste nicht auf, keine Anbieterantwort überstand die Bindung (TX_INTEGRITY_MISMATCH), oder festgelegter Inhalt/Chiffretext ließ sich nicht beschaffen oder zurechnen. Derselbe Datensatz kann bei einem erneuten Versuch oder unter einem anderen Gateway valid verifizieren. |
| pending | 3 | strukturell wohlgeformt und on-chain, aber unterhalb der Schwelle für die Bestätigungstiefe (INSUFFICIENT_CONFIRMATIONS); kann sich noch festigen. Kein Ergebnis eines ausstehenden Datensatzes darf als endgültig dargestellt werden. |
Laufzeitfehler auf der Verifizierer-Host-Seite, die dem Datensatz nicht zurechenbar sind, verwenden Exit-Codes 4 und höher und entsprechen keinem Verdikt.
Ein valid-Verdikt DARF NICHT gemeldet werden, wenn ein Problem mit Schweregrad
error vorliegt; ein Datensatz DARF valid sein mit einer nichtleeren Liste von
warnings und/oder info. Keine Schicht darf einen Fehler zu einer Warnung
"abmildern", um einen Datensatz durchzulassen. Jedes Verdikt ist seinem eigenen Fall
vorbehalten: pending tritt nie an die Stelle von valid oder failed, und ein dem
Anbieter zurechenbares Scheitern ist unverifiable, nie failed.
Eine Commitment-Untergrenze regelt die Verfügbarkeit: Lief die Inhaltsprüfung, aber
ließen Verfügbarkeitsfehler kein tatsächlich verifiziertes Inhalts-Commitment des
Datensatzes übrig, ist das Verdikt unverifiable, nie valid – ein valid-Verdikt
bedeutet, dass mindestens ein Inhalts-Commitment geprüft wurde. Integritätsergebnisse
bleiben von der Untergrenze unberührt: Zurechenbare Bytes, die ein Commitment nicht
erfüllen, ergeben failed, ungeachtet dessen, was sonst verfügbar war.
Inhaltsadressen-Bindung und Zurechenbarkeit
Schritt 8 (und, beim Empfänger-Verifizierer, die Entschlüsselung) ruft Bytes aus inhaltsadressierten Speicher-Gateways ab, die der Verifizierer gewählt hat – und Gateways sind nicht vertrauenswürdig. Die obige Verdikt-Linie dreht sich um eine einzige Frage, die der Verifizierer über jeden abgerufenen Byte-Strom beantworten können MUSS: Lassen sich diese Bytes der URI selbst zurechnen? Beide Schemata sind inhaltsadressiert, also können sie es:
ipfs://– die CID über den abgerufenen Inhalt neu berechnen (den Multihash direkt bei einer CID mit Raw-Codec; Block-für-Block-Digests entlang des aufgelösten Pfades bei einer CID in DAG-Form).ar://– die signierte Arweave-Transaktion validieren und den Chunk-Merkle-Baum gegen ihrendata_rootneu berechnen; bei einem ANS-104-Data-Item den Deep-Hash neu berechnen, die Owner-Signatur verifizieren und prüfen, dass der SHA-256 der Signatur der ID in der URI gleicht.
Bytes, die die eigenen Digests des Datensatzes erfüllen, brauchen keine Bindungsprüfung – das Commitment des Datensatzes ist mindestens so stark wie das der Speicherschicht. Wo die Bindung angewendet wird, entscheidet die Zurechenbarkeit, was eine Abweichung bedeutet:
- Zurechenbare Bytes – Bindung verifiziert oder vom Aufrufer außerhalb des Bandes
geliefert – werden dem Datensatz angerechnet, wenn sie ein Commitment nicht erfüllen:
URI_INTEGRITY_MISMATCHfür Element-Inhalt (ein harter Integritätsfehler, ungeachtet dessen, was eine Geschwister-URI trägt), dieMERKLE_*-Familie für eine Blattliste,TAMPERED_CIPHERTEXTfür einen zurechenbaren Chiffretext-Blob. Verdiktfailed. - Nicht zurechenbare Bytes – Bindung nicht verifiziert oder verifiziert und
gescheitert – belasten den Anbieter, nie den Datensatz:
URI_PROVIDER_INTEGRITY_MISMATCH(Warnung). Der Verifizierer fährt mit den verbleibenden URIs und Gateways fort; ein Anspruch, der ohne zurechenbare Bytes verbleibt, endet mit einem Verfügbarkeitsergebnis (CONTENT_UNAVAILABLE,MERKLE_LEAVES_UNAVAILABLE,CIPHERTEXT_UNAVAILABLE), Verdiktunverifiable– genau so, als wäre nichts abgerufen worden.
Dies ist das speicherseitige Gegenstück zur Bindung an die Transaktionsreferenz: Ein
sich fehlverhaltendes Gateway kann nur die Verfügbarkeit verschlechtern, nie das
Verdikt. URI_INTEGRITY_MISMATCH und URI_PROVIDER_INTEGRITY_MISMATCH sind daher
verschiedene Codes – der erste verurteilt den Datensatz, der zweite einen Anbieter –,
und ein Verifizierer, der sie vermengte, ließe ein feindseliges Gateway ein failed
fälschen. Die nachträgliche Klartext-Hash-Prüfung nach der Entschlüsselung braucht keinen
Zurechenbarkeits-Qualifizierer: Chiffretext, der unter dem authentifizierten Umschlag
aufgeht, ist durch das AEAD selbst zugerechnet, sodass eine Klartext-Hash-Abweichung dort
(URI_INTEGRITY_MISMATCH) stets dem Datensatz zurechenbar ist und failed erzwingt.
Der typisierte Fehlerkatalog
Jeder Fehlermodus löst sich zu einem Code aus einem einzigen geschlossenen Katalog
auf. Codes sind in SCREAMING_SNAKE_CASE, und eine konforme Implementierung MUSS
genau diese Zeichenketten ausgeben, nie den internen Kleinbuchstaben-Code eines
Parsers, nie eine frei formulierte Meldung. Zwei Implementierungen in zwei Sprachen,
die dieselbe Eingabe erhalten, geben denselben Code aus; die vollständige normative
Liste wird byte-exakt durch die Konformitäts-Testsuite festgehalten, und der Katalog
ist gesperrt (Codes werden nur per Änderung ergänzt).
Schweregrad-Modell
Jedes Problem trägt einen von drei Schweregraden, und die Unterscheidung trägt Gewicht:
- error: entwertet das Verdikt. Ein
valid-Ergebnis kann mit keinemerrorkoexistieren. - warning: eine nicht fatale Laufzeitanomalie (ein einzelnes Gateway ist
ausgefallen, eine Blattliste war nur teilweise verfügbar), die
validnicht blockiert. - info: ein bewusst ausgelassener Prüfschritt: ein Aspekt, den der Verifizierer gewählt hat, nicht zu bewerten (ein Feld außerhalb seines Profils, ein nicht erkanntes optionales Verfahren). Ein Info-Eintrag ist kein abgemilderter Fehler und wird nie als solcher verwendet.
Ein Code steht für sich: INSUFFICIENT_CONFIRMATIONS wird auf das Verdikt pending
abgebildet statt auf einen Schweregrad, weil der Datensatz wohlgeformt ist und nur
noch auf die Abwicklung wartet.
Fehlerfamilien
Der Katalog gruppiert sich in Familien. Ein repräsentativer, nicht vollständiger Satz von Codes:
| Familie | Schweregrad | Repräsentative Codes |
|---|---|---|
| Fehlerhaftes / nichtkanonisches CBOR | error | MALFORMED_CBOR, CHUNK_TOO_LARGE |
| Schema | error | SCHEMA_TYPE_MISMATCH, SCHEMA_MISSING_REQUIRED, SCHEMA_UNKNOWN_FIELD, SCHEMA_EMPTY_RECORD |
| Nicht unterstütztes Verfahren | error | UNSUPPORTED_HASH_ALG, UNSUPPORTED_AEAD_ALG, UNSUPPORTED_KEM_ALG, UNSUPPORTED_MERKLE_COMMIT_ALG |
| Explorer / Metadaten | error / pending | TX_NOT_FOUND, PROVIDER_UNAVAILABLE, TX_INTEGRITY_MISMATCH (→ unverifiable), METADATA_NOT_FOUND (→ failed); INSUFFICIENT_CONFIRMATIONS (→ pending) |
| Signatur | error / info | MALFORMED_SIG_COSE_SIGN1, SIGNER_KEY_UNRESOLVED, SIGNATURE_INVALID, WALLET_ADDRESS_MISMATCH; SIGNATURE_UNSUPPORTED (info) |
| Verschlüsselung / KEM / Wrap | 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 |
| Entschlüsselungsergebnis | error | WRONG_DECRYPTION_INPUT_SHAPE, WRONG_RECIPIENT_KEY, TAMPERED_HEADER, TAMPERED_CIPHERTEXT, KDF_DERIVATION_FAILED |
| URI / Inhalt | error / warning | INVALID_URI, URI_TARGET_FORBIDDEN, URI_INTEGRITY_MISMATCH, CONTENT_UNAVAILABLE (→ unverifiable), CIPHERTEXT_UNAVAILABLE (→ unverifiable); URI_PROVIDER_INTEGRITY_MISMATCH, URI_FETCH_FAILED (Warnungen) |
| Merkle-Listenverpflichtung | error / warning / info | MERKLE_ROOT_MISMATCH, SCHEMA_MERKLE_LEAF_COUNT_MISMATCH; MERKLE_LEAVES_UNAVAILABLE (dual); MERKLE_UNSUPPORTED (dual) |
| Dienstunabhängigkeit | error | SERVICE_INDEPENDENCE_VIOLATION |
Die Netzwerk-/Richtliniencodes (TX_NOT_FOUND, PROVIDER_UNAVAILABLE,
CONTENT_UNAVAILABLE, CIPHERTEXT_UNAVAILABLE) – und TX_INTEGRITY_MISMATCH, dessen
Abweichung gegen die Anbieter statt gegen den Datensatz beweisbar ist – haben in der
Problemliste den Schweregrad error (sie blockieren ein valid-Verdikt), sind aber
nicht dem Datensatz zurechenbar, sodass sie auf unverifiable abbilden, nie auf
failed. URI_PROVIDER_INTEGRITY_MISMATCH ist die Pro-Abruf-Warnung nach demselben
Grundsatz. Einige Codes tragen einen doppelten Schweregrad – ENC_UNSUPPORTED,
MERKLE_UNSUPPORTED, OUT_OF_PROFILE_SKIPPED und MERKLE_LEAVES_UNAVAILABLE –, die
standardmäßig als info/warning gelesen werden und in einem strikten Kontext (der
Empfängerrolle, der Merkle-only-Eskalation, dem strikten durchgängigen Modus oder der
Commitment-Untergrenze) auf error heraufgestuft werden.
Der Empfängerpfad ist die diagnostisch präziseste Familie. Für einen
vertrauenswürdigen lokalen Aufrufer löst sich eine gescheiterte Entschlüsselung zu
einem von drei internen Codes auf: WRONG_RECIPIENT_KEY bedeutet, dass kein Slot den
gelieferten Schlüssel angenommen hat (es wurde nie ein Inhaltsschlüssel zurückgewonnen);
TAMPERED_HEADER bedeutet, dass ein Schlüssel zurückgewonnen wurde, aber der
Kandidaten-Inhaltsschlüssel slots_mac über slots_hash nicht reproduzierte (ein
Slot, ein Header-Feld oder slots_mac selbst wurde verändert); TAMPERED_CIPHERTEXT
bedeutet, dass das Slot-Set intakt war, aber das Inhalts-AEAD-Tag scheiterte, nachdem
der Schlüssel zurückgewonnen war. Die drei sind für diesen lokalen Aufrufer strukturell
unterscheidbar, und die Grenze zwischen ihnen gibt kein Schlüsselmaterial preis. Für
einen nicht vertrauenswürdigen externen Aufrufer fallen alle drei zu dem oben
beschriebenen einen generischen Fehlschlag zusammen, nach der Form der Antwort nicht
unterscheidbar. Unter dem Timing-Modell trennt eine zulässige frühe
Kein-Treffer-Rückkehr WRONG_RECIPIENT_KEY (ein Nicht-Empfänger) von den beiden
empfängerseitigen Manipulationsergebnissen, die untereinander keine weitere
Unterscheidung tragen, sodass die diagnostische Präzision nie zu einem
slot- oder schlüsselselektiven Orakel wird.
Wie Codes auf die vier Verdikte abbilden
Ein vom strukturellen Validator ausgegebener Code bedeutet, dass die Bytes des
Datensatzes nicht konform sind. Der öffentliche Verifizierer kürzt den Bericht mit dem
Verdikt failed ab – Exit 1 – samt der Problemliste des Validators, ohne weitere
Chain- oder Krypto-Arbeit auszuführen. Ein Code, der erst ausgegeben wird, nachdem die
strukturelle Validierung bestanden wurde – eine Signatur, die sich nicht verifizieren
ließ, ein zurechenbarer Hash, der nicht übereinstimmte, METADATA_NOT_FOUND auf
der gebundenen Transaktion – ist ebenso failed: Jeder ist dem Datensatz zurechenbar,
ein Beweis, den die eigenen Bytes des Datensatzes liefern.
Ein vorübergehendes oder dem Anbieter zurechenbares Scheitern ist ein anderes Verdikt:
Inhalt, der sich nicht abrufen oder zurechnen ließ, ein nicht erreichbarer Explorer
oder ein Anbieter, der Bytes lieferte, die die Bindung an die Transaktionsreferenz
verfehlen, bilden allesamt auf unverifiable ab – Exit 2 –, denn keines ist die
Schuld des Datensatzes, und derselbe Datensatz kann bei einem erneuten Versuch valid
verifizieren. Die Unterscheidung, die der Exit-Code bewahrt, ist daher dreiteilig unter
den scheiternden Zuständen: dem Datensatz zurechenbares failed (1), betrieblich oder
dem Anbieter zurechenbares unverifiable (2) und unterschwelliges pending (3).
Einige wenige Codes tragen einen kontextabhängigen Schweregrad. Ein Verifizierer, der
einen reichhaltigeren Datensatz liest, als sein deklariertes Profil vorgibt (etwa ein
reiner Hash-Verifizierer, der auf einen versiegelten Eintrag trifft), meldet das
zusätzliche Feld in einem Anzeigekontext als info und validiert den Hash-Anspruch
dennoch, oder in einem strikten durchgängigen Audit-Kontext als error. Ebenso ist
ein nicht erkanntes optionales Signaturverfahren info, denn der Anspruch auf die
Existenz des Inhalts hängt nicht davon ab, sodass ein öffentlicher reiner Hash-Nachweis
auch dann valid bleibt, wenn eine ergänzende Signatur nicht verifizierbar ist.
Dienstunabhängigkeit ist nicht optional
Die Verifizierung greift nie auf die veröffentlichende Stelle zurück. Jeder ausgehende
Aufruf, den ein konformer Verifizierer macht, richtet sich an Infrastruktur, die der
Betreiber gewählt hat: einen Cardano-Explorer für die Transaktion und
inhaltsadressierte Speicher-Gateways für etwaige ar://- oder ipfs://-Bytes. Das
ist strukturell durchgesetzt, kein Versprechen in einem Code-Kommentar:
- Jeder Netzwerkaufruf läuft durch eine einzige Egress-Hülle, die
url,method,status, die Byte-Anzahl und den Zweck für jeden Aufruf, ob Erfolg, Fehler oder erneuter Versuch, in einen verpflichtenden Prüfpfad des Berichts schreibt. Ein Verifizierer, der diesen Pfad nicht vorlegen kann, kann seine Unabhängigkeit nicht nachweisen. - Diese Hülle nimmt eine vom Einsatz gelieferte Deny-Host-Liste entgegen und lässt
jeden Aufruf an einen passenden Host hart mit
SERVICE_INDEPENDENCE_VIOLATIONscheitern. Die Liste ist eine Betreibereingabe, eine Konformitätssuite füllt sie mit den eigenen Domains der Implementierenden, keine Wire-Konstante von Label 309. - Ein Konformitäts-Harness lässt den Verifizierer gegen eingefrorene
Fixture-Transaktionen in einem Netzwerk laufen, in dem die eigenen Domains des
Betreibers ins Leere auflösen, und stellt sicher, dass der Verifizierer dennoch
validzurückgibt. Die Zusicherung erfolgt auf der Netzwerkebene des Betriebssystems, nicht durch ein Durchsuchen des Quellcodes: Ein Verifizierer, der einen verbotenen Host über eine fest verdrahtete IP erreicht, würde einen Quellcode-Scan bestehen, aber an diesem Test scheitern.
Der Verifizierer braucht einen erreichbaren Cardano-Explorer und nichts Implementierungsspezifisches. Inhalts-Gateways, ein privater Empfängerschlüssel und eine Off-Chain-Blattliste sind optionale Eingaben, die jeweils die Inhalts-, die Empfänger- und die Merkle-Prüfung freischalten. Keine davon ist ein Dienst, den der Standard benennt, und keine davon ist die veröffentlichende Stelle.
Verwandte Seiten
- Der Datensatz: das Wire-Format, gegen das der strukturelle Validator prüft: label 309, die Form der Map, die Wiederzusammensetzung der Stücke und das CDDL-Schema.
- Signaturen: die Konstruktion des COSE_Sign1 auf Datensatzebene, die domänengetrennten Nutzdaten und die strikten Ed25519-Verifizierungsregeln.
- Versiegelte PoE: der Verschlüsselungsumschlag, die Empfänger-Schlüsselslots und das Entpacken, das der Empfänger-Verifizierer durchführt.
Versiegelte PoE
Der Verschlüsselungsumschlag von Label 309 — wie ein Absender Inhalte für einen oder mehrere Empfängerschlüssel versiegelt, während die Blockchain nur den Klartext-Hash und die gewickelten Schlüssel-Slots trägt, niemals den Klartext und niemals die Empfänger.
Sicherheitsmodell
Was ein Label-309-Verifizierer voraussetzt und was nicht: die Invariante der eigenständigen Überprüfbarkeit, die Datenschutzgarantien einer versiegelten PoE, die normativen Kryptografie-Regeln, die jede Implementierung einhalten muss, sowie die bekannten Grenzen des Wire-Formats.