Verificación
Los tres roles de verificador de Label 309, los estados del veredicto, la profundidad de finalidad y el catálogo de errores tipados: cómo cualquiera llega a la misma respuesta usando solo infraestructura pública.
Label 309 se verifica, nunca se da por sentado. Quien publica ancla un hash del contenido en Cardano bajo la etiqueta de metadatos 309; a partir de ese momento la afirmación se sostiene por sí sola sobre sus propios bytes, y cualquiera que tenga la referencia de la transacción puede comprobarla. Esta página define cómo se ejecuta esa comprobación: los tres roles de verificador, qué toca y qué no toca cada uno, los estados de veredicto que emiten, la profundidad de confirmación por debajo de la cual un veredicto sigue siendo provisional, y el catálogo de errores tipados que hace que dos implementaciones independientes coincidan en el mismo fallo ante la misma entrada.
La propiedad que lo define es la independencia del servicio. Un verificador conforme alcanza su veredicto usando únicamente la cadena pública, un explorador o gateway de Cardano elegido por el propio verificador y, para las afirmaciones de contenido y los registros sellados, los gateways de almacenamiento direccionado por contenido que el verificador también elige. Nunca contacta con el emisor. El estándar no nombra a ningún proveedor concreto: el gateway es una entrada que aporta el operador.
Tres roles, cada uno una extensión estricta
La verificación está organizada por capas. Cada rol hace todo lo que hace el rol anterior y, además, añade una capacidad. Un rol inferior es por sí mismo un verificador completo y útil: simplemente prueba menos.
| Rol | Añade | Toca |
|---|---|---|
| Validador estructural | conformidad de esquema y de dominio sobre los bytes del registro | nada: es una función pura |
| Verificador público | resolución de cadena, inclusión en cadena, comprobación de firmas | un explorador de Cardano + gateways de contenido |
| Verificador destinatario | descifrado de prueba de una carga útil sellada, recálculo del hash del texto plano | la propia clave privada del verificador |
Validador estructural: una función pura sobre los bytes
El validador estructural es una única función que va de una cadena de bytes a un resultado. No realiza E/S, ni comprobaciones de firma criptográfica, ni descifrado. Nunca accede a una red, una transacción ni una clave. Dada la misma entrada devuelve la misma salida, siempre y en cualquier lugar, que es justo lo que le permite ejecutarse antes del envío dentro de las herramientas de quien publica, dentro de un indexador de terceros o dentro de una herramienta de archivo que confirma que un registro sigue bien formado a largo plazo, todo ello sin un servidor.
Su flujo es fijo:
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.El validador es independiente del perfil: analiza el esquema v1 completo, sea cual
sea el subconjunto sobre el que un verificador posterior pretenda actuar. Los
errores invalidan el registro; las advertencias y las entradas informativas se
muestran, pero lo dejan válido. Y, lo más importante, confirma la forma de un
COSE_Sign1 (un arreglo de cuatro elementos, una carga útil separada (null) y un
encabezado protegido bien formado), pero nunca verifica la firma, y nunca
rechaza un registro por el simple hecho de que el algoritmo de firma sea uno que no
reconoce (ese caso se etiqueta como SIGNATURE_UNSUPPORTED, con severidad info, y
el registro sigue siendo válido). Verificar la firma es tarea del verificador
público. Consulte El registro para conocer el esquema que esta
fase impone.
Verificador público: cadena, inclusión y firmas
El verificador público añade la cadena sobre el validador estructural. Dada una referencia de transacción de Cardano:
- Resuelve un explorador elegido por el verificador. La cadena de exploradores
es una entrada; el verificador los prueba en orden, obteniendo el CBOR en bruto
de la transacción en cadena, nunca la proyección JSON de metadatos del
explorador. La vista JSON colapsa los tipos mayores de CBOR en una unión JSON y
descarta el orden de las claves del mapa, el marco de longitud definida y la
distinción entre bytes y texto, de modo que un verificador que recodificara a
partir de ella no podría reproducir la entrada de firma exacta byte a byte y toda
firma sobre un registro conforme fallaría. La respuesta negativa de un único
proveedor no es autoritativa sobre la cadena (la transacción puede estar en
cadena y ser simplemente desconocida para ese proveedor), así que el verificador
consulta a todos los proveedores restantes antes de emitir
TX_NOT_FOUND; si todos los proveedores son inalcanzables, emitePROVIDER_UNAVAILABLE. - Vincula los bytes obtenidos a la referencia de la transacción. Antes de leer
nada de una transacción obtenida, el verificador recalcula
blake2b-256sobre los bytes del cuerpo de la transacción obtenida (que, por definición del ledger, es el id de la transacción) y rechaza la respuesta ante cualquier discordancia con el hash solicitado. Luego recalculablake2b-256sobre los bytes de los datos auxiliares obtenidos y rechaza ante cualquier discordancia con elauxiliary_data_hashdel cuerpo ya verificado. Ambos resúmenes se calculan sobre los bytes exactamente como se obtuvieron, nunca sobre una recodificación. Una respuesta que falle cualquiera de las dos comprobaciones lleva bytes demostrablemente erróneos y se descarta; si ningún proveedor produce una respuesta que sobreviva a la vinculación, el informe llevaTX_INTEGRITY_MISMATCH. Tras este paso, cada byte del registro y de la transacción circundante queda criptográficamente comprometido con el hash que suministró el llamante: ningún explorador puede sustituir, enmendar ni truncar el registro sin producir una segunda preimagen de blake2b-256. - Desenvuelve los datos auxiliares. El ledger de la era Conway admite tres
codificaciones de datos auxiliares, las tres válidas: un mapa de metadatos pelado y
sin etiqueta, un arreglo de dos elementos
[ metadata, scripts ]y un mapa con etiqueta 259 que lleva los metadatos bajo la clave0. El verificador DEBE aceptar las tres y discriminar únicamente por el tipo y la etiqueta de CBOR de nivel superior: un valor con etiqueta 259 es la forma de mapa con clave, un arreglo sin etiqueta es la forma de dos elementos, y un mapa sin etiqueta es siempre el propio mapa de metadatos. NO DEBE inspeccionar las claves de un mapa para adivinar la forma; cualquier otra forma de nivel superior, o cualquier etiqueta distinta de 259, esMALFORMED_CBOR. Si la transacción vinculada no lleva metadatos bajo la etiqueta 309, el verificador emiteMETADATA_NOT_FOUND, un resultado atribuible al registro, porque la propia transacción vinculada demuestra la ausencia: ningún proveedor podría haber retirado los metadatos sin fallar la vinculación. - Reensambla el array de fragmentos del cuerpo completo. El valor de la etiqueta 309 es el cuerpo del registro en CBOR canónico dividido en un arreglo de cadenas de bytes de ≤ 64 bytes. El verificador concatena los elementos byte a byte y en orden (devolviendo los bytes en bruto, sin una pasada de recodificación) para que la comprobación de CBOR canónico aún pueda detectar una codificación en cadena no conforme.
- Valida estructuralmente el cuerpo reensamblado (el rol anterior). Un rechazo
del validador interrumpe el informe con el veredicto
failed. - Comprueba la profundidad de confirmación (más abajo). Una transacción por
debajo del umbral se detiene aquí con el veredicto
pending. - Verifica cada firma a nivel de registro bajo Ed25519 estricto. No descifra. La resolución de la firma, la carga útil con separación de dominio y las reglas de verificación estricta se especifican en Firmas.
- Obtiene y comprueba el hash del contenido, exigiendo cuentas al registro solo por los bytes que puede atribuir a la propia dirección de contenido de un URI (más abajo). No descifra.
Por qué CBOR en bruto y no JSON
Una firma se calcula sobre el CBOR canónico, byte a byte, del cuerpo del registro. Una proyección JSON de los metadatos tiene pérdida por construcción: no puede volver a esos bytes en un viaje de ida y vuelta. Recodificar a partir de JSON rompe toda firma sobre un registro conforme. El CBOR en bruto de la transacción es la única entrada autoritativa para cualquier comprobación criptográfica; una vista JSON sirve para mostrarlo a las personas, una vez que la verificación ya ha pasado.
Verificador destinatario: descifrar y recalcular
El verificador destinatario es un verificador público que, además, posee una clave privada. Para un registro sellado dirigido a él, descifra de prueba las ranuras de clave en cadena con su clave, recupera la clave de contenido cuando lo consigue, descifra el texto cifrado y, a continuación, recalcula los hashes del texto plano contra el compromiso en cadena, cerrando así el círculo entre los bytes cifrados y la afirmación de existencia del contenido. Como todo registro sellado lleva al menos una entrada de hash del contenido, ese recálculo siempre tiene algo concreto con qué compararse. El sobre sellado, las ranuras de clave y la construcción de desenvolvimiento se especifican en PoE sellada.
Antes de que el destinatario toque ninguna primitiva KEM o AEAD, vuelve a aplicar las
mismas comprobaciones de forma y de recursos del sobre que ya ejecutó el validador
estructural, rechazando primero un sobre estructuralmente inválido o sobredimensionado.
Dos de esas guardas previas a las primitivas son cotas de recursos fijadas por
despliegue, no campos de transmisión: los límites de referencia son
MAX_SLOTS = 1024 ranuras y 65536 bytes para el sobre enc decodificado, ambos muy
por encima del techo de ~16 KiB de los metadatos de transacción de Cardano que acota
cualquier registro honesto, de modo que un registro que supere cualquiera de ellos está
mal formado y se rechaza con ENC_SLOTS_TOO_MANY o ENC_ENVELOPE_TOO_LARGE antes de
ejecutar una sola primitiva. Los despliegues PUEDEN endurecerlos.
Una comprobación de forma es determinante para la seguridad: el material de
encapsulamiento DEBE ser distinto dentro de un mismo slots[] (todos los valores
epk para x25519, o todos los valores kem_ct reensamblados para
mlkem768x25519). Un duplicado dentro del registro se rechaza con
ENC_SLOTS_DUPLICATE_KEM_MATERIAL antes de ejecutar ninguna primitiva KEM o AEAD,
porque un epk/kem_ct repetido rompería la unicidad de clave por ranura de la que
depende el envoltorio con nonce a cero. La reutilización de claves entre registros o
entre claves es una obligación del productor y no la puede detectar el verificador; solo
el duplicado dentro del registro sí. Las tres comprobaciones son estructurales: el
validador las impone en todo registro (los códigos de material duplicado, recuento de
ranuras y sobre decodificado son códigos de la Parte A); el destinatario simplemente las
vuelve a ejecutar como defensa en profundidad.
El desenvolvimiento en sí son dos pasos criptográficos que el destinatario reproduce a
partir del sobre, nunca de ninguna entrada externa. Primero recalcula el hash de la
transcripción de ranuras slots_hash una vez, antes del bucle, y lo mantiene
constante en cada ranura:
slots_hash = SHA-256("cardano-poe-slots-transcript-v1" || canonicalEncode(SLOTS_TRANSCRIPT)),
donde la transcripción fija los campos de cabecera, el conjunto de ranuras en el cable
(cada campo de ranura es una única cadena de bytes, así que no hay fragmentación por
campo que normalizar) y la afirmación de hash del ítem mediante hashes_hash. Vincular
hashes_hash es lo que permite al destinatario confirmar que el sobre se selló para
esta afirmación de hash exacta solo a partir de los bytes en cadena, antes de
recuperar ningún texto cifrado: un sobre empalmado en un ítem con un mapa hashes
distinto falla el MAC. Itera todas las ranuras sin salida anticipada; una
ranura se acepta solo cuando la clave de contenido que produce también reproduce el
slots_mac en el cable sobre ese slots_hash constante. La aceptación también pliega
un bit de validez independiente del secreto: en la ruta clásica, una ranura diseñada
para llevar el secreto compartido X25519 al valor todo a cero pone ese bit en falso (una
comparación en tiempo constante contra 0^32), la KEK se selecciona en tiempo constante
hacia una falsa derivada de 0^32 para que el bucle realice un trabajo idéntico, y el
bit gobierna la aceptación de la ranura: una ranura con ECDH inválido nunca puede abrir,
sea cual sea su envoltorio o MAC. Tanto la apertura del envoltorio como la posterior
apertura del contenido son atómicas: ante un fallo del tag AEAD no devuelven texto
plano, y el candidato que entregan (la clave envuelta o el texto plano del contenido) es
un valor de relleno fijo o pseudoaleatorio independiente del texto cifrado que falló:
nunca se libera texto plano sin verificar.
Una clave de destinatario PUEDE coincidir legítimamente con más de una ranura: un
productor puede sellar la misma clave de contenido para el mismo destinatario en varias
ranuras, cada una con material KEM fresco por ranura, para acolchar el recuento de
destinatarios; es una técnica de privacidad válida, y distinta del rechazo de material de
encapsulamiento duplicado, que se dispara solo ante un epk/kem_ct idéntico. El
verificador selecciona la clave de la primera coincidencia y NO DEBE rechazar
solo porque coincidieran varias ranuras. La única anomalía que DEBE rechazar son dos
ranuras coincidentes que recuperan claves de contenido distintas (comparadas en
tiempo constante): el bucle arrastra un bit cek_conflict y aflora el único fallo
genérico si cualquier coincidencia posterior produce una clave que difiera de la
seleccionada. Esto es defensa en profundidad: bajo el compromiso del conjunto de ranuras,
una coincidencia con clave distinta ya es inviable, así que la comprobación simplemente
falla de forma segura.
Luego, sobre la clave de cifrado del contenido recuperada, deriva la clave de contenido
(una hoja HKDF de esa clave con salt del enc.nonce) y abre el texto cifrado en
STREAM segmentado segmento a segmento, verificando la etiqueta de cada segmento antes
de liberar el texto plano de ese segmento. El AAD por segmento es vacío: todo el contexto
de cabecera ya está vinculado a la clave de forma transitiva a través de slots_mac, así
que alterar cualquier campo de cabecera cambia lo que el destinatario deriva y el flujo no
consigue abrir. El truncamiento se detecta con la marca final: un segmento final ausente,
datos a continuación de él, una marca final en un segmento no final, o un segmento no
final corto fallan todos como TAMPERED_CIPHERTEXT. El formato segmentado no impone ningún
techo criptográfico a la carga útil (el contador de segmento de 88 bits admite 2^88
segmentos); un máximo práctico es una política de denegación de servicio del despliegue,
impuesta de forma incremental a medida que se lee el flujo. En la ruta de frase de
contraseña, el destinatario lee primero la cabecera de compromiso inicial de 32 bytes y la
compara en tiempo constante antes de abrir ningún segmento.
La ruta del destinatario es donde el catálogo de errores demuestra su precisión: distingue el caso en que ninguna ranura aceptó esta clave (destinatario equivocado) del caso en que una ranura aceptó la clave pero el conjunto de ranuras o el texto cifrado fue manipulado. Son afirmaciones de seguridad distintas y llevan códigos diferentes (más abajo). Un llamante no confiable, sin embargo, recibe exactamente una forma de fallo genérico sea cual sea la causa (ninguna ranura abrió, el conjunto de ranuras fue manipulado o el tag de contenido falló), y la respuesta nunca revela qué caso ocurrió ni qué ranura coincidió; los códigos tipados son un diagnóstico interno solo para un llamante local de confianza.
El tiempo sigue un modelo explícito. El verificador PUEDE retornar en la comprobación de no-coincidencia, antes del descifrado del contenido, de modo que un no destinatario y un destinatario tomen un tiempo medible distinto. Esa diferencia revela solo destinatario frente a no destinatario, nunca qué ranura coincidió ni material de clave alguno. No se exige un tiempo uniforme entre un no destinatario y un destinatario cuyo texto cifrado no consigue abrir, y NO DEBE imponerse una apertura de contenido ficticia: cargaría el coste del descifrado del contenido sobre todo transeúnte. La garantía de tiempo constante que sí se mantiene es la de entre ranuras: dentro de la pasada de una sola clave privada, el bucle recorre todas las ranuras con comparaciones en tiempo constante, de modo que nada filtra qué ranura, si alguna, desenvuelve esa clave.
Finalidad: profundidad de confirmación
La liquidación en Cardano es probabilística. Una transacción con un bloque de
profundidad todavía puede quedar huérfana por una reorganización corta; una
transacción con muchos bloques de profundidad ha quedado liquidada con probabilidad
abrumadora. Un verificador que calificara como valid un registro de un solo bloque
de profundidad permitiría que un atacante reanclara un registro contradictorio en una
bifurcación competidora y obtuviera un veredicto «válido» en ambas, rompiendo en
silencio la suposición de solo-anexar sobre la que descansa toda la prueba.
Por eso un verificador reporta el registro como pending, no failed, mientras
se sitúa por debajo de un umbral de profundidad de confirmación. El umbral de uso
general RECOMENDADO es de ≥ 15 bloques (unos cinco minutos). El umbral es una
política del verificador, no una constante del formato: los despliegues que manejan
registros de alto valor o de carácter probatorio DEBERÍAN elevarlo hacia la
finalidad firme, y un verificador DEBE exponer el umbral que usó para que los
consumidores puedan superponer una política más estricta. Un registro pending está
bien formado y en cadena; simplemente todavía no ha liquidado a suficiente
profundidad, y puede resolverse a valid en un reintento posterior.
Estados del veredicto
Un verificador concluye en uno de cuatro veredictos legibles por máquina, cada uno
emparejado uno a uno con un código de salida del proceso, de modo que quien lo invoca (una
puerta de CI, un monitor, un script) pueda distinguir un fallo atribuible al registro de
uno operativo transitorio sin necesidad de analizar el informe estructurado. La línea
rectora es la atribución: condenar un registro exige evidencia que los propios bytes
del registro (o bytes vinculados de forma atribuible a sus referencias) realmente aporten.
Ningún mal comportamiento de un proveedor puede fabricar un failed.
| Veredicto | Salida | Significado |
|---|---|---|
| valid | 0 | toda comprobación que ejecutó el verificador devolvió ok; no hay ningún problema con severidad error. |
| failed | 1 | un fallo atribuible al registro: el validador estructural rechazó los bytes, una firma no verificó, un hash atribuible no coincidió, la transacción vinculada no lleva metadatos bajo la etiqueta 309 (METADATA_NOT_FOUND), o se disparó una regla de host denegado. |
| unverifiable | 2 | sin error atribuible al registro, pero una comprobación requerida no pudo ejecutarse o no pudo atribuirse: la transacción no se resolvió, ninguna respuesta de proveedor sobrevivió a la vinculación (TX_INTEGRITY_MISMATCH), o no se pudo obtener ni atribuir el contenido o el texto cifrado comprometidos. El mismo registro puede verificarse como valid en un reintento o bajo un gateway distinto. |
| pending | 3 | estructuralmente bien formado y en cadena, pero por debajo del umbral de profundidad de confirmación (INSUFFICIENT_CONFIRMATIONS); puede liquidar. Ningún resultado de un registro pendiente puede presentarse como definitivo. |
Los fallos en tiempo de ejecución del anfitrión del verificador que no son atribuibles al registro usan códigos de salida 4 y superiores y no se corresponden con ningún veredicto.
Un veredicto valid NO DEBE reportarse cuando haya presente algún problema con
severidad error; un registro PUEDE ser valid con una lista warnings o info no
vacía. Ninguna capa puede «suavizar» un error y convertirlo en advertencia para hacer pasar
un registro. Cada veredicto se reserva para su propio caso: pending nunca sustituye a
valid ni a failed, y un fallo atribuible a un proveedor es unverifiable, nunca
failed.
Un suelo de compromiso gobierna la disponibilidad: cuando la comprobación de contenido
se ejecutó pero los fallos de disponibilidad dejaron sin verificar ningún compromiso de
contenido del registro, el veredicto es unverifiable, nunca valid; un veredicto valid
significa que se comprobó al menos un compromiso de contenido. Los resultados de integridad
quedan al margen del suelo: unos bytes atribuibles que fallan un compromiso producen
failed, sea cual sea lo demás que estuviera disponible.
Vinculación a la dirección de contenido y atribución
El paso 8 (y, para el verificador destinatario, el descifrado) obtiene bytes de gateways de almacenamiento direccionado por contenido que el verificador eligió, y los gateways no son de confianza. La línea de veredicto de más arriba gira en torno a una única pregunta que el verificador DEBE poder responder sobre cada flujo de bytes obtenido: ¿se pueden atribuir estos bytes al propio URI? Ambos esquemas están direccionados por contenido, así que sí se puede:
ipfs://: recalcular el CID sobre el contenido obtenido (el multihash directamente para un CID de códec en bruto; los resúmenes bloque a bloque a lo largo de la ruta resuelta para un CID en forma de DAG).ar://: validar la transacción de Arweave firmada y recalcular el árbol de Merkle de fragmentos contra sudata_root; para un elemento de datos ANS-104, recalcular el deep-hash, verificar la firma del propietario y comprobar que el SHA-256 de la firma sea igual al id del URI.
Los bytes que satisfacen los propios resúmenes del registro no necesitan comprobación de vinculación: el compromiso del registro es al menos tan fuerte como el de la capa de almacenamiento. Allí donde la vinculación sí se aplica, la atribución decide qué significa una discordancia:
- Bytes atribuibles (vinculación verificada, o suministrados fuera de banda por el
llamante) se imputan al registro cuando fallan un compromiso:
URI_INTEGRITY_MISMATCHpara el contenido de un ítem (un fallo de integridad duro, sea cual sea lo que contenga cualquier URI hermano), la familiaMERKLE_*para una lista de hojas,TAMPERED_CIPHERTEXTpara un blob de texto cifrado atribuible. Veredictofailed. - Bytes no atribuibles (vinculación no verificada, o verificada y fallida) incriminan
al proveedor que los sirve, nunca al registro:
URI_PROVIDER_INTEGRITY_MISMATCH(advertencia). El verificador continúa con los URI y gateways restantes; una afirmación que se queda sin bytes atribuibles termina en un resultado de disponibilidad (CONTENT_UNAVAILABLE,MERKLE_LEAVES_UNAVAILABLE,CIPHERTEXT_UNAVAILABLE), veredictounverifiable, exactamente como si no se hubiera obtenido nada.
Esta es la contraparte, del lado del almacenamiento, de la vinculación a la referencia de la
transacción: un gateway que se comporta mal solo puede degradar la disponibilidad, nunca
el veredicto. URI_INTEGRITY_MISMATCH y URI_PROVIDER_INTEGRITY_MISMATCH son, por tanto,
códigos distintos (el primero condena el registro, el segundo condena un proveedor), y un
verificador que los confundiera dejaría que un gateway hostil forjara un failed. La
recomprobación del hash del texto plano posterior al descifrado no necesita calificador de
atribución: un texto cifrado que abre bajo el sobre autenticado queda atribuido por el
propio AEAD, así que una discordancia del hash del texto plano allí (URI_INTEGRITY_MISMATCH)
es siempre atribuible al registro y fuerza failed.
El catálogo de errores tipados
Cada modo de fallo se resuelve a un código de un único catálogo cerrado. Los códigos
van en SCREAMING_SNAKE_CASE, y una implementación conforme DEBE emitir
exactamente esas cadenas: nunca un código interno en minúsculas de un analizador,
nunca un mensaje de formato libre. Dos implementaciones en dos lenguajes que reciben
la misma entrada emiten el mismo código; la lista normativa completa queda fijada byte
a byte por la suite de pruebas de conformidad, y el catálogo está cerrado (los códigos
solo se añaden mediante enmienda).
Modelo de severidad
Cada problema lleva una de tres severidades, y la distinción es determinante:
- error: invalida el veredicto. Un resultado
validno puede coexistir con ningúnerror. - warning: una anomalía no fatal en tiempo de ejecución (falló un único gateway,
una lista de hojas estaba solo parcialmente disponible) que no impide
valid. - info: una no-comprobación deliberada: un aspecto que el verificador eligió no evaluar (un campo fuera de su perfil, un algoritmo opcional no reconocido). Una entrada informativa no es un error suavizado y nunca se usa como tal.
Un código queda aparte: INSUFFICIENT_CONFIRMATIONS se corresponde con el veredicto
pending en lugar de con una severidad, porque el registro está bien formado y solo
aguarda la liquidación.
Familias de errores
El catálogo se agrupa en familias. Un conjunto representativo, no exhaustivo, de códigos:
| Familia | Severidad | Códigos representativos |
|---|---|---|
| CBOR malformado / no canónico | error | MALFORMED_CBOR, CHUNK_TOO_LARGE |
| Esquema | error | SCHEMA_TYPE_MISMATCH, SCHEMA_MISSING_REQUIRED, SCHEMA_UNKNOWN_FIELD, SCHEMA_EMPTY_RECORD |
| Algoritmo no admitido | error | UNSUPPORTED_HASH_ALG, UNSUPPORTED_AEAD_ALG, UNSUPPORTED_KEM_ALG, UNSUPPORTED_MERKLE_COMMIT_ALG |
| Explorador / metadatos | error / pending | TX_NOT_FOUND, PROVIDER_UNAVAILABLE, TX_INTEGRITY_MISMATCH (→ unverifiable), METADATA_NOT_FOUND (→ failed); INSUFFICIENT_CONFIRMATIONS (→ pending) |
| Firma | error / info | MALFORMED_SIG_COSE_SIGN1, SIGNER_KEY_UNRESOLVED, SIGNATURE_INVALID, WALLET_ADDRESS_MISMATCH; SIGNATURE_UNSUPPORTED (info) |
| Cifrado / KEM / envoltura | 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 |
| Resultado del descifrado | error | WRONG_DECRYPTION_INPUT_SHAPE, WRONG_RECIPIENT_KEY, TAMPERED_HEADER, TAMPERED_CIPHERTEXT, KDF_DERIVATION_FAILED |
| URI / contenido | error / warning | INVALID_URI, URI_TARGET_FORBIDDEN, URI_INTEGRITY_MISMATCH, CONTENT_UNAVAILABLE (→ unverifiable), CIPHERTEXT_UNAVAILABLE (→ unverifiable); URI_PROVIDER_INTEGRITY_MISMATCH, URI_FETCH_FAILED (advertencias) |
| Compromiso de lista Merkle | error / warning / info | MERKLE_ROOT_MISMATCH, SCHEMA_MERKLE_LEAF_COUNT_MISMATCH; MERKLE_LEAVES_UNAVAILABLE (dual); MERKLE_UNSUPPORTED (dual) |
| Independencia del servicio | error | SERVICE_INDEPENDENCE_VIOLATION |
Los códigos de red/política (TX_NOT_FOUND, PROVIDER_UNAVAILABLE, CONTENT_UNAVAILABLE,
CIPHERTEXT_UNAVAILABLE) —y TX_INTEGRITY_MISMATCH, cuya discordancia es demostrable contra
los proveedores y no contra el registro— son de severidad error en la lista de problemas
(bloquean un veredicto valid) pero no son atribuibles al registro, así que se asignan a
unverifiable, nunca a failed. URI_PROVIDER_INTEGRITY_MISMATCH es la advertencia por
recuperación bajo el mismo principio. Unos pocos códigos llevan severidad dual
(ENC_UNSUPPORTED, MERKLE_UNSUPPORTED, OUT_OF_PROFILE_SKIPPED y
MERKLE_LEAVES_UNAVAILABLE): se leen como info/warning por defecto y se promueven a
error en un contexto estricto (el rol del destinatario, la escalada de solo-merkle, el modo
estricto de extremo a extremo o el suelo de compromiso).
La ruta del destinatario es la familia más precisa en términos de diagnóstico. Para un
llamante local de confianza, un descifrado fallido se resuelve a uno de tres
códigos internos: WRONG_RECIPIENT_KEY significa que ninguna ranura aceptó la clave
suministrada (nunca se recuperó ninguna clave de contenido); TAMPERED_HEADER significa
que se recuperó una clave pero la clave de contenido candidata no reprodujo slots_mac
sobre slots_hash (se alteró una ranura, un campo de cabecera o el propio slots_mac);
TAMPERED_CIPHERTEXT significa que el conjunto de ranuras estaba intacto pero falló el
tag del AEAD de contenido tras recuperar la clave. Los tres son estructuralmente
distinguibles para ese llamante local, y la frontera entre ellos no filtra material de
clave alguno. Para un llamante externo no confiable, los tres colapsan en el único
fallo genérico descrito más arriba, indistinguibles por la forma de la respuesta. Bajo el
modelo de tiempo, un retorno anticipado permitido en la no-coincidencia separa
WRONG_RECIPIENT_KEY (un no destinatario) de los dos resultados de manipulación del lado
del destinatario, que entre sí no llevan ninguna distinción adicional, de modo que la
precisión diagnóstica nunca se convierte en un oráculo selectivo por ranura o por clave.
Cómo los códigos se asignan a los cuatro veredictos
Un código emitido por el validador estructural significa que los bytes del registro no son
conformes. El verificador público interrumpe el informe con el veredicto failed (salida 1)
y con la lista de problemas del validador, sin ejecutar más trabajo de cadena ni de
criptografía. Un código emitido solo después de que la validación estructural haya pasado
(una firma que no verificó, un hash atribuible que no coincidió, METADATA_NOT_FOUND en
la transacción vinculada) también es failed: cada uno es atribuible al registro, evidencia
que los propios bytes del registro aportan.
Un fallo transitorio o atribuible a un proveedor es un veredicto distinto: un contenido que
no se pudo obtener ni atribuir, un explorador inalcanzable o un proveedor que sirvió bytes
que fallan la vinculación a la referencia de la transacción se asignan todos a
unverifiable (salida 2), porque ninguno es culpa del registro y el mismo registro puede
verificarse como valid en un reintento. La distinción que preserva el código de salida es,
por tanto, triple entre los estados de fallo: failed atribuible al registro (1),
unverifiable operativo o atribuible a un proveedor (2), y pending por debajo del umbral
(3).
Algunos códigos llevan una severidad que depende del contexto. Un verificador que lee
un registro más rico que el perfil que declara (por ejemplo, un verificador de solo
hash que se topa con un registro sellado) reporta el campo adicional como info en un
contexto de visualización, y aun así valida la afirmación de hash, o como error en
un contexto de auditoría estricta de extremo a extremo. Del mismo modo, un algoritmo
de firma opcional no reconocido es info: la afirmación de existencia del contenido
no depende de él, de modo que una prueba pública de solo hash sigue siendo valid
incluso cuando una firma de carácter consultivo no se puede verificar.
La independencia del servicio no es opcional
La verificación nunca recurre de vuelta al emisor. Toda llamada saliente que realiza
un verificador conforme se dirige a infraestructura que eligió el operador: un
explorador de Cardano para la transacción, y gateways de almacenamiento direccionado
por contenido para cualesquiera bytes ar:// o ipfs://. Esto se impone
estructuralmente, no es una promesa en un comentario de código:
- Toda llamada de red pasa por una única envoltura de salida que registra
url,method,status, el recuento de bytes y el propósito de cada llamada (éxito, fallo y reintento por igual) en un rastro de auditoría obligatorio dentro del informe. Un verificador que no puede producir ese rastro no puede demostrar su independencia. - Esa envoltura acepta una lista de hosts denegados que aporta el despliegue y falla
de forma tajante cualquier llamada a un host coincidente con
SERVICE_INDEPENDENCE_VIOLATION. La lista es una entrada del operador (una suite de conformidad la rellena con los propios dominios de quien implementa), no una constante del formato de Label 309. - Un arnés de conformidad ejecuta el verificador contra transacciones de fixture
congeladas en una red donde los propios dominios del operador no resuelven a ningún
lado, y afirma que el verificador aun así devuelve
valid. La afirmación se hace en la capa de red del sistema operativo, no rastreando el código fuente: un verificador que alcanzara un host prohibido mediante una IP codificada a mano pasaría un escaneo del fuente, pero fallaría esta prueba.
El verificador necesita un explorador de Cardano alcanzable y nada específico de quien implementa. Los gateways de contenido, una clave privada de destinatario y una lista de hojas fuera de cadena son entradas opcionales que desbloquean, respectivamente, las comprobaciones de contenido, de destinatario y de Merkle. Ninguna de ellas es un servicio que el estándar nombre, y ninguna de ellas es el emisor.
Páginas relacionadas
- El registro: el formato del que parte el validador estructural para sus comprobaciones: la etiqueta 309, la forma del mapa, el reensamblaje de fragmentos y el esquema CDDL.
- Firmas: la construcción COSE_Sign1 a nivel de registro, la carga útil con separación de dominio y las reglas de verificación estricta de Ed25519.
- PoE sellada: el sobre de cifrado, las ranuras de clave del destinatario y el desenvolvimiento que realiza el verificador destinatario.
PoE sellada
El sobre de cifrado de Label 309: cómo un remitente sella el contenido para una o varias claves de destinatario mientras la cadena solo transporta el hash del texto plano y las ranuras de clave envueltas, nunca el texto plano y nunca los destinatarios.
Modelo de seguridad
Qué confía y qué no confía un verificador de Label 309: el invariante de verificabilidad autónoma, las garantías de privacidad de la PoE sellada, las reglas criptográficas normativas que toda implementación debe respetar y los límites conocidos del formato de transmisión.