You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DateKeys-App/CHANGELOG.md

290 lines
48 KiB

# Changelog
Cambios notables de la librería TypeScript y de la página. El proyecto usa versionado semántico; mientras sea 0.x, no hay promesa de estabilidad. La sección «Versiones» del [README](README.md) explica qué cubre cada número.
## 0.4.0 — sin publicar
La especificación 0.15, de la rama `v0.15` de `datekeys-go`: el objeto release, el release en la mano y el paso 9.c.
### La especificación 0.15: el objeto release y el release en la mano (07-10-2026)
- `SPEC_VERSION` pasa a `0.15` y la versión a `0.4.0-dev`. `testdata` se sincroniza con `datekeys-go` en `3c3e737`, que añade `vectors/release.json`, los ficheros de `releases/` y el campo `source` de `mutations.json`.
- **El objeto release** (§47.1). `releaseobject.ts`, sin noble, hace lo de `provider/release.go` y `provider/archive.go` de Go, con sus textos byte a byte: `encodeRelease` y `decodeRelease`, con las capas del paso 10 (el tamaño de 1 a 1024 bytes antes de decodificar, el tipo y la versión, el schema); `parseRelease`, que lee también el JSON de drand como lo lee `encoding/json` de Go, con `ERR_RELEASE_INVALID` para cualquier fallo; `ReleaseSupplier` y `encodedRelease`, el release en la mano; y `ReleaseArchive`, el archivo de releases local, formato informativo (§50), cuyos fallos son `ERR_RELEASE_UNAVAILABLE`, también una ronda a ceros.
- **La cadena en el paso 10.** `verifyRelease` compara primero la cadena que nombra el release con la del perfil fijado (`ERR_PROFILE_MISMATCH`), y después la ronda y la firma.
- **El paso 9.c, opción B.** `open` acepta `release`, un release en la mano, en lugar de `source`: no se compara con el reloj, `Opened.clockBehind` dice si el reloj iba por detrás de la fecha, y el paso 10 lo decodifica con los códigos de ese paso. A una fuente de red no se le pide nada antes de `round_time`, como antes. El release verificado lleva la cadena del perfil fijado.
- **Las pruebas.** `vectors.test.ts` corre `release.json` entero, con los textos de Go, y cada fichero de `releases/`, que la guarda de `testdata` exige. El corpus de mutaciones lee `source` y da a cada caso su clase de fuente, como `singleSource` de Go. `scripts/mutation-go-texts.go` hace lo mismo, y `testing/mutation-texts.json` se regenera con Go: cambian el campo `spec`, «round not reached yet», que ahora abre, y los cuatro casos nuevos, con los textos que explica la v0.15. Los demás ficheros de `testing/` generados con Go no cambian: sus scripts usan una fuente de red con releases válidos y sin cadena, con la que Go se comporta como antes.
- **La página `/inspect`.** El release se puede pegar, como antes, o dar en un fichero: el objeto release, la respuesta de drand en JSON o un archivo de releases. Va a `open` como release en la mano. Si el reloj del dispositivo dice que la fecha no ha llegado, la página ya no se cierra: deja dar el release, sin pedirlo a drand, y si abre la cápsula dice que el reloj parece ir atrasado. Las glosas de los pasos 9 y 10 dicen lo que comprueba la v0.15.
## 0.3.0 — 6 de octubre de 2026
La especificación 0.14, el tag `spec-v0.14` de `datekeys-go`: un solo scheme de drand y la raíz de confianza byte a byte, con `tlock_steps.json`. El autor la cerró el 6 de octubre de 2026, con el tag `v0.3.0`, para congelarla en el paquete de la revisión externa: la `0.2.0` tenía el `testdata` en `spec-v0.13`.
### La especificación 0.14, aprobada (06-10-2026)
- El autor aprobó el 6 de octubre de 2026 el borrador v0.14 con la recomendación de cada una de sus diez decisiones: `datekeys-go` lo cierra con el tag `spec-v0.14` (`39b2033`). `SPEC_VERSION` pasa a `0.14`, `testdata` se sincroniza con ese tag, y `testing/mutation-texts.json` se regenera con Go: solo cambia su campo `spec`. Ningún otro fichero de `testing/` generado con Go lleva ese campo ni depende de un perfil de otro scheme; los veredictos de `bls12381-vectors.json` salen idénticos con Go en `39b2033`, y solo se corrige su descripción.
- **Un solo scheme de drand (decisión 8).** `validateProfile`, y con ella `decodeProfile`, admite solo `bls-unchained-g1-rfc9380`, con la clave pública en G2, como `validateDrand` de Go desde `c041fa3`: un nombre que drand no conoce sigue siendo «is not a drand scheme», y cualquier otro scheme de drand, `pedersen-bls-unchained` y `bls-unchained-on-g1` incluidos, falla con `ERR_UNKNOWN_PROFILE` y el texto de Go, byte a byte, antes de mirar la clave y el `chain_hash`. Ningún perfil fijado ni ninguna cápsula válida cambian.
- **`tlock_steps.json`.** Un bloque nuevo de `vectors.test.ts` lee el fichero con el formato estricto de los demás y recorre, valor a valor y con el código de la librería, los pasos 10 y 11 de las cinco stanzas: M, H(M), la ecuación de pairing, las partes del stanza, e(firma, U), H2, sigma, H4, la file key, cada intento de H3 y r, y r·G2 = U; y las comprobaciones negativas: el DST de G2, la ronda sin SHA-256, el bit más alto puesto a cero, una firma de otra ronda y un V o un W editados. La guarda de `testdata` lo exige. `ibe.ts` exporta para ello `h3Base`, `h3Try` y `hashToG1`, que `h3`, el cifrado y `release.ts` usan ahora; `index.ts` no los exporta.
- El comentario de `h3` decía que se pone a cero el bit más alto de cada intento: el código desplaza el primer byte un bit a la derecha, como kyber, y así lo dice ahora.
## 0.2.0 — 6 de octubre de 2026
La especificación 0.13, el tag `spec-v0.13` de `datekeys-go`: lee los formatos 1 a 3 y escribe el 3, con la firma de autor, el sello, la llave de palabras, la nota pública y el localizador de `datekeys.capsule`. El autor la cerró el 6 de octubre de 2026, con el tag `v0.2.0`. Desde la fase 3 hasta la especificación 0.13, en orden inverso:
Format 3, step 3: read capsule format 3 of spec v0.10 Syncs testdata with datekeys-go at the tag spec-v0.10 (cc35d2c) and moves the reader to the DateKeys Protocol Specification v0.10. The three capsule formats are read. - framing: FORMAT_3, and isPadded for formats 2 and 3. control: schema version 3, with the keys 6 and 7 of version 2. SPEC_VERSION is 0.10. - open: OpenOptions.sink receives the files of a format 3 capsule (sink.ts: Sink with begin, create, commit and abort, as capsule.Sink, and MemorySink). Without one, open rejects with a TypeError right after step 2, before any request, as ErrSinkRequired. Opened gains head, verdicts, areaLen and unusableHeadExtensions. - open3.ts: step 17 of format 3 in its substeps 17.2 to 17.8, as openBody of the reference: a failure of age or a plaintext whose length is not P prevails, the first failing substep decides, and the codes other than ERR_INTEGRITY are reported only after reading PAYLOAD_AGE to its end. Reads grow with the bytes received, never with the lengths BODY declares. A failure of the sink is ERR_INTEGRITY with its text, and the sink is aborted once after begin. - The page: opener.ts opens the fixtures of format 3 into a MemorySink; the open panel says that it does not deliver their files yet, and the glosses of the steps name format 3. check-build.mjs refuses to ship the heads, salts, comments and paths of the format 3 fixtures. Tests: the 21 fixtures, format 3 laid out byte by byte from its record and opened into a sink with its files and verdicts; the 209 cases of the corpus from memory and from a Blob, with the code, the step and, new, the exact text of capsule.Open, frozen by scripts/mutation-go-texts.go in testing/mutation-texts.json, which replays the corpus as internal/testkit does (its extension validator texts included); the 5110 differential cases over 14 bases; paths, path_fold, head_schema and security vectors; the control of schema version 3 in cbor.json; and step 17 on crafted plaintexts sealed again to I_PAYLOAD, whose texts capsule.Open gives on the same plaintexts. ibe-vectors.json gains the nine format 3 fixtures from scripts/ibe-go-vectors.go; the twelve before are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
### El localizador sellado, comprobado antes de la fecha (06-10-2026)
- `parseInfo` comprueba el localizador sellado como `ParseInfo` de Go desde `69dbb0c`, a petición del autor: la cadena del stanza tlock en hexadecimal en minúsculas y, si la DateKey es de Quicknet, la de Quicknet; y que el cuerpo tras la cabecera `age` lleve un texto de 4096 bytes o un múltiplo, así que una cabecera sin cuerpo se rechaza. Cada caso es `ERR_EXTENSION_DATA_INVALID` con el texto de Go. `infoExtension` rechaza además una DateKey de un perfil que la librería no fija. El límite de 1 MiB al abrir el localizador se queda, por decisión del autor.
- Los vectores de Go del localizador se regeneran sobre ese commit: cambian solo los casos de esas comprobaciones.
### La especificación 0.13, aprobada (06-10-2026)
- El autor aprobó el 6 de octubre de 2026 el borrador v0.13, NAT64, tal como estaba: `datekeys-go` lo cierra con el tag `spec-v0.13` (`913dd60`). `SPEC_VERSION` pasa a `0.13`, `testdata` se sincroniza con ese tag, y `testing/mutation-texts.json` se regenera con Go: solo cambia el campo `spec` de cada fichero.
### Dos direcciones que el §44.1 ya rechazaba (06-10-2026)
- Un CID con un carácter de más cuyos bits son cero, que decodifica a los mismos bytes, y `https://[[2000::]/` se rechazan, como en `datekeys-go` desde `e801e03`: `isCidV1` rechaza 5 bits sobrantes o más, y el host de un literal IPv6 lleva un solo par de corchetes. Eran dos de las decisiones pendientes del autor, pero el texto aprobado de la v0.12 ya lo pedía.
- `testing/locator-uris.json` y `locator-vectors.json` se regeneran con `scripts/locator-go-vectors.go` sobre ese commit: cambian solo las diez direcciones de esas dos formas y los localizadores que las llevan.
### La nota pública en `/inspect` (06-10-2026)
- `/inspect` muestra la nota pública justo debajo del veredicto: el texto del creador, en la letra serif de la página y sobre el fondo de aviso, con dos líneas que dicen que nadie la ha comprobado, que la lee cualquiera que tenga el fichero y que antes de la fecha nadie puede comprobar quién creó la cápsula ni si va firmada, como `showNote` de la CLI de Go. Una nota que no cumple las reglas de texto no se muestra, y la página lo dice.
- `buildReport` lleva la nota en `Report.note`, con su prueba. Comprobado en el navegador con el fixture `format3_note`.
- **Errores que no se esperaban.** Las páginas ya no enseñan el mensaje de una excepción, que podía venir en inglés y con una URL interna, como «Failed to fetch dynamically imported module: http://localhost:5188/src/lib/inspector/opener.ts». `unexpectedProblem` de `format.ts` lo dice en español y con lo que hay que hacer: recargar si no llegó una parte de la página, volver a elegir un fichero que el navegador ya no deja leer, liberar espacio, o, en otro caso, recargar y usar la herramienta de línea de órdenes. La excepción va a la consola. Lo usan la apertura, la lectura de una cápsula en `/inspect` y la creación en `/create`.
- **El servidor de desarrollo ya no recarga la página al abrir.** `vite.config.ts` hace que Vite prepare desde el arranque las dependencias que las páginas cargan bajo demanda (`optimizeDeps.include`). Sin eso, la primera apertura le hacía preparar dos módulos de noble y recargar la página, y la carga en curso fallaba con ese mensaje. `dependencies.test.ts` comprueba que la lista está completa. La versión compilada no tenía el problema.
### NAT64, del borrador v0.13 (06-10-2026)
- `testdata` se sincroniza con `datekeys-go` en `a83b44d`, el borrador v0.13, sin aprobar: añade `vectors/resolved_ip.json`, y ningún otro fichero cambia. `SPEC_VERSION` sigue en `0.12`.
- `checkResolvedIp` cuenta una dirección de NAT64 a la que resuelve un nombre, de `64:ff9b::/96` o del prefijo de la red (el parámetro `nat64`), por la IPv4 que lleva dentro, con los textos de `locator.CheckResolvedIP` de Go. `ipaddr.ts` exporta `isIpv4In6`. Un bloque nuevo de `vectors.test.ts` corre los 42 casos.
The writer signs and seals: the hooks of capsule.EncryptFiles of Go encryptFiles gains authorKey (alg 1, an AuthorSigner such as AuthorKey), cmsSigner (alg 2, a CMS signature with certificates), sealer (seal_type 2, an RFC 3161 token) and largeArea, as EncryptOptions of Go at spec-v0.12: the same checks in the same order with the same texts, the signature and the seal made with the final control and head and before anything is written, and the security area evaluated by the reader of this library in the context of the capsule before it is written, as Go's security does. The hooks may be asynchronous. The area grows to 64 KiB only when what was signed does not fit and largeArea allows it, and the larger capsule counts in the limit of memory. security.ts encodes the area with its signature and seal, and securitycms.ts encodes SIGNERS. scripts/signing-go-vectors_test.go, run as a test in an export of datekeys-go at spec-v0.12, writes testing/signing-vectors.json: with the draws of crypto/rand of Go and the signatures and tokens of its hooks, encryptFiles writes the eight signed and sealed capsules of Go byte for byte, asks the hooks over the same messages, and fails with the text of Go in the other 15 recipes; and Go opens the five capsules that scripts/signing-ts-samples.mjs writes with this library, its own random values and certificates, with the same verdicts and lines. check-build.mjs fails when a page loads the author keys with the page, or when /inspect can load them at all. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 day ago
### Las claves de autor y la firma al escribir (06-10-2026)
Las claves de autor de `alg` 1 y los enganches de firma y de sello del escritor, como `authorkey` y `capsule.EncryptFiles` de Go en `spec-v0.12`, byte a byte. Ningún paquete ni módulo nuevo: el SHA-512, el HKDF, ChaCha20-Poly1305 y el scrypt de `age-encryption` ya estaban.
- **`ed25519sign.ts`**, la firma Ed25519 en código propio: `crypto_sign` de TweetNaCl, como el port de Dart, con el SHA-512 de `@noble/hashes`. Aritmética exacta en `Float64Array`, y los secretos nunca en `BigInt`. JavaScript no promete tiempo constante ni borrar la memoria, y el código lo dice.
- **`authorkey.ts`**, el paquete `authorkey` de Go: `AuthorKey` (`generate` con una fuente de azar inyectable, `fromSeed`, `publicKey`, `sign`, `clear`, `secret` y un `toString` que oculta el secreto), `authorPublicString`, `parseAuthorPublic`, `parseAuthorSecret`, `marshalAuthorKey`, `encryptAuthorKey` y `readAuthorKey`, con los textos de error de Go byte a byte, también los de `age`, también los números al revés del de `PublicString`. Las cadenas se leen como bytes, con las mayúsculas, las minúsculas y los espacios del paquete `unicode` de Go, que `gounicode.ts` trae en tablas generadas con Go (`scripts/go-unicode-tables.go`). El fichero cifrado lleva scrypt con logN 16, y se lee con un máximo de 16, 64 KiB y las líneas de `bufio.Scanner`.
- **El escritor.** `encryptFiles` gana `authorKey` (`alg` 1), `cmsSigner` (`alg` 2) y `sealer` (`seal_type` 2), que pueden ser asíncronos, y `largeArea`. Se comprueban en el orden de Go y con sus textos; la firma y el sello se piden con el control y el head finales y antes de escribir nada, y el área se evalúa con el lector antes de escribirla, como `security` de Go. Un área que crece a 64 KiB cuenta en el límite de memoria. `security.ts` escribe el área con firma y sello, y `securitycms.ts`, `SIGNERS`.
- **Interoperabilidad con Go**, en dos ficheros congelados de `testing/`:
- `authorkey-vectors.json`, de `scripts/authorkey-go-vectors.go`: 234 firmas, la reducción de escalares, 24 claves, `Generate` y el fichero cifrado con los valores al azar de Go, que `encryptAuthorKey` reproduce byte a byte, 1 288 cadenas, 3 240 runas y 130 ficheros que leer, cada uno con el resultado o el texto de Go;
- `signing-vectors.json`, de `scripts/signing-go-vectors_test.go` en una exportación de `spec-v0.12`: con los valores al azar y las firmas de Go, `encryptFiles` escribe sus ocho cápsulas firmadas y selladas byte a byte, y falla con su texto en las otras 15. Y Go abre las cinco cápsulas que escribe `scripts/signing-ts-samples.mjs` con esta librería, sus certificados y su azar, con los mismos veredictos y las mismas líneas.
- **Guardas.** `dependencies.test.ts` deja importar noble a `authorkey.ts` y `ed25519sign.ts`, y `age-encryption` a `authorkey.ts`, y no deja que `index.ts` los reexporte. `check-build.mjs` falla si una página carga las claves de autor con la página, o si `/inspect` puede cargarlas. `authorkey.ts`, `ed25519sign.ts` y `gounicode.ts` quedan al 100 % de cobertura.
- **Pruebas.** `npm run verify` pasa con 7 904; una más, la de un área que crece y ya no cabe en memoria, lee 1 GiB y corre con `DATEKEYS_LARGE=1`. Con 27 fallos inyectados uno a uno en la firma, las claves, el escritor y los codificadores, las pruebas detectan 26; el otro es equivalente: el escritor compara la clave del veredicto con la del enganche, que no puede ser otra si la firma da F4. Y `check-build.mjs` detecta las claves de autor en `/inspect`.
- **Integración.** Se hizo en la rama `signing`, en paralelo con el localizador, y se puso encima de él y de NAT64 con `rebase`, con conflictos solo en las guardas, en `vitest.config.ts`, en el README y aquí. Con las tres partes, `npm run verify` pasa con 8 017 pruebas y una aplazada.
### El localizador de `datekeys.capsule` (06-10-2026)
El paquete `locator` de `datekeys-go` en `spec-v0.12` (§43 a §44.1), con los mismos checks en el mismo orden, los mismos códigos y los mismos textos de error, byte a byte, como lo portó `datekeys-dart` en sus partes 7a y 7b.
- **Lo que no necesita criptografía** (`locator.ts`, `ipaddr.ts`): los datos de la extensión (`parseInfo` e `infoExtension`); `standardExtensions`, el registro de las extensiones de la especificación, que por defecto comprueba los datos de `datekeys.capsule` como `locator.Standard`; las direcciones, con cada regla del §44.1 de la v0.12 (`checkURI`, `addressHost`, `usableAddresses`), los bloques de IANA comparados byte a byte sobre los 16 bytes de una IPv6 y los CID v1 en base32; `checkResolvedIp`, la IP a la que resuelve un nombre, como la de `datekeys-dart`, que hoy rechaza `64:ff9b::/96`; el texto en claro con su relleno (`marshalLocator`, `unmarshalLocator`, `plaintextLength`); y el resto en su host (`restIn`, `hide`).
- **La criptografía** (`ageio.ts`, `envelope.ts`): abrir un localizador sellado con el release de su ronda (`openSealed`, `openInfoLocator`), que lee como mucho 1 MiB como Go; abrir el sobre (`openEnvelope`); sellar (`seal`) y crear el sobre (`newEnvelope`), con una fuente de lo aleatorio inyectable que se lee en el orden de Go. `ageio.ts` lee y escribe ficheros `age` como `filippo.io/age` 1.3.2, con sus textos, porque `locator.Open` y `OpenEnvelope` los copian. Sin dependencias nuevas: usa los módulos de noble que ya usa `x25519.ts`, y HMAC es el HKDF-Extract de `@noble/hashes/hkdf.js`.
- **Nada entra en `/inspect`.** `index.ts` no reexporta el localizador: la nota trae las tablas de Unicode, y el sobre, noble. `dependencies.test.ts` añade `ageio.ts` a los que pueden importar noble y los cuatro módulos a los que `index.ts` no reexporta, y `check-build.mjs` falla si una página carga el localizador con su primera carga.
- **Contra Go**, todo con el resultado y el texto de Go:
- `vectors.test.ts` corre entero `testdata/vectors/locator.json`, en vez de mirar solo su campo `spec`;
- `testing/locator-uris.json` y `testing/locator-vectors.json`, de `scripts/locator-go-vectors.go`: 6 531 casos de direcciones, IP, textos en claro, localizadores sellados, sobres, datos de la extensión, el registro y la apertura de una cápsula cuya `.dkk` lleva `datekeys.capsule`, y las 20 585 bases del relleno de −4 100 a 16 484;
- `testing/locator-seal.json`, de `scripts/locator-seal-go-vectors.go`: con la misma semilla, `seal` y `newEnvelope` sacan los mismos valores que Go en el mismo orden y escriben los mismos bytes;
- `testing/locator-interop.json`: Go abre los localizadores y los sobres que escribe esta librería (`scripts/locator-ts-samples.mjs` y `scripts/locator-go-verdicts.go`), de 0 bytes a 16 MiB y un byte.
Los generadores son los de `datekeys-dart` con las semillas de este repositorio, y corren en una exportación de `datekeys-go` en `spec-v0.12`.
- **Lo que el autor tiene pendiente** se queda como en Go: un CID no canónico pasa, `https://[[2000::]/` pasa, `parseInfo` comprueba menos de lo que podría y `openSealed` lee 1 MiB.
- **Pruebas.** `locator.test.ts`, `envelope.test.ts` y `locator.interop.test.ts`, con los cuatro módulos al 100 % de cobertura: 7 901 pruebas en total.
### La especificación 0.12, aprobada (06-10-2026)
- El autor aprobó el 6 de octubre de 2026 el borrador v0.12, tal como estaba: `datekeys-go` lo cierra con el tag `spec-v0.12` (`fe405e2`). `SPEC_VERSION` pasa a `0.12`, y `testdata` se sincroniza con ese tag: solo cambia el campo `spec` de cada fichero.
- `testing/mutation-texts.json` se regenera con `scripts/mutation-go-texts.go`: solo cambia su campo `spec`.
- La librería ya seguía el borrador: no cambia nada más. `npm run verify` pasa con 7 832 pruebas.
### Los vectores compartidos de la llave de palabras (06-10-2026)
- `testdata` se sincroniza con `datekeys-go` en `084728d`, que añade `vectors/wordkey.json`: los casos de la llave de palabras que pide el §64 de la v0.11, que hasta ahora solo estaban en las pruebas de Go. Ningún otro fichero cambia.
- Un bloque nuevo de `vectors.test.ts` los corre: las palabras de 45 textos, entre ellos cada espacio del §38.1 y tres que no lo son; lo que hace un escritor con 20 textos, con el texto del error de Go; y 6 identidades con su recipient, el vector del §38.1 el primero. La librería no cambia: todos coinciden.
### 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`.
- **CMS como lo lee Go.** Un emisor que incumple las reglas del autor declarado se muestra con el SHA-256 de su `Name` (`RawIssuer`), y no con el del certificado. Una clave ECDSA solo cuenta sin comprimir, `0x04` y las dos coordenadas, como en `x509.ParsePKIXPublicKey`: con el punto comprimido, un firmante es «no verificable» (F5) y un sello da S1. Un `UTF8String` y las horas del certificado y del token conservan un U+FEFF inicial, así que ese nombre se muestra con el hash y esa hora rompe el perfil (F1, S2).
- **Lectura lineal.** `oidOf` e `intOf` leen en tiempo lineal, sin un desplazamiento por byte, que tardaba unos 700 ms con 60 KB; los atributos de un tipo se añaden sin copiarse.
- **`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; una al decodificar el área da X. La referencia hará lo mismo desde la v0.12.
- **Pruebas que no probaban lo que decían.** Las de `cms.test.ts` de un segundo content-type y dos signature-time-stamp fallaban por un SET OF desordenado, y ahora fallan por la regla de recuento. La de profundidad de `der.test.ts` fallaba por la longitud, y ahora prueba la frontera de 32 niveles.
- **La nota pública.** `checkNote` rechaza un texto con UTF-16 mal formado, con el texto de Go para el UTF-8 inválido, así que ninguna nota se escribe alterada. `publicNote` conserva un U+FEFF inicial, que la deja inservible como en Go. También lo conservan `authorCode` y la lectura de la respuesta de los relays de drand; el head y las rutas ya lo hacían, y sus pruebas lo fijan con los textos de Go.
- **El escritor.** `testVectors` y `areaLen` salen de las opciones públicas: con ellas, cualquiera podía escribir el formato 2 o un área de 512 bytes, que delata la falta de firma (§55.2).
- Lo que solo pide un generador de vectores es el argumento `TestVectors` del núcleo, que solo pasan los ayudantes de `testing/encrypt.ts`: `encryptVectors`, `encryptWith` y `encryptFilesWith`.
- `encrypt` conserva la forma de `capsule.Encrypt`: sin generador, falla con su texto.
- `dependencies.test.ts` y `check-build.mjs` dejan `testing/` fuera de la librería y de las páginas.
- **Las opciones, como en Go.** Como generador, `encrypt` rechaza la nota y el área con el texto de `capsule.Encrypt`. Los errores de la nota llevan `capsule: `, y las opciones se comprueban en el orden de `newSealer`.
- **El tamaño con nota.** `capsuleLength` acepta la nota pública y predice exactamente el tamaño del `.dkc` con ella.
- **Interoperabilidad.** `capsule-vectors.json` se regenera con el escritor actual: las seis cápsulas de formato 3 llevan el área de 32 KiB, y hay dos más con nota pública, una de 1024 bytes. Go las abre con cada credencial, encuentra el área de 32 KiB y lee la nota con `Header.PublicNote`. El fichero gana el texto de `capsule.Encrypt` para una nota en el formato 2, y los de `capsule.EncryptFiles` para nueve notas inválidas.
- **Documentación.** El README completa la tabla de módulos (`author.ts`, `ed25519strict.ts`, `der.ts`, `cms.ts`, `securitycms.ts` y `note.ts`), los veredictos de la v0.11, las dependencias y sus guardas, y los recuentos del corpus de mutaciones; los comentarios ya no hablan del área de 512 bytes ni de una versión sin `alg`.
- **Pendiente, con la v0.12:** el lector de certificados, cuyo perfil se fija ahora en Go (T2, T6, T7 y T8), el texto del emisor sin CN y la prueba de `cms.test.ts` que lo compara consigo mismo.
### `testdata` en `spec-v0.11` (01-10-2026)
- `testdata` se sincroniza con el tag `spec-v0.11` de `datekeys-go` (`ae33434`), y `SPEC_VERSION` pasa a `0.11`. Trae tres fixtures (`format3_signed`, con firma de clave propia; `format3_signed_cms`, con dos certificados sellados; `format3_sealed`, con firma y sello RFC 3161) y tres ficheros de vectores (`ed25519_strict.json`, `security_cms.json` y `locator.json`). El corpus de mutaciones pasa a 210 casos, con uno fuera del §64: una firma de `alg` 1 que no verifica, F2. `ibe-vectors.json` añade los tres fixtures y rehace los de `format3_signature_unsupported` y `format3_seal_unsupported`; `mutation-texts.json` se rehace con el `capsule.Open` de esa referencia.
- **La firma de clave propia, `alg` 1** (§29.8, §29.9), portada: `ed25519strict.ts` comprueba las cuatro condiciones del perfil estricto con la aritmética de `@noble/curves` (que solo ofrece la ecuación con cofactor) y da la respuesta de Go en los 18 vectores de `ed25519_strict.json`; `author.ts` calcula `payload_commit`, `control_commit`, `head_digest`, `signers_digest`, `AUTHOR_MESSAGE` y su código, y los registros de `format3_signed` los confirman. `evaluateSecurity(área, contexto)` da F2, F3 y F4, `open` pasa el contexto del control y del head, y `OpenOptions.authorKeys` son las claves que la persona guardó. Los dos módulos usan solo `@noble/curves` y `@noble/hashes`, que ya iban en el bundle: ningún paquete nuevo, y entran en la lista de quien puede importar noble.
- **La firma con certificados, `alg` 2, y el sello RFC 3161, `seal_type` 2** (§29.10, §29.11), portados sin dependencias nuevas: `der.ts` comprueba el DER byte a byte, `cms.ts` lee la firma CMS y el token con la tabla cerrada de algoritmos (RSA PKCS #1 y PSS en `BigInt`, síncrono, y ECDSA con la aritmética de `@noble/curves`) y `securitycms.ts` da F1, F2, F5 y F6 con los firmantes nombrados, y S1 a S5 con la autoridad del sello. `evaluateSecurity` los devuelve con su `detail`, `verdictLines` escribe las líneas de F6 y S4, y `open` pasa la hora de la ronda. Reproducen los 22 casos de `security_cms.json`, con los resultados de cada firmante, y los fixtures `format3_signed_cms` y `format3_sealed`. `testing/cmsbuild.ts` construye firmas y tokens de prueba con WebCrypto, y `cms.test.ts` porta los casos hostiles de Go.
- **El escritor de la v0.11** (§29.2, §24.1, §62.1 regla 13): `encryptFiles` escribe el área de seguridad de 32 KiB (`AREA_LEN` pasa de 512 a 32768) y acepta `publicNote`, la extensión `datekeys.note` de la cabecera pública (`note.ts`: `checkNote`, `newNote`, `publicNote`, con las reglas de texto del autor declarado). Otra área solo la escribe un generador de vectores, con `testVectors` y `areaLen`, y así los tests reproducen byte a byte los fixtures que escribió un escritor de la v0.10, de 512 bytes. `lengths.ts` y la página calculan L con el área nueva. Una nota cambiada después de escribir la cápsula falla en el paso 15.
- **Lo que esta biblioteca no hace todavía:** el escritor no firma ni pide sellos (`alg` 1, `alg` 2 y RFC 3161 solo se leen y verifican), la página no pide ni muestra la nota, y el localizador del §44.1 (la extensión `datekeys.capsule` de la `.dkk`, su sobre y su relleno) y la página de firma. `locator.json` solo se comprueba en su estructura.
Format 3, step 3: read capsule format 3 of spec v0.10 Syncs testdata with datekeys-go at the tag spec-v0.10 (cc35d2c) and moves the reader to the DateKeys Protocol Specification v0.10. The three capsule formats are read. - framing: FORMAT_3, and isPadded for formats 2 and 3. control: schema version 3, with the keys 6 and 7 of version 2. SPEC_VERSION is 0.10. - open: OpenOptions.sink receives the files of a format 3 capsule (sink.ts: Sink with begin, create, commit and abort, as capsule.Sink, and MemorySink). Without one, open rejects with a TypeError right after step 2, before any request, as ErrSinkRequired. Opened gains head, verdicts, areaLen and unusableHeadExtensions. - open3.ts: step 17 of format 3 in its substeps 17.2 to 17.8, as openBody of the reference: a failure of age or a plaintext whose length is not P prevails, the first failing substep decides, and the codes other than ERR_INTEGRITY are reported only after reading PAYLOAD_AGE to its end. Reads grow with the bytes received, never with the lengths BODY declares. A failure of the sink is ERR_INTEGRITY with its text, and the sink is aborted once after begin. - The page: opener.ts opens the fixtures of format 3 into a MemorySink; the open panel says that it does not deliver their files yet, and the glosses of the steps name format 3. check-build.mjs refuses to ship the heads, salts, comments and paths of the format 3 fixtures. Tests: the 21 fixtures, format 3 laid out byte by byte from its record and opened into a sink with its files and verdicts; the 209 cases of the corpus from memory and from a Blob, with the code, the step and, new, the exact text of capsule.Open, frozen by scripts/mutation-go-texts.go in testing/mutation-texts.json, which replays the corpus as internal/testkit does (its extension validator texts included); the 5110 differential cases over 14 bases; paths, path_fold, head_schema and security vectors; the control of schema version 3 in cbor.json; and step 17 on crafted plaintexts sealed again to I_PAYLOAD, whose texts capsule.Open gives on the same plaintexts. ibe-vectors.json gains the nine format 3 fixtures from scripts/ibe-go-vectors.go; the twelve before are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
El formato 3 de la especificación 0.10, según `PLAN_formato3_ts.md` (en `../docs`). La versión que lo publique la decide el autor.
### Llave de palabras y firma de drand
- Llave de palabras v2, como decide el borrador de la especificación 0.11 (§38.1): la sal lleva además el `capsule_id`, así que las mismas palabras dan otra llave en cada cápsula; las palabras se pasan a minúsculas con la tabla de Unicode 18.0.0 de `pathrule.ts`, no con la de la plataforma; cuentan solo las distintas de 3 letras o más; y se rechazan los caracteres invisibles. `encryptFiles` recibe las palabras (`words`) y deriva la llave al sortear el `capsule_id`. `/create` pide escribirlas dos veces y muestra cómo se guardan. Las cápsulas hechas antes con palabras ya no se abren con ellas. El módulo pasa a `src/lib/dkc/wordkey.ts`.
- `/inspect` pide la firma de la ronda a los relays de drand con un botón (`drand.ts`), además de poder pegarla.
- Una cápsula «solo con una llave» puede abrirse con palabras que elige quien la crea, al menos 6, en vez del fichero `.dkk` (`wordkey.ts`): PBKDF2-SHA256 de 600.000 vueltas, con la red y la ronda como sal, da una clave X25519 que entra como una persona de `age` más. El formato no cambia; dan igual mayúsculas, acentos y espacios.
### Paso 8: revisión adversarial y rediseño de `/create`
- Correcciones de la revisión: el payload llega a `age` en trozos de un chunk (`chunked`), el sumidero nunca se aborta tras el commit y recibe copias, el escritor copia cada trozo que lee y acepta fuentes escritas como clase, y las extensiones de tipos incorrectos son un `TypeError`.
- El sitio es siempre claro. `/create` se rediseña como una carta al futuro: tres preguntas, fechas rápidas, la fecha de apertura en un sobre de correo aéreo con el botón, y los detalles técnicos plegados; los mensajes ya no citan R4 ni §29.6.
- `/inspect` marca el principio de un fichero como contenido del creador, sin comprobar, y conserva ZWNJ y ZWJ en el comentario y el autor.
### Paso 7: `/create` con ficheros y carpetas
- La página cifra ficheros y carpetas, elegidos o soltados, con un comentario y un autor declarado. Las rutas se pueden editar y se comprueban mientras se escriben, cada problema en su fila y en español; los ficheros de los sistemas quedan fuera, tachados, salvo que se marquen; y una casilla, marcada por defecto, guarda la fecha de cada fichero.
- El tamaño exacto del `.dkc` antes de escribir, con los ficheros medidos una vez (`measureFiles`, `headLengthOf` y `bodyLengthOf` en `lengths.ts`), y el progreso de las dos lecturas de `encryptFiles`.
- `create-files.ts` (la lista, sin tablas) y `create-check.ts` (las reglas en español, bajo demanda), al 100 %. Go abre una cápsula de la página, y `/inspect` también.
### Paso 6: `/inspect` abre el formato 3
- La página abre las cápsulas de formato 3: los ficheros van al fichero temporal por un `ZipSink`, o a la memoria, y se muestran primero los veredictos, después el autor declarado y el comentario, y luego cada ruta como texto, con su tamaño, su fecha y los avisos de la CLI de la referencia. Se descarga el fichero, si es el único, con el ZIP de su carpeta como segunda opción, o el ZIP de todos y cada fichero por separado.
- `files.ts` (avisos, rutas y descargas) y `opener.ts` (`OpenedFiles`, la falta de espacio), cargados bajo demanda; `ZipSink` comprueba el espacio al empezar.
- `check-build.mjs` exige que las tablas de las rutas no entren en la primera carga de ninguna página.
Format 3, step 5: the ZIP sink of the page, which archive/zip reads zipsink.ts is the sink of the page for a format 3 capsule (design of format 3, section 5). Its files go to the temporary file of OPFS: the file itself when the capsule holds one file of one segment, and otherwise a ZIP of stored entries laid out from the head before any byte arrives. Each local header is written at its offset, the bytes of the file follow as open delivers them, the CRC-32 of the entry is patched in its header with a positioned write, and commit writes the central directory and closes the file; abort discards it, also when the opening failed before begin. Each file is a contiguous range of the file written (ranges), and zipOf makes the same ZIP in memory as a Blob of its parts. tempfile.ts: the writable of a temporary file takes TempChunk, bytes at the position of the file or at a given one, as FileSystemWritableFileStream does; cancellable is generic. Interoperability: scripts/zip-ts-samples.mjs writes the samples of testing/zip.ts with ZipSink, and scripts/zip-go-read.go reads them with archive/zip of the Go standard library: names out of ASCII with bit 11, stored entries, their CRC-32 and sizes, the times of the extra fields in 1970, at 2^31 - 1 and after it, in 9999 and the time of the round for a file without one, and 65535 entries, ZIP64 by their number. The reading is frozen in testing/zip-vectors.json, and zipsink.test.ts writes each sample again, requires its SHA-256 and computes the entries Go must have read. zipsink.ts is covered at 100 %. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
### Paso 5: el ZIP de la página
- `zipsink.ts`: `ZipSink`, el sumidero de la página sobre el fichero temporal de OPFS. Un fichero de un segmento va tal cual, y los demás casos a un ZIP propio, con el CRC-32 de cada entrada parcheado con una escritura posicionada y el directorio central al hacer commit; nada se publica antes del paso 18. `zipOf` hace el mismo ZIP en memoria.
- `tempfile.ts`: el `writable` de un fichero temporal acepta trozos con posición (`TempChunk`), como `FileSystemWritableFileStream`.
- Interoperabilidad: `archive/zip` de Go lee las muestras de la página, 65 535 entradas con ZIP64 incluidas, con sus nombres, CRC-32, tamaños, fechas y contenidos (`testing/zip-vectors.json`, de `scripts/zip-ts-samples.mjs` y `scripts/zip-go-read.go`).
Format 3, step 4: encryptFiles, the writer of capsule format 3 encryptFiles(files, opts) writes a .dkc of format 3 as capsule.EncryptFiles at spec-v0.10, on the sealer of the previous commit: - newHead: the comment, with CR LF and a lone CR turned into LF, the declared author and every path checked with the rules of the reader, in the words of a writer (spec 62.1 rule 15); the files in the byte order of their paths, not the UTF-16 order of JavaScript strings; and the mtime in seconds from 1970 to 9999, none outside. - L measured with a head whose salt and SHA-256 are zero, at most 16 MiB and L_MAX; the first reading hashes each file; the head with a fresh salt, the empty security area and the frame are checked with the rules of the reader before anything is written. - BODY is the content of seal: the frame, the area, the head and the files read a second time, which fail if a size or a SHA-256 changed (rule 18), with the texts of readSource. FileSource describes a file (path, size, mtime in milliseconds, open), and fileSource makes the one of a File or a Blob. The draws gain the salt of the head. lengths.ts gains bodyLength and headLength, which measure the head from the sizes of its CBOR items without the Unicode tables, and mtimeSeconds and headComment, which the writer shares. Tests: the five fixtures that EncryptFiles wrote are reproduced byte for byte, PRELUDE, PUBLIC_HEADER, CONTROL_CBOR, HEAD_CBOR and BODY, and their .dkk; capsuleLength with bodyLength gives the size written, and headLength agrees with encodeHead on 300 random heads around every boundary of the CBOR heads; the invalid inputs give the texts that capsule.EncryptFiles gives to the same inputs, taken from the reference with a scratch program. writer.ts, encrypt.ts and lengths.ts stay at 100 %. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
### Paso 4: la escritura del formato 3
- `writer.ts` se parte como el writer de Go: `newSealer` comprueba las opciones que no dependen del contenido, y `seal` escribe la cápsula de un formato alrededor de un contenido dado en trozos. El formato 2 no cambia.
- `encryptFiles(files, opts)` escribe un `.dkc` de formato 3 con sus ficheros, el comentario y el autor declarado, y las extensiones del head, como `capsule.EncryptFiles`: lee cada fichero dos veces y falla, con el texto de Go, si cambió entre las dos lecturas. `fileSource` hace la fuente de un `File`. Los sorteos ganan la sal del head.
- `lengths.ts`: `bodyLength`, `headLength`, `mtimeSeconds` y `headComment`, para dar el tamaño exacto del `.dkc` antes de escribirlo.
- `encrypt` escribe el formato 2 solo con `testVectors`, y sin comentario, autor ni extensiones del head, con los textos de `capsule.Encrypt`; las pruebas, `encryptWith` y los scripts de muestras lo piden.
- `/create` escribe el formato 3 con `encryptFiles`: el fichero va bajo su nombre y con su fecha de modificación, y el plan da el tamaño exacto con `bodyLength`.
- Interoperabilidad: `capsule-vectors.json` se regenera con seis cápsulas de formato 3 escritas por `encryptFiles`, que Go abre en un `Sink` con cada credencial, con los mismos ficheros, head y veredictos; las trece de formato 2 y los demás bloques se regeneran igual.
Format 3, step 4: encryptFiles, the writer of capsule format 3 encryptFiles(files, opts) writes a .dkc of format 3 as capsule.EncryptFiles at spec-v0.10, on the sealer of the previous commit: - newHead: the comment, with CR LF and a lone CR turned into LF, the declared author and every path checked with the rules of the reader, in the words of a writer (spec 62.1 rule 15); the files in the byte order of their paths, not the UTF-16 order of JavaScript strings; and the mtime in seconds from 1970 to 9999, none outside. - L measured with a head whose salt and SHA-256 are zero, at most 16 MiB and L_MAX; the first reading hashes each file; the head with a fresh salt, the empty security area and the frame are checked with the rules of the reader before anything is written. - BODY is the content of seal: the frame, the area, the head and the files read a second time, which fail if a size or a SHA-256 changed (rule 18), with the texts of readSource. FileSource describes a file (path, size, mtime in milliseconds, open), and fileSource makes the one of a File or a Blob. The draws gain the salt of the head. lengths.ts gains bodyLength and headLength, which measure the head from the sizes of its CBOR items without the Unicode tables, and mtimeSeconds and headComment, which the writer shares. Tests: the five fixtures that EncryptFiles wrote are reproduced byte for byte, PRELUDE, PUBLIC_HEADER, CONTROL_CBOR, HEAD_CBOR and BODY, and their .dkk; capsuleLength with bodyLength gives the size written, and headLength agrees with encodeHead on 300 random heads around every boundary of the CBOR heads; the invalid inputs give the texts that capsule.EncryptFiles gives to the same inputs, taken from the reference with a scratch program. writer.ts, encrypt.ts and lengths.ts stay at 100 %. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
- Pruebas: los cinco fixtures que escribió `EncryptFiles`, byte a byte; los tamaños frente a lo escrito y 300 heads aleatorios frente a `encodeHead`; y las entradas inválidas, con los textos que da `capsule.EncryptFiles` a las mismas entradas.
Format 3, step 3: read capsule format 3 of spec v0.10 Syncs testdata with datekeys-go at the tag spec-v0.10 (cc35d2c) and moves the reader to the DateKeys Protocol Specification v0.10. The three capsule formats are read. - framing: FORMAT_3, and isPadded for formats 2 and 3. control: schema version 3, with the keys 6 and 7 of version 2. SPEC_VERSION is 0.10. - open: OpenOptions.sink receives the files of a format 3 capsule (sink.ts: Sink with begin, create, commit and abort, as capsule.Sink, and MemorySink). Without one, open rejects with a TypeError right after step 2, before any request, as ErrSinkRequired. Opened gains head, verdicts, areaLen and unusableHeadExtensions. - open3.ts: step 17 of format 3 in its substeps 17.2 to 17.8, as openBody of the reference: a failure of age or a plaintext whose length is not P prevails, the first failing substep decides, and the codes other than ERR_INTEGRITY are reported only after reading PAYLOAD_AGE to its end. Reads grow with the bytes received, never with the lengths BODY declares. A failure of the sink is ERR_INTEGRITY with its text, and the sink is aborted once after begin. - The page: opener.ts opens the fixtures of format 3 into a MemorySink; the open panel says that it does not deliver their files yet, and the glosses of the steps name format 3. check-build.mjs refuses to ship the heads, salts, comments and paths of the format 3 fixtures. Tests: the 21 fixtures, format 3 laid out byte by byte from its record and opened into a sink with its files and verdicts; the 209 cases of the corpus from memory and from a Blob, with the code, the step and, new, the exact text of capsule.Open, frozen by scripts/mutation-go-texts.go in testing/mutation-texts.json, which replays the corpus as internal/testkit does (its extension validator texts included); the 5110 differential cases over 14 bases; paths, path_fold, head_schema and security vectors; the control of schema version 3 in cbor.json; and step 17 on crafted plaintexts sealed again to I_PAYLOAD, whose texts capsule.Open gives on the same plaintexts. ibe-vectors.json gains the nine format 3 fixtures from scripts/ibe-go-vectors.go; the twelve before are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
### Paso 3: la lectura del formato 3, con `testdata` en `spec-v0.10`
- `testdata` se sincroniza con el tag `spec-v0.10` de `datekeys-go` (`cc35d2c`), y `SPEC_VERSION` pasa a `0.10`.
- `framing.ts`: `FORMAT_3`, e `isPadded` para los formatos 2 y 3. `control.ts`: la versión de schema 3, con las claves 6 y 7 de la 2.
- `open.ts` y `open3.ts`: el paso 17 del formato 3 en sus subpasos, con la precedencia y los textos de `capsule.Open`. Los ficheros van a `OpenOptions.sink` (`sink.ts`: `Sink` y `MemorySink`), que solo los publica en el paso 18; sin sumidero, `open` rechaza con un `TypeError` justo tras el paso 2. `Opened` gana `head`, `verdicts`, `areaLen` y `unusableHeadExtensions`.
- La página: `opener.ts` abre en memoria los fixtures del formato 3; el panel de apertura dice que aún no entrega sus ficheros, y los textos de los pasos nombran el formato 3.
- Pruebas: los 21 fixtures; los 209 casos del corpus, con el texto exacto de `capsule.Open`, congelado con `scripts/mutation-go-texts.go` en `testing/mutation-texts.json`; las 5 110 mutaciones del diferencial; los vectores de rutas, pliegue, head y seguridad; y los textos del paso 17 con textos en claro preparados, contrastados con Go. `ibe-vectors.json` gana los nueve fixtures nuevos.
- `check-build.mjs` impide publicar el head, la sal, el comentario y las rutas de los fixtures del formato 3.
### Paso 2: el códec del formato 3
- `body.ts`, `security.ts` y `head.ts`, como `capsule/format3.go`: la trama de `BODY`, los veredictos del área de seguridad con sus textos, y el head con las capas de §69.1. `ERR_HEAD_INVALID` es el código 19.
### Pasos 0, 1 y parte del 5: las reglas de las rutas y el ZIP de la página
- `pathrule-tables.ts`, generado por `datekeys-go` con Unicode 18.0.0 y WindowsBestFit, y `pathrule.ts`, las reglas de las rutas y de los textos del head con los textos de error de Go.
- `crc32.ts` y `zip.ts`, en `src/lib/inspector`: la disposición del ZIP en que la página entregará los ficheros, con entradas almacenadas, nombres UTF-8, las fechas en DOS, NTFS y el sello extendido, y ZIP64.
### La fase 3: la escritura del formato 2
Fase 3: la escritura de cápsulas de formato 2, según `PLAN_fase3_escritura.md` (v3, en `../docs`). Hecha, pasos 0 a 7.
Phase 3, steps 6 and 7: the create page /create seals a person's file into a .dkc of format 2 and, when asked, a portable .dkk, in the browser and without network, with the decisions the author confirmed in step 6: time_only by default, the zone of the device with a selector, the warnings of §53 and §50 beyond 365 days, a notice of preliminary protocol, and files named capsula-<opening time, UTC>. - lengths.ts: sealedControlLength moves out of writer.ts, and capsuleLength gives the size of the .dkc before writing it; the property loop checks it on every capsule (500 seeds pass). - datekey.ts: LONG_HORIZON_SECONDS and isLongHorizon. - src/lib/inspector: localtime.ts (local times of a zone as UTC instants, a skipped time refused, a repeated one taken at its later instant), create-input.ts (the form, checked in its order) and creator.ts (the writing, loaded on demand), all at 100 %. - The .dkc goes to an OPFS temporary file, committed only when complete and checked, or to memory up to 64 MiB; the writing can be cancelled. The .dkk stays in memory only; losing it when it is the only credential asks for confirmation. - /inspect also cleans the temporary files of /create, and check-build checks the code loaded on demand of both pages. Checked in the browser on the production build: a capsule made for four minutes later opened afterwards in /inspect with the pasted release and with datekeys decrypt of Go over the network, to the same content. An adversarial review found one major and eight minor issues, all fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
#### Después del paso 7: ayuda de `age` y el texto en claro a la vista
- `/inspect` muestra el principio del texto en claro de cualquier cápsula que se abre, no solo de los fixtures, si es texto: UTF-8 imprimible, hasta 100 000 caracteres de sus primeros 128 KiB. Se ve también un texto escrito en Windows, con CR LF o BOM; la descarga conserva los bytes exactos. `opener.ts` da esos primeros bytes (`PREVIEW_BYTES`), y `opening.ts` decide qué se muestra (`plaintextPreview`).
- Ayuda de las claves de `age`. En `/create`, un bloque plegable explica qué es un destinatario `age1…` y cómo se consigue con `age-keygen`. En `/inspect`, el campo de identidades dice qué pegar: la línea `AGE-SECRET-KEY-1…` del fichero de `age-keygen`, o el fichero entero.
- Al abrir, el contenido va justo debajo del veredicto. La descarga de una cápsula sin extensión propia, como `capsula-<fecha>.dkc`, toma la del contenido (`contentExtension`): `.txt`, `.pdf`, `.png`, `.jpg` y otras por sus primeros bytes. La cápsula no guarda el nombre del fichero (§6, §55.2).
- `vite preview` sirve las páginas con `Cache-Control: no-cache`, para que una pestaña recargada tras compilar no se quede con la página anterior, cuyos ficheros ya no existen.
#### Pasos 6 y 7: la página `/create`
Phase 3, steps 6 and 7: the create page /create seals a person's file into a .dkc of format 2 and, when asked, a portable .dkk, in the browser and without network, with the decisions the author confirmed in step 6: time_only by default, the zone of the device with a selector, the warnings of §53 and §50 beyond 365 days, a notice of preliminary protocol, and files named capsula-<opening time, UTC>. - lengths.ts: sealedControlLength moves out of writer.ts, and capsuleLength gives the size of the .dkc before writing it; the property loop checks it on every capsule (500 seeds pass). - datekey.ts: LONG_HORIZON_SECONDS and isLongHorizon. - src/lib/inspector: localtime.ts (local times of a zone as UTC instants, a skipped time refused, a repeated one taken at its later instant), create-input.ts (the form, checked in its order) and creator.ts (the writing, loaded on demand), all at 100 %. - The .dkc goes to an OPFS temporary file, committed only when complete and checked, or to memory up to 64 MiB; the writing can be cancelled. The .dkk stays in memory only; losing it when it is the only credential asks for confirmation. - /inspect also cleans the temporary files of /create, and check-build checks the code loaded on demand of both pages. Checked in the browser on the production build: a capsule made for four minutes later opened afterwards in /inspect with the pasted release and with datekeys decrypt of Go over the network, to the same content. An adversarial review found one major and eight minor issues, all fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
- El autor confirma las decisiones de la página con cada recomendación: `time_only` por defecto, la zona del dispositivo con un selector, los avisos de §53 y §50 desde 365 días, un aviso de protocolo preliminar y los nombres `capsula-<apertura en UTC>`.
- `/create` cifra un fichero propio en un `.dkc` de formato 2 y, si se pide, en una `.dkk` portable, en el navegador y sin red. Antes de cifrar muestra el instante efectivo, la ronda, la `dk1_`, el tamaño exacto del `.dkc` y lo que deja ver hasta la fecha. El `.dkc` va a un fichero temporal de OPFS, o a memoria hasta 64 MiB, y la escritura se puede cancelar. La `.dkk` vive solo en memoria, y la página avisa si se sale sin descargarla. El resultado lleva el informe de los pasos 1 a 8 de lo escrito.
- `lengths.ts`: `sealedControlLength` sale de `writer.ts`, y `capsuleLength` da el tamaño del `.dkc` antes de escribirlo; el bucle de propiedades lo comprueba en cada cápsula. `datekey.ts`: `LONG_HORIZON_SECONDS` e `isLongHorizon`.
- `localtime.ts`, `create-input.ts` y `creator.ts`, al 100 %. `/inspect` limpia también la zona de crear. `check-build.mjs` comprueba la carga bajo demanda de las dos páginas que la tienen.
- Comprobado en el navegador: una cápsula creada para dentro de cuatro minutos se abrió después en `/inspect` con el release pegado y con `datekeys decrypt` de Go, con el mismo contenido.
- Una revisión adversarial encontró un fallo mayor y ocho menores, todos corregidos. El mayor: la `.dkk` que es la única credencial se podía borrar sin confirmación. Ahora la página la pide al olvidarla y al crear otra cápsula. Entre los menores: la zona desconocida del dispositivo pasa a UTC; el reloj de la página se lee cada segundo; hay un mensaje propio para un reloj anterior a Quicknet; lo escrito no se ofrece si los pasos 1 a 8 lo rechazan; y el foco va a «Cancelar» durante la escritura. `localtime.test.ts` compara la conversión con una búsqueda exhaustiva alrededor de todos los cambios de hora de 2030.
#### Paso 5: interoperabilidad con Go a nivel de cápsula
- `interop.test.ts` y `testing/capsule-vectors.json`: Go abre con `capsule.Open` las trece cápsulas de muestra que escribe `encrypt`, con cada credencial, y reencodifica sus objetos a los mismos bytes. Cubren las dos políticas y las dos reglas, de 0 a 16 credenciales, los bordes de trozo y las extensiones.
- Go rechaza cuatro mezclas de dos cápsulas con el mismo código y paso que `open`, codifica igual 500 entradas aleatorias de los codificadores, y da los mismos textos que esta librería con 22 recipients y 21 opciones inválidas.
- Lo generan `scripts/capsule-ts-samples.mjs` y `scripts/capsule-go-verdicts.go`, y se congela; el test comprueba en cada ejecución los veredictos de Go y que `open` da lo mismo sobre los bytes congelados.
#### Pasos 3 y 4: el writer
Phase 3, steps 3 and 4: the writer of capsule format 2 encrypt(src, opts) writes a .dkc of format 2 and, when asked, a portable .dkk (spec §61, §62, §62.1), in the order and with the texts and codes of capsule.Encrypt: - L known in advance: the size of a Uint8Array or a Blob, or the length declared with a ReadableStream; a source of another length fails with Go's texts; - reforzado padding by default, or bloque256; - 1 to 16 credentials, canonical and not of low order, a dummy in each slot left, whose scalar is wiped once its public key is derived, and a uniform order of the 16; - SEALED_CONTROL_LEN from the formula of §62.1, checked against the real seal; - the self-checks of rule 11, plus OUTER_TIME_AGE under the reader's rules and the header of PAYLOAD_AGE opened by I_PAYLOAD before anything is written. The content is streamed in pieces of 64 KiB, then the zeros of the padding, into memory (up to MAX_MEMORY_DKC) or an output that is closed only once the capsule is complete and checked and aborted on any failure. The core in writer.ts takes its random values from the caller: encrypt.ts passes crypto.getRandomValues, and only testing/encrypt.ts fixes them. Tests: the deterministic sections of the seven format 2 fixtures of Go byte for byte; round trips with open for both policies, 1 to 16 credentials and every padding boundary; the invalid options; streaming and failures of the source and the output; the internal errors with age-encryption replaced by a spy; a property loop (50 seeds per run, 500 by hand). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
- `encrypt.ts` y `writer.ts`: `encrypt(src, opts)` escribe un `.dkc` de formato 2 y, si se pide, una `.dkk` portable, como `capsule.Encrypt`: L conocida de antemano, relleno `reforzado` por defecto, de 1 a 16 credenciales con señuelos en un orden uniforme, `SEALED_CONTROL_LEN` con la fórmula del §62.1 y las autocomprobaciones de la regla 11 y dos más. Streaming desde `Uint8Array`, `Blob` o `ReadableStream`, hacia memoria o hacia un `WritableStream` que solo se cierra con la cápsula completa y comprobada.
- Reproduce byte a byte las secciones deterministas de los siete fixtures de formato 2 de Go, y todo lo que escribe se abre con `open`.
- Tests de streaming, de errores internos con `age-encryption` sustituido y un bucle de propiedades (50 semillas en cada ejecución; 500 pasaron a mano).
#### Paso 2: piezas de apoyo
- `recipient.ts`: recipients `age1…` como `age` 1.3.2, las reglas de §37 con los textos de `agewrap.CheckX25519Recipient` y la lista de recipients de una persona, con errores por número de línea. Sin noble.
- `random.ts`: el índice sin sesgo y la permutación de Fisher–Yates del orden de los 16 huecos, con la prueba de uniformidad de Go.
- `agefile.ts`: los ficheros `age` enteros que antes eran privados de la apertura, para compartirlos con el writer.
- `x25519.ts`: `newX25519Identity` y `x25519PublicKey`, con los vectores de RFC 7748. `digest.ts`: `sha256Hasher`. `datekey.ts`: `compareInstants`, que usa `open.ts`, e `isInstant`.
- `tempfile.ts`: la zona de la apertura y la de crear (`OPEN_AREA`, `CREATE_AREA`), con su limpieza por separado.
- Guardas: solo `agefile.ts`, `open.ts`, `tlock.ts`, `writer.ts` y los tests importan `age-encryption`; solo `encrypt.ts` y `testing/` importan `writer.ts`; `index.ts` no reexporta la apertura ni el writer.
## 0.1.0 — 29 de septiembre de 2026
Read capsule format 2 of spec v0.9 Syncs testdata with datekeys-go at spec-v0.9 (7e2d83c) and moves the reader to the DateKeys Protocol Specification v0.9. Both capsule formats are read; a format 1 capsule keeps the verdict v0.8.2 gave it. - framing: the VERSION of the prelude is the capsule format, 1 or 2 (Prelude.format, FORMAT_1, FORMAT_2, isFormat). - control: decodeControl and encodeControl take the format; schema version 2 adds payload_length (8 bytes, at most L_MAX) and padding (1 or 2). - padding.ts: the rules bloque256 and reforzado of spec §29.1, exact up to L_MAX with BigInt bit lengths and ceil roundings, and the length of PAYLOAD_AGE. - open: exactly 16 stanzas in INNER_ACCESS_AGE of format 2 (step 12), P at step 16, and at step 17 a plaintext of exactly P bytes whose padding is zero; only the first L bytes are delivered, never the padding. Step 17 is recorded when it passes, and step 18 gives the bytes of content, as the reference does. Opened reports the format, L and, in format 2, the rule and P. - inspect: the JSON view carries format, as datekeys inspect -json. - The page shows the format, warns about format 1, and gives the padding rule and P once a format 2 capsule opens. Tests: the twelve fixtures, the 125 mutation cases through open from memory and from a Blob, the 4380 differential cases, padding.json, the format 2 CBOR vectors, and padding.test.ts against a BigInt statement of §29.1. The error texts of the 125 corpus cases were compared with capsule.Open at spec-v0.9. ibe-vectors.json gains the seven format 2 fixtures from scripts/ibe-go-vectors.go; its frozen values are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
Implementa la especificación DateKeys 0.9 (tag `spec-v0.9` de `datekeys-go`) para el perfil Quicknet, y pasa todos los vectores y fixtures compartidos de `datekeys-go` en `7e2d83c`. Hasta el 29-09-2026 implementaba la 0.8.2 (`9ac9cd9`).
### Especificación 0.9: el formato 2
- El prelude lee el formato de la cápsula, 1 o 2 (`Prelude.format`); otro `VERSION` es `ERR_UNSUPPORTED_VERSION` en el paso 2. `DKC_FRAMING_VERSION` desaparece: `FORMAT_1`, `FORMAT_2` e `isFormat`.
- `CONTROL_CBOR` se lee y se escribe para un formato, `decodeControl(b, format)` y `encodeControl(c, format)`: su versión de schema es la del formato, y en el formato 2 lleva `payload_length` (8 bytes, hasta L_MAX) y `padding` (claves 6 y 7).
- `padding.ts`: las reglas `bloque256` y `reforzado` de §29.1, exactas hasta L_MAX = 2⁵³ − 2⁴⁶, y la longitud de `PAYLOAD_AGE`.
- `open`: exactamente 16 stanzas en `INNER_ACCESS_AGE` del formato 2 (paso 12, `ACCESS_SLOTS`), P en el paso 16, y en el 17 un texto en claro de P bytes con ceros tras el contenido, del que solo se entregan los L primeros bytes, nunca el relleno. El paso 17 se registra también cuando se supera, y el 18 da los bytes de contenido, como la referencia. `Opened` da `format`, `payloadLength` y, en el formato 2, `padding` y `paddedLength`.
- La vista JSON de `inspect` lleva `format`, como `datekeys inspect -json`.
- La página muestra el formato de la cápsula, avisa cuando es el 1, que no oculta el número de credenciales ni la longitud exacta del contenido, y al abrir una del formato 2 da la regla de relleno y P.
- `testdata` sincronizado con `spec-v0.9`: doce fixtures, siete de ellos del formato 2, `padding.json`, 125 casos de mutación y 4 380 del diferencial. `ibe-vectors.json` añade los siete fixtures nuevos.
### Hecho
- Codec CBOR del perfil de §58 con los textos de error de la referencia Go.
- Schemas del Provider Profile, `PUBLIC_HEADER`, `CONTROL_CBOR` y `.dkk`.
- Tramas DKC1 y DKK1, cabeceras `age` y DateKey (`dk1_`).
- Extensiones, con los objetos y arrays de su registro.
- La inspección de los pasos 1 a 8 de §63.
- La página estática `/inspect`, sin red. Tras cada compilación se comprueban su política de seguridad y los paquetes de su bundle.
- Fase 2:
- dependencias de ejecución (`age-encryption` 0.3.1, `@noble/curves` y `@noble/hashes` 2.4.0) con sus guardas;
Phase 2, step 5a: open capsules, steps 9 to 18, in memory src/lib/dkc/open.ts runs steps 9 to 18 of spec §63 on top of the steps 1 to 8 of inspectWith. It follows capsule.Open of the Go reference, with its checks, codes and texts: - step 9: the access credentials (the .dkk as an object, then its capsule_id and capsule_digest), then the release, never before the round time. Any failure of the source is ERR_RELEASE_UNAVAILABLE alone, keeping its text and its cause (correction 6); - step 10: verifyRelease; - steps 11 to 13: OUTER_TIME_AGE, the structure against access_policy and INNER_ACCESS_AGE; - steps 14 to 18: CONTROL_CBOR, header_binding, I_PAYLOAD, PAYLOAD_AGE and the commit. The three age files open with the Decrypter of age-encryption and identities that apply the rules of Go's agewrap: the tlock identity on ibe.ts, and the access and payload identities on x25519.ts. A failure of age that no identity reports is ERR_INTEGRITY with the fixed reason of its phase, header or STREAM, never the text of age-encryption. The plaintext is decrypted in memory and returned only after step 18. Streaming to OPFS is step 5b. src/lib/dkc/x25519.ts opens one age X25519 stanza at a time, in the order of age's X25519Identity. Step 13 must try every identity on every stanza (spec §36), and age-encryption's Decrypter stops at the first. Its primitives are the ones age-encryption uses: X25519 and HKDF from noble curves and hashes, and ChaCha20-Poly1305 from @noble/ciphers 2.4.0. The author approved declaring that package as a direct dependency on 2026-09-28; it is the copy already installed and bundled. The guards now allow ciphers, and x25519.ts in the noble allowlist. src/lib/dkc/bech32.ts ports age's internal/bech32, with its MIT notice, to read AGE-SECRET-KEY-1 identities. Tests: - vectors.test.ts runs all 65 cases of the mutation corpus through open. Each gives the code and the step of Go, and no case that fails without the network requests a release. This includes the 34 cases of steps 9 to 18 that were skipped, so the suite no longer skips any test. - open.test.ts: - the five official fixtures open to their plaintext, with each credential, with the checks and details of the reference; - the unusable noncritical extensions are reported; - the source failures and the clock; - age failures by phase; - CONTROL_CBOR that does not decode, and a low-order share in INNER_ACCESS_AGE, through an OUTER_TIME_AGE resealed with the FK_TIME of the Go vectors; - the texts of the identities. - x25519.test.ts checks against age-encryption both ways and against the Go-written stanzas of the fixtures, and covers every low-order share. - bech32.test.ts has the vectors of the reference. x25519.ts and bech32.ts are at 100 % coverage, now thresholds. open.ts is at 100 % of lines; the one branch left is the one for an error that is not a DateKeysError. index.ts does not re-export the opening yet. The page imports index.ts, and re-exporting would pull noble into /inspect (58.7 to 84.9 KB gzip) even unused; step 8 will load it on demand. The site does not change. npm run verify is green: 2,490 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
- el IBE de tlock (`ibe.ts`) y la verificación local de releases (`release.ts`), contrastados con la referencia Go;
- la apertura, pasos 9 a 18 de §63 (`open.ts`), con el texto en claro en memoria. Las identidades estrictas de `agewrap` se apoyan en `x25519.ts`, que abre cada stanza X25519 por separado, y en `bech32.ts`. Los 65 casos del corpus de mutaciones pasan por `open` con el código y el paso de Go, y los cinco fixtures oficiales se abren a su texto en claro;
Phase 2, step 5b: open from a Blob, streaming to an output open(dkc, opts) now takes a Uint8Array or a Blob, such as a File. - Of a Blob it reads only the prefix that steps 1 to 8 need. inspectedLength and readCapsule move from src/lib/inspector/load.ts to src/lib/dkc/prefix.ts, and the page imports them from the library. - The .dkk capsule_digest is computed over the Blob's stream with the new src/lib/dkc/digest.ts, an incremental SHA-256 on @noble/hashes, since Web Crypto hashes whole buffers only. digest.ts joins the noble allowlist of the guards. - PAYLOAD_AGE is decrypted in streaming. The plaintext goes to memory, as before, or to opts.output, a WritableStream. The output is written as age authenticates each chunk, closed only after step 18, and aborted after any failure at any step, even before step 17 (spec §56). A failure of the output is ERR_INTEGRITY with its text, as Go keeps the error of the writer of the plaintext. Tests: - the fixtures from Blobs, to memory and to an output; - a truncated two-chunk payload whose first chunk reached the output before the abort; - early failures that never write; - write and close failures, and an abort that fails; - a .dkk without capsule_digest; - the whole mutation corpus again as Blobs into an output, aborted in every case; - digest.ts against Web Crypto. Coverage of digest.ts is 100 % and a threshold. Checked in the browser (dev server, real OPFS). time_only.dkc, two STREAM chunks, opened from a Blob into FileSystemFileHandle.createWritable gives 78,000 bytes with the SHA-256 of its sidecar. The same file truncated fails at step 17, and the OPFS file keeps its previous content. The quota check, the temporary file and the download belong to the page, in step 8. npm run verify is green: 2,560 tests. The site does not change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
- `@noble/ciphers` 2.4.0 como dependencia directa, aprobada el 28-09-2026: la copia que ya trae `age-encryption`;
- la apertura en streaming. La entrada puede ser un `Blob`, del que se lee solo el prefijo de los pasos 1 a 8 (`prefix.ts`, antes en la página) y se descifra `PAYLOAD_AGE` en streaming. La salida puede ser un `WritableStream`, que se cierra solo tras el paso 18 y se aborta ante cualquier fallo. En el navegador, con un fichero OPFS, un fallo de STREAM deja intacto su contenido anterior.
Phase 2, step 8: the open action of /inspect After steps 1 to 8, a valid capsule whose date has passed on the device clock can be opened in the page: steps 9 to 18 of spec section 63 with open, loaded on demand with a dynamic import (opener.ts), so noble and age-encryption stay out of the first load of every page. - The release is supplied directly by the person (spec 63, step 10): drand's JSON answer or the bare signature, pasted after opening the drand URL the page links to, or the release in the record of an official fixture. The page never fetches it and reads only its round and signature (spec 11, 13). The CSP is unchanged. - time_and_key credentials: a .dkk (readAccessKey reads at most 12 bytes + 16 MiB + 1) or age identities, one per line. - The plaintext of the person's own file goes to a temporary OPFS file (tempfile.ts), committed only after step 18 (spec 56), offered for download and deleted on request, with another capsule, on pagehide and, if left over, on the next visit. One directory and one Web Lock per tab keep other tabs' clean-up away from files in use. Without OPFS, or when the browser refuses it, capsules up to 64 MiB open in memory. An opening in progress stops when another capsule is loaded. - opening.ts builds the page model of steps 9 to 18 as the reference records them; fixtures show their plaintext and compare its SHA-256 with their record. - licenses.txt: the notices of tlock-js (ibe.ts) and age (bech32.ts), the license of every package in the client bundle, Vite's and rolldown's runtime code, and the site's own license. check-build now fails if a notice is missing, or if a page loads noble, @scure/base or age-encryption with its first load. - The home page no longer says that the page never asks for keys. Checked in the browser on the production build: the time_only, time_and_key_portable (with its .dkk) and time_and_key_recipients (with a pasted identity) fixtures open with the SHA-256 of their records; a tampered signature fails at step 10 and a tampered STREAM chunk at step 17, with no download and no file left; an own file opens to OPFS, downloads without a CSP violation and is deleted with its lock; a left over directory goes on the next visit; no request leaves the origin. An adversarial review (four dimensions, each finding checked by a refuter) confirmed 15 findings, all fixed here. 2611 tests; coverage 100 % of the new modules, now a threshold. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
- el cifrado del stanza tlock (`encryptOnG2RFC9380`) y el `Recipient` de `OUTER_TIME_AGE` (`tlock.ts`). Con sigma fijo, el cifrado reproduce byte a byte los vectores de Go. Además Go abre lo que cifra esta librería: el cuerpo IBE con `tlock.TimeUnlock` y el fichero `age` con `agewrap.NewTimeIdentity`;
- la acción "abrir" de `/inspect` (paso 8), cuyo código, con noble y `age-encryption`, se carga bajo demanda:
- el release lo pega quien abre (la respuesta de drand o la firma sola), o sale del registro de un fixture. La página nunca lo pide a la red y solo lee su ronda y su firma;
- las credenciales de `time_and_key` son una `.dkk` o identidades `AGE-SECRET-KEY-1…`;
- el texto en claro de un fichero propio va a un fichero temporal de OPFS que solo se confirma tras el paso 18. Se ofrece para descargar y se borra al pedirlo, con otra cápsula, al salir o en la visita siguiente;
- `readAccessKey` en `prefix.ts`.
- `VERSION` y `SPEC_VERSION`, también en el pie de la página.
Phase 2, step 8: the open action of /inspect After steps 1 to 8, a valid capsule whose date has passed on the device clock can be opened in the page: steps 9 to 18 of spec section 63 with open, loaded on demand with a dynamic import (opener.ts), so noble and age-encryption stay out of the first load of every page. - The release is supplied directly by the person (spec 63, step 10): drand's JSON answer or the bare signature, pasted after opening the drand URL the page links to, or the release in the record of an official fixture. The page never fetches it and reads only its round and signature (spec 11, 13). The CSP is unchanged. - time_and_key credentials: a .dkk (readAccessKey reads at most 12 bytes + 16 MiB + 1) or age identities, one per line. - The plaintext of the person's own file goes to a temporary OPFS file (tempfile.ts), committed only after step 18 (spec 56), offered for download and deleted on request, with another capsule, on pagehide and, if left over, on the next visit. One directory and one Web Lock per tab keep other tabs' clean-up away from files in use. Without OPFS, or when the browser refuses it, capsules up to 64 MiB open in memory. An opening in progress stops when another capsule is loaded. - opening.ts builds the page model of steps 9 to 18 as the reference records them; fixtures show their plaintext and compare its SHA-256 with their record. - licenses.txt: the notices of tlock-js (ibe.ts) and age (bech32.ts), the license of every package in the client bundle, Vite's and rolldown's runtime code, and the site's own license. check-build now fails if a notice is missing, or if a page loads noble, @scure/base or age-encryption with its first load. - The home page no longer says that the page never asks for keys. Checked in the browser on the production build: the time_only, time_and_key_portable (with its .dkk) and time_and_key_recipients (with a pasted identity) fixtures open with the SHA-256 of their records; a tampered signature fails at step 10 and a tampered STREAM chunk at step 17, with no download and no file left; an own file opens to OPFS, downloads without a CSP violation and is deleted with its lock; a left over directory goes on the next visit; no request leaves the origin. An adversarial review (four dimensions, each finding checked by a refuter) confirmed 15 findings, all fixed here. 2611 tests; coverage 100 % of the new modules, now a threshold. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
- `licenses.txt` en el sitio, con los avisos de `tlock-js` y `age` y los de cada paquete del bundle.

Powered by TurnKey Linux.