diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b31a04..4a7c117 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,30 @@ Cambios notables de la librería TypeScript y de la página. El proyecto usa ver ## Especificación 0.10, en la rama `v0.10` — sin versión +### El borrador v0.12: `testdata`, la regla del §72 y la nota de `inspect` (05-10-2026) + +- `testdata` se sincroniza con la cabeza de la rama `v0.12` de `datekeys-go` (`601e6d2`); `SPEC_VERSION` sigue en `0.11` hasta que el autor apruebe el borrador. Trae: + - los fixtures `format3_unsigned`, el contenido de `format3_signed` sin firma y con la misma P, y `format3_note`, con nota pública; + - `format3_seal_unsupported` con `seal_type` 4294967295; + - `note.json`, `security.json` con su contexto y sus líneas, los 135 casos de `security_cms.json` y los 218 de `mutations.json`, 178 de ellos del §64. +- **Los vectores de Go.** `mutation-texts.json` se regenera con `scripts/mutation-go-texts.go`: cambian solo los ocho casos nuevos y el nombre del de `seal_type`. `ibe-vectors.json` gana las entradas de `format3_note`, `format3_unsigned` y el `format3_seal_unsupported` nuevo, sin tocar sus valores congelados. +- **La regla de los codificadores del §72**, `checkWrite` en `extension.ts`, con `NOTE_ID` y `CAPSULE_ID`, como `extension.CheckWrite` de Go: + - el escritor de cápsulas rechaza `datekeys.note` fuera del array no crítico de la cabecera o con datos que incumplen sus reglas, y `datekeys.capsule` en una cápsula; + - el de `.dkk` rechaza una nota, y `datekeys.capsule` fuera de su array no crítico o sin datos; + - los textos de error son los de Go. +- **La nota pública.** `checkNoteData` comprueba los bytes de una nota en el orden de Go, y `unusableNote` distingue una nota inservible de ninguna. `inspect` lee la nota bajo demanda, solo si la cabecera lleva una, y la vista de `inspect -json` da `public_note` y `public_note_unusable`, como la CLI de Go. Por eso `/inspect` sigue sin cargar las tablas de Unicode. +- **Pruebas.** `note.json`, y el bloque de `mutations.json` con sus recuentos nuevos: 7 759 pruebas en total. + +### El lector de certificados y los textos del borrador v0.12 (05-10-2026) + +Los fallos T2, T6, T7 y T8, y lo que toca a TypeScript de E2, E3, E7, E8 y E9, de `spec_v0.11/revision_sesion_1_2_octubre.md` (en `../docs`), como los arregla `datekeys-go` en la rama `v0.12` (`601e6d2`), cuyos `security.json` y `security_cms.json` leen las pruebas. + +- **El certificado, campo a campo**, con el perfil del §29.10 del borrador v0.12: versión 3, los campos en orden, nombres de SET no vacíos, la validez en DER y sin fracción, las extensiones sin repetir y un `subjectKeyIdentifier` no vacío. Uno que lo incumple no decide nada salvo que lo nombre un `SignerInfo`, y dos copias de uno cuentan como una. El texto de un nombre sale solo de los cinco tipos de cadena, en su alfabeto, sin quitar nada y nunca de un atributo repetido. El titular es su `givenName` y su `surname` antes que su `commonName`, que puede llevar el NIF, y el emisor, su `commonName` o su `organizationName`, ya no el texto de todos sus atributos. +- **Identificadores, claves y sellos.** Los OID se comparan por los bytes de su DER: un arco de 2³¹ o más es solo uno que la tabla no tiene. Un SET OF puede repetir un elemento, así que una TSA que manda dos veces su certificado ya no da S2. La clave RSA lleva parámetros NULL, exactamente un módulo y un exponente, y un módulo impar, y una clave de otro esquema que su algoritmo da F2, no F5. Un `messageImprint` de otra longitud da S3, los `crls` de un token no deciden nada, y los milisegundos y microsegundos de `accuracy` son INTEGER mínimos. `der.ts` comprueba las horas en sus formas de X.690 y admite los tipos de cadena restringidos, NumericString entre ellos. +- **Los textos de los veredictos.** Cada nombre de un certificado va entre « y », y se muestra si cumple las reglas del autor declarado, tiene como mucho 64 puntos de código y no lleva dos espacios seguidos; si no, su SHA-256. La línea de cada firmante de F6 nombra la autoridad de su sello, y si alguna dice «antes de la fecha de apertura», la sigue «DateKeys no comprueba quién emitió los sellos.». El resultado de un firmante ajeno va en español, y una hora lleva la fracción de su sello. +- **Pruebas.** `cms.test.ts`, `der.test.ts` y `securitycms.test.ts` portan las de `internal/cms`, `internal/der` y `signature2_test.go`, y la del emisor sin `commonName` ya no lo compara consigo mismo. `vectors.test.ts` lee `security.json` con su contexto y sus líneas, y compara en cada caso de `security_cms.json` los veredictos, los firmantes exigidos y los ajenos, el sello y las líneas. +- **Diferencial con Go.** `capsule.EvaluateSecurityIn` y `Verdicts.Lines` de `601e6d2` dan lo mismo que `evaluateSecurity` y `verdictLines`, campo a campo, en 63 623 áreas: las de los vectores, sus mutaciones byte a byte y elemento a elemento, y áreas firmadas y selladas de verdad cuyos certificados, firmas y tokens varían campo a campo. Antes de estos cambios diferían en 13 296 de 42 986. + ### Arreglos de la revisión de la sesión del 1 y 2 de octubre (02-10-2026) Los fallos T1, T3, T4, T5, T9 a T12, T14 y parte de T13 de `spec_v0.11/revision_sesion_1_2_octubre.md` (en `../docs`). Cada texto y cada veredicto nuevo se contrastó con un oráculo de Go sobre el tag `spec-v0.11`. diff --git a/README.md b/README.md index 5ac72ea..686f02b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # datekeys-ts -Implementación en TypeScript del protocolo DateKeys (formato 3 de la v0.10; de la v0.11, la firma de clave propia, la firma con certificados y el sello de tiempo, que lee y verifica, y el escritor con el área de 32 KiB y la nota pública; el localizador y firmar al escribir están pendientes) y página de prueba en el navegador. Sustituye al prototipo, archivado en `../archive/prototype` (API Quicknet en Go, CLI tlock y cliente Svelte, commit `4d2b0a1`). +Implementación en TypeScript del protocolo DateKeys (formato 3 de la v0.10; de la v0.11, la firma de clave propia, la firma con certificados y el sello de tiempo, que lee y verifica con el perfil del certificado y los textos del borrador v0.12, y el escritor con el área de 32 KiB y la nota pública; el localizador y firmar al escribir están pendientes) y página de prueba en el navegador. Sustituye al prototipo, archivado en `../archive/prototype` (API Quicknet en Go, CLI tlock y cliente Svelte, commit `4d2b0a1`). La implementación de referencia es la librería Go `g.activething.com/go/DateKeys`, en `../datekeys-go`. Los planes y el estado del trabajo están en `../docs`, el repositorio privado de documentación del proyecto. @@ -21,7 +21,7 @@ Hay tres números de versión, cada uno con su significado, como en la referenci | Versión | Dónde | Cambia cuando | |---|---|---| | Formato | Dentro de los objetos: el formato de la cápsula, el `VERSION` del prelude de DKC1, 1, 2 o 3 al leer, que fija también la versión de schema de CONTROL_CBOR; y 1 en la trama DKK1 y en el schema de los demás objetos | Cambia el formato. Un lector rechaza una versión que no conoce (§22, §70) | -| Especificación | `SPEC_VERSION` de `src/lib/dkc/version.ts`, hoy `0.11`: la del tag `spec-v0.11` de `datekeys-go` | Cambia el texto normativo | +| Especificación | `SPEC_VERSION` de `src/lib/dkc/version.ts`, hoy `0.11`: la del tag `spec-v0.11` de `datekeys-go`. `testdata` sigue ya el borrador v0.12, la cabeza de la rama `v0.12` (`601e6d2`), cuyos ficheros dicen `0.11` hasta que el autor lo apruebe | Cambia el texto normativo | | Librería | `VERSION` de `src/lib/dkc/version.ts`, igual al campo `version` de `package.json` | Cambia la API o el comportamiento. Versionado semántico, sin promesa de estabilidad antes de 1.0.0 | `version.test.ts` comprueba que `VERSION` coincide con `package.json` y con su lockfile, y que `SPEC_VERSION` es la versión que nombran los vectores y fixtures compartidos; `vectors.test.ts` exige esa versión a cada fichero. El pie de la página muestra las dos. @@ -47,7 +47,7 @@ La inspección (pasos 1 a 8) no importa ninguna dependencia. Funciona en navegad | `bytes.ts` | Hex, UTF-8 estricto, `goQuote` (el `%q` de Go, con la tabla de `strconv.IsPrint` de Go 1.26 fijada en el código) y `sha256` (Web Crypto) | `strconv`, `unicode/utf8` | | `cbor.ts` | El codec propio de la referencia, con las mismas lecturas, las mismas comprobaciones en el mismo orden y los mismos textos de error: `Encoder` con error persistente; `Decoder`, cursor estricto (`map`/`key`/`endMap`, `array`, `uint`/`uint64`, `bstr`, `text`, `done`); `unmarshal` (decodifica, reencodifica y compara; `onReject` para borrar secretos); `peek`/`checkSchema` (capa 2 de §69.1: tipo y versión antes que nada) y `walk` (lector genérico acotado en profundidad y longitud) | `codec` | | `schema.ts` | Lo que comparten los decodificadores de PUBLIC_HEADER, CONTROL_CBOR y el cuerpo de la `.dkk`: `key N: ` en los errores, claves obligatorias y arrays de extensiones | `capsule/framing.go`, `accesskey` | -| `extension.ts` | Arrays de extensiones, leídos con su objeto (capa 3 de §69.1). Registros con ubicación opcional (`registeredIn`): una extensión conocida fuera de los objetos y arrays de su registro cuenta allí como desconocida (§54, §72), como `extension.Placement` en Go. Reglas del array: de 1 a 64, en orden estrictamente ascendente de los bytes UTF-8 de `extension_id` (nunca por unidades UTF-16), `extension_version` hasta 2³² − 1, `data` ausente o `bstr` no vacío, ningún id en los dos arrays; registros, críticas y no críticas (capa 4) | `extension` | +| `extension.ts` | Arrays de extensiones, leídos con su objeto (capa 3 de §69.1). Registros con ubicación opcional (`registeredIn`): una extensión conocida fuera de los objetos y arrays de su registro cuenta allí como desconocida (§54, §72), como `extension.Placement` en Go. Reglas del array: de 1 a 64, en orden estrictamente ascendente de los bytes UTF-8 de `extension_id` (nunca por unidades UTF-16), `extension_version` hasta 2³² − 1, `data` ausente o `bstr` no vacío, ningún id en los dos arrays; registros, críticas y no críticas (capa 4). `checkWrite` es la regla de los codificadores del §72 para las extensiones de la especificación (`NOTE_ID`, `CAPSULE_ID`): `datekeys.note` solo en el array no crítico de la cabecera y `datekeys.capsule` solo en el de una `.dkk`, con datos válidos; la aplican el escritor de cápsulas y el de `.dkk` | `extension` (`CheckWrite` y el registro `Standard`) | | `profile.ts` | Provider Profile: CBOR exacto, `profile_hash`, reglas 1 a 4 de §12.1 en su orden (el límite de `period` de §74 en la capa del esquema; alfabetos, clave pública del grupo del scheme y fórmula de `chain_hash`), registro pinneado; Quicknet fijado por su CBOR y su hash | `profile` | | `bls12381.ts` | Pertenencia de claves públicas BLS12-381 comprimidas (G1 y G2) al subgrupo, como `FromCompressed` de kilic | `kyber-bls12381` | | `ibe.ts` | IBE-CCA de tlock sobre G2 para Quicknet (§63 paso 11): `decryptOnG2` y `encryptOnG2RFC9380` (Qid = H(id) en G1 con el DST de RFC 9380, sigma aleatorio, U = r·G2), con la puerta de codificación canónica de `bls12381.ts` sobre la firma y U; H2 sobre GT serializado en el orden de kilic (nunca `Fp12.toBytes` de noble), H3 y H4; `roundIdentity`; el cuerpo `U ‖ V ‖ W` de 128 bytes del stanza. Errores `IbeError` con motivo (`length`, `encoding`, `identity`, `proof`) y texto fijos, sin ningún valor del cálculo; borra sigma y los hashes derivados. Sobre `@noble/curves` 2.4.0; lleva el aviso MIT de `tlock-js`, cuya estructura sigue. Lo usa la apertura (`open.ts`) | `encrypt/ibe` de drand/kyber (`DecryptCCAonG2`), `tlock.BytesToCiphertext` y `TimeUnlock` | @@ -65,18 +65,18 @@ La inspección (pasos 1 a 8) no importa ninguna dependencia. Funciona en navegad | `bech32.ts` | Bech32 (BIP 173) tal como `internal/bech32` de `age`, que la referencia copia como `codec/bech32`; conserva su aviso MIT | `codec/bech32` | | `datekey.ts` | `dk1_` canónico con las reglas de lectura de §19 (CR, LF y todo carácter fuera del alfabeto fallan el paso 1; números JSON por su valor decimal exacto), ronda desde una fecha con precisión de nanosegundos y cota de 9999-12-31T23:59:59Z (§15), parser RFC 3339 equivalente a `time.Parse(time.RFC3339Nano, …)`; `compareInstants` e `isInstant`; `LONG_HORIZON_SECONDS` e `isLongHorizon`, el umbral de 365 días de los avisos de §53 y §50, una política de producto | `datekey` | | `header.ts`, `control.ts`, `accesskey.ts` | PUBLIC_HEADER, CONTROL_CBOR y `.dkk` (cuerpo y trama), decodificar y codificar, con las capas de §69.1. CONTROL_CBOR se lee y se escribe para un formato: versión de schema 1 sin las claves 6 y 7, o 2 y 3 con `payload_length` (8 bytes, hasta L_MAX) y `padding` (1 o 2); 103 bytes sin extensiones sea cual sea L | `capsule`, `accesskey` | -| `body.ts`, `security.ts`, `head.ts` | El formato 3 (§29.2 a §29.7): la trama de `BODY` (`AREA_LEN`, `SECURITY_LEN` y `HEAD_LEN`) y los ceros del área, `ERR_INTEGRITY`; el `SECURITY_CBOR` vacío que escriben los writers, y los veredictos de la v0.11 con sus textos y las líneas que los muestran: X; F0 a F6, con la firma de `alg` 1 y la de `alg` 2 comprobadas en el contexto de la cápsula; y S0 a S5, con el sello de `seal_type` 2. `evaluateSecurity` nunca lanza: una excepción al evaluar la firma da F1, y una al evaluar el sello, S2, cada una sin tocar el otro veredicto. Y el head, con las capas de §69.1: R1 y R8 en el CDDL, R8 por los bytes UTF-8 y no por el orden UTF-16 de las cadenas de JavaScript, y luego el comentario, el autor declarado, las rutas, la maquetación, R7 y R9, todo `ERR_HEAD_INVALID`, y las extensiones críticas del objeto `head` | `capsule/format3.go`, `capsule/signature.go` | +| `body.ts`, `security.ts`, `head.ts` | El formato 3 (§29.2 a §29.7): la trama de `BODY` (`AREA_LEN`, `SECURITY_LEN` y `HEAD_LEN`) y los ceros del área, `ERR_INTEGRITY`; el `SECURITY_CBOR` vacío que escriben los writers, y los veredictos de la v0.11 con sus textos y las líneas que los muestran, las de un certificado con los textos del borrador v0.12 (cada nombre entre « y », la autoridad del sello de cada firmante de F6 y el aviso de que DateKeys no comprueba quién emitió los sellos): X; F0 a F6, con la firma de `alg` 1 y la de `alg` 2 comprobadas en el contexto de la cápsula; y S0 a S5, con el sello de `seal_type` 2. `evaluateSecurity` nunca lanza: una excepción al evaluar la firma da F1, y una al evaluar el sello, S2, cada una sin tocar el otro veredicto. Y el head, con las capas de §69.1: R1 y R8 en el CDDL, R8 por los bytes UTF-8 y no por el orden UTF-16 de las cadenas de JavaScript, y luego el comentario, el autor declarado, las rutas, la maquetación, R7 y R9, todo `ERR_HEAD_INVALID`, y las extensiones críticas del objeto `head` | `capsule/format3.go`, `capsule/signature.go` | | `author.ts` | Lo que se firma y se sella (§29.8, §29.11): `payload_commit`, `control_commit` sobre `CONTROL_SIG`, `head_digest`, `signers_digest`, `AUTHOR_MESSAGE` (99 bytes de ASCII) y su código, que se toma byte a byte como en Go, `SIG_PART` y `SEAL_SUBJECT`. Nada se guarda: todo se recalcula de la cápsula abierta | `capsule/signature.go` | | `ed25519strict.ts` | La verificación estricta de la firma de `alg` 1 (§29.9): las cuatro condiciones del perfil, con la aritmética del grupo de `@noble/curves`, cuyo `verify` usa la ecuación con cofactor y acepta lo que el perfil rechaza. Da la respuesta de Go en los 18 vectores de `ed25519_strict.json` | `internal/ed25519strict` | -| `der.ts` | La comprobación estricta de DER que hace la firma CMS antes de mirar dentro (§29.10): longitudes definidas y mínimas, BOOLEAN, INTEGER, NULL, OID y BIT STRING canónicos, solo los tipos universales que usan los certificados, las firmas y los tokens, y una profundidad de 32; `setOfSorted` para los SET OF cuyo esquema conoce quien llama | `internal/der` | -| `cms.ts` | La firma CMS (RFC 5652) de `alg` 2 y el token RFC 3161 del sello (§29.10, §29.11), con el orden de comprobaciones y los resultados de Go y la tabla cerrada de algoritmos: RSA PKCS #1 v1.5 y PSS con `BigInt`, de 2048 a 4096 bits, y ECDSA sobre P-256, P-384 y P-521 con la aritmética de `@noble/curves`, solo con el punto sin comprimir, como `x509.ParsePKIXPublicKey`. Lee del certificado lo que usa el §29.10: a quién nombra, el emisor que dice, su validez y su clave; nunca comprueba quién lo emitió ni si se revocó. Lee OID y enteros en tiempo lineal, y un nombre o una hora conserva un U+FEFF inicial, como en Go | `internal/cms` | -| `securitycms.ts` | Los veredictos de una firma de `alg` 2, F1, F2, F5 y F6, con cada firmante requerido y ajeno nombrado como el §29.7 (su nombre, o el SHA-256 del certificado si no cumple las reglas del autor declarado, y su emisor, o el SHA-256 de su `Name`), y los de un sello, S1 a S5, con su autoridad y t | `capsule/signature2.go` | -| `note.ts` | La nota pública (§24.1): la extensión `datekeys.note` de la cabecera, de 1 a 1024 bytes de UTF-8 que cumplen las reglas del autor declarado, con los textos y el orden de `extension.CheckNote`. Una cadena con un sustituto suelto se rechaza: nunca se escribe con U+FFFD. `publicNote` la lee como Go, con un U+FEFF inicial que la deja inservible | `extension` (`CheckNote`, `NewNote`, `Note`) | +| `der.ts` | La comprobación estricta de DER que hace la firma CMS antes de mirar dentro (§29.10): longitudes definidas y mínimas, BOOLEAN, INTEGER, NULL, OID y BIT STRING canónicos, UTCTime y GeneralizedTime en sus formas de X.690 y con una fecha que existe (`parseTime` los lee), solo los tipos universales que usan los certificados, las firmas y los tokens, los tipos de cadena restringidos entre ellos, y una profundidad de 32; `setOfSorted` para los SET OF cuyo esquema conoce quien llama, que pueden repetir un elemento | `internal/der` | +| `cms.ts` | La firma CMS (RFC 5652) de `alg` 2 y el token RFC 3161 del sello (§29.10, §29.11), con el orden de comprobaciones y los resultados de Go y la tabla cerrada de algoritmos: RSA PKCS #1 v1.5 y PSS con `BigInt`, de 2048 a 4096 bits y con un módulo impar, y ECDSA sobre P-256, P-384 y P-521 con la aritmética de `@noble/curves`, solo con el punto sin comprimir. Lee el certificado campo a campo con el perfil del §29.10 del borrador v0.12, como Go: a quién nombra (su `givenName` y su `surname` antes que su `commonName`), el emisor que dice (su `commonName` o su `organizationName`), su validez y su clave; nunca comprueba quién lo emitió ni si se revocó. Compara los OID por los bytes de su DER, acepta un SET OF que repite un elemento y cuenta como uno un certificado repetido, y un nombre conserva un U+FEFF inicial, como en Go | `internal/cms` | +| `securitycms.ts` | Los veredictos de una firma de `alg` 2, F1, F2, F5 y F6, con cada firmante requerido y ajeno nombrado como el §29.7 del borrador v0.12 (su nombre si cumple las reglas del autor declarado, tiene como mucho 64 puntos de código y no lleva dos espacios seguidos, y si no el SHA-256 del certificado; su emisor, o el SHA-256 de su `Name`; y la autoridad de su sello), y los de un sello, S1 a S5, con su autoridad y t | `capsule/signature2.go` | +| `note.ts` | La nota pública (§24.1): la extensión `datekeys.note` de la cabecera, de 1 a 1024 bytes de UTF-8 que cumplen las reglas del autor declarado, con los textos y el orden de `extension.CheckNote`. Una cadena con un sustituto suelto se rechaza: nunca se escribe con U+FFFD. `checkNoteData` comprueba los bytes de una nota en el orden de Go: la longitud, el UTF-8 y las reglas. `publicNote` la lee como Go, con un U+FEFF inicial que la deja inservible, y `unusableNote` distingue una nota inservible de ninguna | `extension` (`CheckNote`, `NewNote`, `Note`), `capsule` (`Header.UnusableNote`) | | `pathrule.ts`, `pathrule-tables.ts` | Las reglas de las rutas y de los textos del head (§29.5, §29.6), de R1 a R10 con R4b, R6b, R6c y R9, NFD, el pliegue y la clave de R7, con los textos de error de Go. Nunca usa `normalize`, `toLowerCase`, `localeCompare`, `Intl` ni las clases `\p{…}`, cuya versión de Unicode cambia con el motor: las tablas de Unicode 18.0.0 y WindowsBestFit las genera `datekeys-go` (`pathrule/gen -ts`), y una prueba recalcula su digest | `internal/pathrule` | | `open3.ts`, `sink.ts` | El paso 17 del formato 3 en sus subpasos 17.2 a 17.8, con la precedencia de Go: un fallo de `age` o un texto en claro que no mide P prevalecen, manda el primer subpaso que falla, y los códigos distintos de `ERR_INTEGRITY` solo se dan tras leer `PAYLOAD_AGE` hasta el final. `Sink` (`begin`, `create`, `commit`, `abort`) recibe los ficheros y solo los publica en el paso 18; `MemorySink` los guarda en memoria, que crece con los bytes recibidos y nunca con los tamaños que declara el head | `capsule/open3.go` | | `framing.ts` | Prelude DKC1 (16 bytes), con el formato de la cápsula, de 1 a 3, y DKK1 (12 bytes) en el orden de §23 y §40, longitudes de 1 byte hasta los límites de §57, y troceo de secciones | `capsule/framing.go` | | `age.ts` | Parser estricto de la cabecera `age` v1 (§28.1) sobre los ficheros binarios, con los textos de error de `age`; reglas de stanzas, con los 16 de `INNER_ACCESS_AGE` en el formato 2 (`ACCESS_SLOTS`); `MAX_AGE_HEADER_LEN` (2 MiB), el límite que usa la página para leer solo el prefijo de un `.dkc` grande | `agewrap`, `filippo.io/age/internal/format` | -| `inspect.ts` | Pasos 1 a 8 de §63 y la vista JSON de `datekeys inspect -json` (`inspectView`, `inspectJSON`) | `capsule/inspect.go`, `internal/inspectview` | +| `inspect.ts` | Pasos 1 a 8 de §63 y la vista JSON de `datekeys inspect -json` (`inspectView`, `inspectJSON`), con la nota pública (`public_note`) o el aviso de que no se muestra (`public_note_unusable`). `inspect` lee la nota bajo demanda, solo si la cabecera lleva una, así que las tablas de Unicode nunca se cargan con `/inspect` | `capsule/inspect.go`, `internal/inspectview` | | `prefix.ts` | Lecturas acotadas de un `Blob`: el prefijo de un `.dkc` que necesitan los pasos 1 a 8 (`readCapsule`) y, de una `.dkk`, como mucho 12 bytes + 16 MiB + 1 (`readAccessKey`), que dan el mismo resultado que el fichero entero | | | `index.ts` | Reexporta todo salvo la fase 2 (`ibe.ts`, `release.ts`, `open.ts`, `tlock.ts`, `x25519.ts`, `bech32.ts`, `digest.ts` y `agefile.ts`), la fase 3 (`encrypt.ts`, `writer.ts`, `recipient.ts` y `random.ts`), el formato 3 (`open3.ts`, `sink.ts`, `head.ts`, `pathrule.ts` y sus tablas, que pesan 136 KB) y la v0.11 (`author.ts`, `ed25519strict.ts`, `der.ts`, `cms.ts`, `securitycms.ts` y `note.ts`), y una guarda lo comprueba. La página importa `index.ts`, y reexportarlos metería noble, `age-encryption` o las tablas en la primera carga de `/inspect` aunque no los use, porque noble ejecuta código al cargarse. La página carga la apertura bajo demanda (`src/lib/inspector/opener.ts`) | | | `testing/` | Solo para tests: lectura de `testdata/` y de sus formatos (`vectors.ts`: ediciones, vectores), constructores de CBOR en hex, cirugía de cápsulas, firmas y tokens de prueba (`cmsbuild.ts`), y el writer como generador de vectores (`encrypt.ts`), el único que escribe el formato 2 u otra área. Solo lo importan los tests y `testing/` mismo: una guarda de `dependencies.test.ts` lo comprueba en `src/`, y `check-build.mjs` en el bundle de las páginas | | @@ -265,10 +265,13 @@ Umbrales de cobertura (`vitest.config.ts`), al 100 % en líneas, ramas, funcione - `testdata/vectors/cbor.json`: cada vector genérico (`accept` y `reject`) pasa por `walk` con los `max_depth` y `max_len` del fichero; los enteros aceptados comparan su `value` (número o, por encima de 2⁵³ − 1, `bigint`), y los rechazados «above max_len» o «above max_depth» se aceptan sin ese límite. Cada vector de `schemas` pasa por el decodificador de su esquema (`decodeProfile`, `decodeHeader`, `decodeControl` con el formato del vector, 1 si no lo trae, también el 3, `decodeAccessKeyBody`) con el código exacto, y un objeto aceptado se reescribe a los mismos bytes. - `testdata/vectors/padding.json`: P con las dos reglas y la longitud de `PAYLOAD_AGE` de cada L, incluidas las fronteras en que fallan las operaciones de 32 bits y un logaritmo en coma flotante, y las longitudes por encima de L_MAX, que se rechazan. `padding.test.ts` contrasta además `paddedLength` con el §29.1 escrito en `BigInt` sobre 20 000 longitudes de todo el rango. - `testdata/vectors/tlock_ibe.json`: el vector de H2 del IBE de tlock (§63 paso 11). Hasta que llegue `ibe.ts` (fase 2), el test lo recalcula con `@noble/curves` 2.4.0: los puntos son canónicos para `bls12381.ts`, el pairing serializado en el orden de kilic es el GT del vector y su H2 coincide; el orden propio de noble (`Fp12.toBytes`) da otro hash. -- `testdata/vectors/mutations.json`: se leen los 210 casos enteros (ediciones sobre un fixture o hex congelado, release, reloj, registro, extensiones, `.dkk`, identidades y, en los cuatro que abren, sus veredictos). Los 210 pasan por `open` con su release, su reloj, su registro, sus extensiones, su `.dkk`, sus identidades y un `MemorySink`, y dan el mismo código en el mismo paso que Go y el mismo texto que `capsule.Open` (`testing/mutation-texts.json`); los cuatro de seguridad del formato 3 abren con los veredictos X, F1, F2 y S1 del registro. También pasan como `Blob` con un stream de salida, que termina abortado en los 206 que fallan, y un sumidero que nunca se publica. Son los 169 del §64: las 33 mutaciones de las dos primeras listas en cada formato, las 23 de la lista del formato 2 y las 47 de la del formato 3; y 41 más. Ninguno de los que fallan sin red pide un release. Los 57 de los pasos 1 a 8 pasan además por `inspect`, y un test fija los recuentos y el orden. Las `.dkk` ofrecidas se decodifican. +- `testdata/vectors/mutations.json`: se leen los 218 casos enteros (ediciones sobre un fixture o hex congelado, release, reloj, registro, extensiones, `.dkk`, identidades y, en los once que abren, sus veredictos). Los 218 pasan por `open` con su release, su reloj, su registro, sus extensiones, su `.dkk`, sus identidades y un `MemorySink`, y dan el mismo código en el mismo paso que Go y el mismo texto que `capsule.Open` (`testing/mutation-texts.json`); los cuatro de seguridad del formato 3 abren con los veredictos X, F1, F2 y S1 del registro, y siete de la lista de la v0.11 con los suyos. También pasan como `Blob` con un stream de salida, que termina abortado en los 207 que fallan, y un sumidero que nunca se publica. Son los 178 del §64: las 33 mutaciones de las dos primeras listas en cada formato, las 23 de la lista del formato 2, las 48 de la del formato 3 y las 8 de la lista de la v0.11; y 40 más. Ninguno de los que fallan sin red pide un release. Los 57 de los pasos 1 a 8 pasan además por `inspect`, y un test fija los recuentos y el orden. Las `.dkk` ofrecidas se decodifican. - `testdata/vectors/inspect_differential.json`: las 5 110 mutaciones de los catorce fixtures de base dan el mismo veredicto, código y paso que Go; los `bases` se comprueban por su SHA-256. - `testdata/vectors/paths.json` y `path_fold.json`, con las tablas cuyo digest nombran: cada ruta pasa por las reglas de una entrada con el texto exacto, cada árbol por la decodificación de un head de ficheros de 0 bytes, y cada segmento da su NFD y su clave de R7. -- `testdata/vectors/head_schema.json` y `security.json`: cada head pasa por `decodeHead` con el código de la primera capa que falla y el texto exacto de `ERR_HEAD_INVALID`, y un head válido se reescribe a sus bytes; cada área de seguridad da sus veredictos. +- `testdata/vectors/head_schema.json` y `security.json`: cada head pasa por `decodeHead` con el código de la primera capa que falla y el texto exacto de `ERR_HEAD_INVALID`, y un head válido se reescribe a sus bytes; cada área de seguridad da, en el contexto del fichero, sus veredictos y sus líneas. +- `testdata/vectors/security_cms.json`: los 135 casos de `alg` 2 y de `seal_type` 2 dan, en su contexto, los veredictos, el resultado de cada firmante exigido y de cada ajeno, la autoridad y la hora del sello y las líneas de Go, byte a byte. `ed25519_strict.json` lo corre `ed25519strict.test.ts`. +- `testdata/vectors/note.json`: cada nota pasa por `checkNoteData`, con su resultado y el texto exacto de la regla que incumple, y por `publicNote`, `unusableNote` y `newNote`. +- `testdata/vectors/locator.json`: solo se comprueba que nombra esta especificación, porque el localizador aún no está portado. - `src/lib/dkc/testing/zip-vectors.json`: cómo lee `archive/zip` de Go los ZIP de la página. `scripts/zip-ts-samples.mjs` escribe con `ZipSink` las muestras de `testing/zip.ts` en un directorio: ficheros en carpetas con nombres fuera de ASCII y todas las clases de fecha (1970, 2³¹ − 1, 2³¹, 9999 y ninguna, que toma la hora de la ronda), un fichero dentro de una carpeta, y 65 535 ficheros, que hacen el ZIP64 por número de entradas. `scripts/zip-go-read.go`, solo con la biblioteca estándar, registra el SHA-256 de cada ZIP y una línea por entrada: nombre, bit 11, método, CRC-32, tamaños, fecha leída de los campos extra y SHA-256 del contenido, leído con el CRC comprobado. `zipsink.test.ts` vuelve a escribir cada muestra, exige su SHA-256 y calcula las líneas que Go tiene que dar. Para regenerarlo: `node scripts/zip-ts-samples.mjs DIR > zip-samples.json` y `go run scripts/zip-go-read.go DIR zip-samples.json > zip-vectors.json`. - `src/lib/dkc/testing/mutation-texts.json`: el texto del error de `capsule.Open` para cada caso de `mutations.json`, u `ok`. Lo escribe `scripts/mutation-go-texts.go`, que reproduce los casos como `internal/testkit` de la referencia, que un módulo de fuera no puede importar: el perfil de Quicknet o ninguno, una fuente con el release del caso, la `.dkk` ya decodificada, las identidades, las extensiones del caso con los textos de `testkit.KnownExtensions` y un sumidero que descarta. Comprueba cada código contra el corpus. Para regenerarlo, desde un módulo Go temporal como el de abajo: `go run mutation-go-texts.go ../datekeys-ts/testdata > mutation-texts.json`. - `src/lib/dkc/testing/ibe-vectors.json`: los valores de referencia de `ibe.ts`. Los escribe `scripts/ibe-go-vectors.go` con kyber, tlock y `age`, las librerías de la referencia Go, y `ibe.test.ts` los comprueba todos: @@ -405,7 +408,7 @@ Comprueba que los ficheros coinciden con `SOURCE.json`, sin faltantes ni sobrant `.gitattributes` marca `testdata/**` como binario para que git no altere ningún byte. -Copia actual: la de `testdata/SOURCE.json` (tag `spec-v0.11`, `ae33434`), que se sincroniza con `node scripts/sync-testdata.mjs sync --commit spec-v0.11`. +Copia actual: la de `testdata/SOURCE.json` (la cabeza de la rama `v0.12` de `datekeys-go`, `601e6d2`, con el borrador v0.12), que se sincroniza con `node scripts/sync-testdata.mjs sync --commit 601e6d2`. ## Licencia