53 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 explica qué cubre cada número.
0.5.0 — sin publicar
Las palabras al azar de la llave de palabras (07-10-2026)
El SHOULD de §38.1, ofrecer palabras al azar de una lista pública, como hace datekeys encrypt -new-words desde c49c67c de datekeys-go. No cambia ningún formato ni la derivación.
- Las listas de
datekeys-go.scripts/sync-testdata.mjscopia del mismo commitwordkey/listsenwordlists/, con suSOURCE.json, ycheckcomprueba las dos copias.testdataywordlistsestán en27a75eededatekeys-go, de la ramav0.15después del tagspec-v0.15: los ficheros detestdatason los del tag, ywordliststrae la lista española, de 7 776 palabras, un borrador aún sin revisar, con licencia CC BY-SA 4.0. wordlist.ts, comowordkey.Generate,CheckListyBitsde Go en27a75ee, con sus textos:generateWordssortea palabras distintas, 7 por defecto, concrypto.getRandomValues;wordBitsda su fuerza, 90 bits para 7 de 7 776;checkWordListrechaza una lista de menos de 2 048 palabras, con dos que son una al normalizarlas o con un carácter que no es una letra del alfabeto de su idioma, que da el código y no la lista (paraes, de laaa laz,á,é,í,ó,ú,üyñ); yreadWordListsolo acepta una lista con el SHA-256 fijado para su idioma, que sea UTF-8 y quecheckWordListacepte.wordkey.tsganawordRules, que carga una vez las tablas de Unicode para quien lee muchas palabras.- La página
/createofrece palabras al azar por defecto. Con la política «con llave», una casilla abre la cápsula también con unas palabras: al marcarla, la página descarga del propio sitio la lista española (create-words.ts, el fichero que Vite publica con un nombre con hash), la acepta solo con su SHA-256 fijado, y sortea 7 palabras que no salen del navegador. Las muestra numeradas, con su fuerza calculada con la lista cargada y un botón para sacar otras. «Las elijo yo» deja escribir las propias, con el aviso de que son más débiles. En los dos casos hay que escribirlas otra vez para comprobar que se tienen; dan igual mayúsculas y tildes.planCapsulerecibewordsKind(none,randomuown) y pide las palabras que falten. - Corregido en
/create: el efecto que comprueba las rutas escribíapathChecky lo volvía a leer, así que Svelte lo relanzaba sin fin en cuanto se cargaban las reglas, con el primer fichero, comentario o autor:effect_update_depth_exceededen la consola ycheckPathsrepetido sobre toda la lista. Lo lee ahora de una variable local. Venía de7dc88ef(1 de octubre) y está en la0.4.0. - La lista inglesa.
testdataywordlistspasan ae671032dedatekeys-go, con el mismotestdata:wordlists/en.txtes la lista grande de la EFF, de 7 776 palabras, CC BY 4.0, en su orden y sin los números de los dados.WORD_LIST_SHA256fija su SHA-256, y el alfabeto deenes de laaa lazy el guion de sus cuatro palabras compuestas, comot-shirt./createsigue ofreciendo la española, ycheck-build.mjsexige que la página publique solo esa. - Los dados, para quien no se fía del azar del ordenador, como
dice.godedatekeys-goen92e7154, con sus textos: cinco dados por palabra dan un número del 11111 al 66666, la posición de la palabra en una lista de 7 776.wordlist.tsganaDICE_LIST_SIZE,diceNumber,diceWord,diceWordsydiceList, la lista numerada como la publica la EFF (la deenes su fichero, byte a byte), ywordkey.ts,goFields, que separa por espacios comostrings.Fieldsde Go. En/create, «Con dados» convierte los números en palabras a medida que se escriben, avisa de un número que no vale o de una palabra repetida, y ofrece la lista numerada para imprimirla, con su SHA-256;planCapsulerecibediceydiceList, yreadDicelee los números uno a uno.testdataywordlistspasan a92e7154, cuyoREADME.mdde las listas recoge el SHA-256 de cada lista numerada. - Lo que dice el SDK oficial al sellar, como
aefc8f6dedatekeys-go(§7.6, §62.1 reglas 26 y 27, §71).sync-testdata.mjscopia tambiénannex/de Go, el anexo de recuperación (§79 bajo un título con la versión y el SHA-256 de la especificación), ytestdata,wordlistsyannexpasan aaefc8f6. En/create: con una fecha a más de un año y «solo fecha», la recomendación de la llave; tras crear la cápsula, «Para abrirla más adelante», con lo que hará falta y la descarga de las instrucciones para abrirla sin DateKeys,<cápsula>.recuperacion.txt(annex.ts); ycheck-build.mjsexige el anexo byte a byte.profile.tsganaProfileStatus,PROFILE_STATUSyprofileStatusOf, comoStatusOfde Go: Quicknet está activo;planCapsuleno escribe con un perfil que no lo esté, y/inspectavisa si el de una cápsula está comprometido (buildReportrecibeprofileStatus). licenses.txtlleva elREADME.mddewordlists/, con el origen, el método y la licencia de la lista (CC BY-SA 4.0), ycheck-build.mjsexige que esté y que la lista se publique byte a byte.
0.4.0 — 7 de octubre de 2026
La especificación 0.15, el tag spec-v0.15 de datekeys-go: la recuperación a largo plazo, con el objeto release, los archivos de releases y el release en la mano. El autor la cerró el 7 de octubre de 2026, con el tag v0.4.0.
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_VERSIONpasa a0.15y la versión a0.4.0-dev.testdatase sincroniza con el tagspec-v0.15dedatekeys-go(fe50885), que añadevectors/release.json, los ficheros dereleases/y el camposourcedemutations.json.- El objeto release (§47.1).
releaseobject.ts, sin noble, hace lo deprovider/release.goyprovider/archive.gode Go, con sus textos byte a byte:encodeReleaseydecodeRelease, 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 leeencoding/jsonde Go, conERR_RELEASE_INVALIDpara cualquier fallo;ReleaseSupplieryencodedRelease, el release en la mano; yReleaseArchive, el archivo de releases local, formato informativo (§50), cuyos fallos sonERR_RELEASE_UNAVAILABLE, también una ronda a ceros. - La cadena en el paso 10.
verifyReleasecompara 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.
openaceptarelease, un release en la mano, en lugar desource: no se compara con el reloj,Opened.clockBehinddice 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 deround_time, como antes. El release verificado lleva la cadena del perfil fijado. - Las pruebas.
vectors.test.tscorrerelease.jsonentero, con los textos de Go, y cada fichero dereleases/, que la guarda detestdataexige. El corpus de mutaciones leesourcey da a cada caso su clase de fuente, comosingleSourcede Go.scripts/mutation-go-texts.gohace lo mismo, ytesting/mutation-texts.jsonse regenera con Go: cambian el campospec, «round not reached yet», que ahora abre, y los cuatro casos nuevos, con los textos que explica la v0.15. Los demás ficheros detesting/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 aopencomo 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-golo cierra con el tagspec-v0.14(39b2033).SPEC_VERSIONpasa a0.14,testdatase sincroniza con ese tag, ytesting/mutation-texts.jsonse regenera con Go: solo cambia su campospec. Ningún otro fichero detesting/generado con Go lleva ese campo ni depende de un perfil de otro scheme; los veredictos debls12381-vectors.jsonsalen idénticos con Go en39b2033, y solo se corrige su descripción. - Un solo scheme de drand (decisión 8).
validateProfile, y con elladecodeProfile, admite solobls-unchained-g1-rfc9380, con la clave pública en G2, comovalidateDrandde Go desdec041fa3: un nombre que drand no conoce sigue siendo «is not a drand scheme», y cualquier otro scheme de drand,pedersen-bls-unchainedybls-unchained-on-g1incluidos, falla conERR_UNKNOWN_PROFILEy el texto de Go, byte a byte, antes de mirar la clave y elchain_hash. Ningún perfil fijado ni ninguna cápsula válida cambian. tlock_steps.json. Un bloque nuevo devectors.test.tslee 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 detestdatalo exige.ibe.tsexporta para elloh3Base,h3TryyhashToG1, queh3, el cifrado yrelease.tsusan ahora;index.tsno los exporta.- El comentario de
h3decí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:
El localizador sellado, comprobado antes de la fecha (06-10-2026)
parseInfocomprueba el localizador sellado comoParseInfode Go desde69dbb0c, 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 cabeceraagelleve un texto de 4096 bytes o un múltiplo, así que una cabecera sin cuerpo se rechaza. Cada caso esERR_EXTENSION_DATA_INVALIDcon el texto de Go.infoExtensionrechaza 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-golo cierra con el tagspec-v0.13(913dd60).SPEC_VERSIONpasa a0.13,testdatase sincroniza con ese tag, ytesting/mutation-texts.jsonse regenera con Go: solo cambia el campospecde 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 endatekeys-godesdee801e03:isCidV1rechaza 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.jsonylocator-vectors.jsonse regeneran conscripts/locator-go-vectors.gosobre 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)
/inspectmuestra 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, comoshowNotede la CLI de Go. Una nota que no cumple las reglas de texto no se muestra, y la página lo dice.buildReportlleva la nota enReport.note, con su prueba. Comprobado en el navegador con el fixtureformat3_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».
unexpectedProblemdeformat.tslo 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/inspecty la creación en/create. - El servidor de desarrollo ya no recarga la página al abrir.
vite.config.tshace 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.tscomprueba que la lista está completa. La versión compilada no tenía el problema.
NAT64, del borrador v0.13 (06-10-2026)
testdatase sincroniza condatekeys-goena83b44d, el borrador v0.13, sin aprobar: añadevectors/resolved_ip.json, y ningún otro fichero cambia.SPEC_VERSIONsigue en0.12.checkResolvedIpcuenta una dirección de NAT64 a la que resuelve un nombre, de64:ff9b::/96o del prefijo de la red (el parámetronat64), por la IPv4 que lleva dentro, con los textos delocator.CheckResolvedIPde Go.ipaddr.tsexportaisIpv4In6. Un bloque nuevo devectors.test.tscorre los 42 casos.
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_signde TweetNaCl, como el port de Dart, con el SHA-512 de@noble/hashes. Aritmética exacta enFloat64Array, y los secretos nunca enBigInt. JavaScript no promete tiempo constante ni borrar la memoria, y el código lo dice. -
authorkey.ts, el paqueteauthorkeyde Go:AuthorKey(generatecon una fuente de azar inyectable,fromSeed,publicKey,sign,clear,secrety untoStringque oculta el secreto),authorPublicString,parseAuthorPublic,parseAuthorSecret,marshalAuthorKey,encryptAuthorKeyyreadAuthorKey, con los textos de error de Go byte a byte, también los deage, también los números al revés del dePublicString. Las cadenas se leen como bytes, con las mayúsculas, las minúsculas y los espacios del paqueteunicodede Go, quegounicode.tstrae 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 debufio.Scanner. -
El escritor.
encryptFilesganaauthorKey(alg1),cmsSigner(alg2) ysealer(seal_type2), que pueden ser asíncronos, ylargeArea. 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, comosecurityde Go. Un área que crece a 64 KiB cuenta en el límite de memoria.security.tsescribe el área con firma y sello, ysecuritycms.ts,SIGNERS. -
Interoperabilidad con Go, en dos ficheros congelados de
testing/:authorkey-vectors.json, descripts/authorkey-go-vectors.go: 234 firmas, la reducción de escalares, 24 claves,Generatey el fichero cifrado con los valores al azar de Go, queencryptAuthorKeyreproduce 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, descripts/signing-go-vectors_test.goen una exportación despec-v0.12: con los valores al azar y las firmas de Go,encryptFilesescribe 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 escribescripts/signing-ts-samples.mjscon esta librería, sus certificados y su azar, con los mismos veredictos y las mismas líneas.
-
Guardas.
dependencies.test.tsdeja importar noble aauthorkey.tsyed25519sign.ts, yage-encryptionaauthorkey.ts, y no deja queindex.tslos reexporte.check-build.mjsfalla si una página carga las claves de autor con la página, o si/inspectpuede cargarlas.authorkey.ts,ed25519sign.tsygounicode.tsquedan al 100 % de cobertura. -
Pruebas.
npm run verifypasa con 7 904; una más, la de un área que crece y ya no cabe en memoria, lee 1 GiB y corre conDATEKEYS_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. Ycheck-build.mjsdetecta 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 conrebase, con conflictos solo en las guardas, envitest.config.ts, en el README y aquí. Con las tres partes,npm run verifypasa 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 (parseInfoeinfoExtension);standardExtensions, el registro de las extensiones de la especificación, que por defecto comprueba los datos dedatekeys.capsulecomolocator.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 dedatekeys-dart, que hoy rechaza64: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.tslee y escribe ficherosagecomofilippo.io/age1.3.2, con sus textos, porquelocator.OpenyOpenEnvelopelos copian. Sin dependencias nuevas: usa los módulos de noble que ya usax25519.ts, y HMAC es el HKDF-Extract de@noble/hashes/hkdf.js. -
Nada entra en
/inspect.index.tsno reexporta el localizador: la nota trae las tablas de Unicode, y el sobre, noble.dependencies.test.tsañadeageio.tsa los que pueden importar noble y los cuatro módulos a los queindex.tsno reexporta, ycheck-build.mjsfalla si una página carga el localizador con su primera carga. -
Contra Go, todo con el resultado y el texto de Go:
vectors.test.tscorre enterotestdata/vectors/locator.json, en vez de mirar solo su campospec;testing/locator-uris.jsonytesting/locator-vectors.json, descripts/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.dkkllevadatekeys.capsule, y las 20 585 bases del relleno de −4 100 a 16 484;testing/locator-seal.json, descripts/locator-seal-go-vectors.go: con la misma semilla,sealynewEnvelopesacan 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.mjsyscripts/locator-go-verdicts.go), de 0 bytes a 16 MiB y un byte.
Los generadores son los de
datekeys-dartcon las semillas de este repositorio, y corren en una exportación dedatekeys-goenspec-v0.12. -
Lo que el autor tiene pendiente se queda como en Go: un CID no canónico pasa,
https://[[2000::]/pasa,parseInfocomprueba menos de lo que podría yopenSealedlee 1 MiB. -
Pruebas.
locator.test.ts,envelope.test.tsylocator.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-golo cierra con el tagspec-v0.12(fe405e2).SPEC_VERSIONpasa a0.12, ytestdatase sincroniza con ese tag: solo cambia el campospecde cada fichero. testing/mutation-texts.jsonse regenera conscripts/mutation-go-texts.go: solo cambia su campospec.- La librería ya seguía el borrador: no cambia nada más.
npm run verifypasa con 7 832 pruebas.
Los vectores compartidos de la llave de palabras (06-10-2026)
testdatase sincroniza condatekeys-goen084728d, que añadevectors/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.tslos 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)
testdatase sincroniza con la cabeza de la ramav0.12dedatekeys-go(601e6d2);SPEC_VERSIONsigue en0.11hasta que el autor apruebe el borrador. Trae:- los fixtures
format3_unsigned, el contenido deformat3_signedsin firma y con la misma P, yformat3_note, con nota pública; format3_seal_unsupportedconseal_type4294967295;note.json,security.jsoncon su contexto y sus líneas, los 135 casos desecurity_cms.jsony los 218 demutations.json, 178 de ellos del §64.
- los fixtures
- Los vectores de Go.
mutation-texts.jsonse regenera conscripts/mutation-go-texts.go: cambian solo los ocho casos nuevos y el nombre del deseal_type.ibe-vectors.jsongana las entradas deformat3_note,format3_unsignedy elformat3_seal_unsupportednuevo, sin tocar sus valores congelados. - La regla de los codificadores del §72,
checkWriteenextension.ts, conNOTE_IDyCAPSULE_ID, comoextension.CheckWritede Go:- el escritor de cápsulas rechaza
datekeys.notefuera del array no crítico de la cabecera o con datos que incumplen sus reglas, ydatekeys.capsuleen una cápsula; - el de
.dkkrechaza una nota, ydatekeys.capsulefuera de su array no crítico o sin datos; - los textos de error son los de Go.
- el escritor de cápsulas rechaza
- La nota pública.
checkNoteDatacomprueba los bytes de una nota en el orden de Go, yunusableNotedistingue una nota inservible de ninguna.inspectlee la nota bajo demanda, solo si la cabecera lleva una, y la vista deinspect -jsondapublic_noteypublic_note_unusable, como la CLI de Go. Por eso/inspectsigue sin cargar las tablas de Unicode. - Pruebas.
note.json, y el bloque demutations.jsoncon 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
subjectKeyIdentifierno vacío. Uno que lo incumple no decide nada salvo que lo nombre unSignerInfo, 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 sugivenNamey susurnameantes que sucommonName, que puede llevar el NIF, y el emisor, sucommonNameo suorganizationName, 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
messageImprintde otra longitud da S3, loscrlsde un token no deciden nada, y los milisegundos y microsegundos deaccuracyson INTEGER mínimos.der.tscomprueba 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.tsysecuritycms.test.tsportan las deinternal/cms,internal/derysignature2_test.go, y la del emisor sincommonNameya no lo compara consigo mismo.vectors.test.tsleesecurity.jsoncon su contexto y sus líneas, y compara en cada caso desecurity_cms.jsonlos veredictos, los firmantes exigidos y los ajenos, el sello y las líneas. - Diferencial con Go.
capsule.EvaluateSecurityInyVerdicts.Linesde601e6d2dan lo mismo queevaluateSecurityyverdictLines, 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,0x04y las dos coordenadas, como enx509.ParsePKIXPublicKey: con el punto comprimido, un firmante es «no verificable» (F5) y un sello da S1. UnUTF8Stringy 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.
oidOfeintOfleen 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. evaluateSecuritynunca 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.tsde 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 deder.test.tsfallaba por la longitud, y ahora prueba la frontera de 32 niveles. - La nota pública.
checkNoterechaza 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.publicNoteconserva un U+FEFF inicial, que la deja inservible como en Go. También lo conservanauthorCodey 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.
testVectorsyareaLensalen 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
TestVectorsdel núcleo, que solo pasan los ayudantes detesting/encrypt.ts:encryptVectors,encryptWithyencryptFilesWith. encryptconserva la forma decapsule.Encrypt: sin generador, falla con su texto.dependencies.test.tsycheck-build.mjsdejantesting/fuera de la librería y de las páginas.
- Lo que solo pide un generador de vectores es el argumento
- Las opciones, como en Go. Como generador,
encryptrechaza la nota y el área con el texto decapsule.Encrypt. Los errores de la nota llevancapsule:, y las opciones se comprueban en el orden denewSealer. - El tamaño con nota.
capsuleLengthacepta la nota pública y predice exactamente el tamaño del.dkccon ella. - Interoperabilidad.
capsule-vectors.jsonse 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 conHeader.PublicNote. El fichero gana el texto decapsule.Encryptpara una nota en el formato 2, y los decapsule.EncryptFilespara nueve notas inválidas. - Documentación. El README completa la tabla de módulos (
author.ts,ed25519strict.ts,der.ts,cms.ts,securitycms.tsynote.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 sinalg. - 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.tsque lo compara consigo mismo.
testdata en spec-v0.11 (01-10-2026)
testdatase sincroniza con el tagspec-v0.11dedatekeys-go(ae33434), ySPEC_VERSIONpasa a0.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.jsonylocator.json). El corpus de mutaciones pasa a 210 casos, con uno fuera del §64: una firma dealg1 que no verifica, F2.ibe-vectors.jsonañade los tres fixtures y rehace los deformat3_signature_unsupportedyformat3_seal_unsupported;mutation-texts.jsonse rehace con elcapsule.Opende esa referencia.- La firma de clave propia,
alg1 (§29.8, §29.9), portada:ed25519strict.tscomprueba 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 deed25519_strict.json;author.tscalculapayload_commit,control_commit,head_digest,signers_digest,AUTHOR_MESSAGEy su código, y los registros deformat3_signedlos confirman.evaluateSecurity(área, contexto)da F2, F3 y F4,openpasa el contexto del control y del head, yOpenOptions.authorKeysson las claves que la persona guardó. Los dos módulos usan solo@noble/curvesy@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,
alg2, y el sello RFC 3161,seal_type2 (§29.10, §29.11), portados sin dependencias nuevas:der.tscomprueba el DER byte a byte,cms.tslee la firma CMS y el token con la tabla cerrada de algoritmos (RSA PKCS #1 y PSS enBigInt, síncrono, y ECDSA con la aritmética de@noble/curves) ysecuritycms.tsda F1, F2, F5 y F6 con los firmantes nombrados, y S1 a S5 con la autoridad del sello.evaluateSecuritylos devuelve con sudetail,verdictLinesescribe las líneas de F6 y S4, yopenpasa la hora de la ronda. Reproducen los 22 casos desecurity_cms.json, con los resultados de cada firmante, y los fixturesformat3_signed_cmsyformat3_sealed.testing/cmsbuild.tsconstruye firmas y tokens de prueba con WebCrypto, ycms.test.tsporta los casos hostiles de Go. - El escritor de la v0.11 (§29.2, §24.1, §62.1 regla 13):
encryptFilesescribe el área de seguridad de 32 KiB (AREA_LENpasa de 512 a 32768) y aceptapublicNote, la extensióndatekeys.notede 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, contestVectorsyareaLen, y así los tests reproducen byte a byte los fixtures que escribió un escritor de la v0.10, de 512 bytes.lengths.tsy 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 (
alg1,alg2 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óndatekeys.capsulede la.dkk, su sobre y su relleno) y la página de firma.locator.jsonsolo se comprueba en su estructura.
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 depathrule.ts, no con la de la plataforma; cuentan solo las distintas de 3 letras o más; y se rechazan los caracteres invisibles.encryptFilesrecibe las palabras (words) y deriva la llave al sortear elcapsule_id./createpide 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 asrc/lib/dkc/wordkey.ts. /inspectpide 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 deagemá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
ageen 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 unTypeError. - El sitio es siempre claro.
/createse 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. /inspectmarca 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
.dkcantes de escribir, con los ficheros medidos una vez (measureFiles,headLengthOfybodyLengthOfenlengths.ts), y el progreso de las dos lecturas deencryptFiles. create-files.ts(la lista, sin tablas) ycreate-check.ts(las reglas en español, bajo demanda), al 100 %. Go abre una cápsula de la página, y/inspecttambié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) yopener.ts(OpenedFiles, la falta de espacio), cargados bajo demanda;ZipSinkcomprueba el espacio al empezar.check-build.mjsexige que las tablas de las rutas no entren en la primera carga de ninguna página.
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.zipOfhace el mismo ZIP en memoria.tempfile.ts: elwritablede un fichero temporal acepta trozos con posición (TempChunk), comoFileSystemWritableFileStream.- Interoperabilidad:
archive/zipde 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, descripts/zip-ts-samples.mjsyscripts/zip-go-read.go).
Paso 4: la escritura del formato 3
writer.tsse parte como el writer de Go:newSealercomprueba las opciones que no dependen del contenido, ysealescribe la cápsula de un formato alrededor de un contenido dado en trozos. El formato 2 no cambia.encryptFiles(files, opts)escribe un.dkcde formato 3 con sus ficheros, el comentario y el autor declarado, y las extensiones del head, comocapsule.EncryptFiles: lee cada fichero dos veces y falla, con el texto de Go, si cambió entre las dos lecturas.fileSourcehace la fuente de unFile. Los sorteos ganan la sal del head.lengths.ts:bodyLength,headLength,mtimeSecondsyheadComment, para dar el tamaño exacto del.dkcantes de escribirlo.encryptescribe el formato 2 solo contestVectors, y sin comentario, autor ni extensiones del head, con los textos decapsule.Encrypt; las pruebas,encryptWithy los scripts de muestras lo piden./createescribe el formato 3 conencryptFiles: el fichero va bajo su nombre y con su fecha de modificación, y el plan da el tamaño exacto conbodyLength.- Interoperabilidad:
capsule-vectors.jsonse regenera con seis cápsulas de formato 3 escritas porencryptFiles, que Go abre en unSinkcon cada credencial, con los mismos ficheros, head y veredictos; las trece de formato 2 y los demás bloques se regeneran igual. - Pruebas: los cinco fixtures que escribió
EncryptFiles, byte a byte; los tamaños frente a lo escrito y 300 heads aleatorios frente aencodeHead; y las entradas inválidas, con los textos que dacapsule.EncryptFilesa las mismas entradas.
Paso 3: la lectura del formato 3, con testdata en spec-v0.10
testdatase sincroniza con el tagspec-v0.10dedatekeys-go(cc35d2c), ySPEC_VERSIONpasa a0.10.framing.ts:FORMAT_3, eisPaddedpara los formatos 2 y 3.control.ts: la versión de schema 3, con las claves 6 y 7 de la 2.open.tsyopen3.ts: el paso 17 del formato 3 en sus subpasos, con la precedencia y los textos decapsule.Open. Los ficheros van aOpenOptions.sink(sink.ts:SinkyMemorySink), que solo los publica en el paso 18; sin sumidero,openrechaza con unTypeErrorjusto tras el paso 2.Openedganahead,verdicts,areaLenyunusableHeadExtensions.- La página:
opener.tsabre 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 conscripts/mutation-go-texts.goentesting/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.jsongana los nueve fixtures nuevos. check-build.mjsimpide 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.tsyhead.ts, comocapsule/format3.go: la trama deBODY, los veredictos del área de seguridad con sus textos, y el head con las capas de §69.1.ERR_HEAD_INVALIDes 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 pordatekeys-gocon Unicode 18.0.0 y WindowsBestFit, ypathrule.ts, las reglas de las rutas y de los textos del head con los textos de error de Go.crc32.tsyzip.ts, ensrc/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.
Después del paso 7: ayuda de age y el texto en claro a la vista
/inspectmuestra 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.tsda esos primeros bytes (PREVIEW_BYTES), yopening.tsdecide qué se muestra (plaintextPreview).- Ayuda de las claves de
age. En/create, un bloque plegable explica qué es un destinatarioage1…y cómo se consigue conage-keygen. En/inspect, el campo de identidades dice qué pegar: la líneaAGE-SECRET-KEY-1…del fichero deage-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,.jpgy otras por sus primeros bytes. La cápsula no guarda el nombre del fichero (§6, §55.2). vite previewsirve las páginas conCache-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
- El autor confirma las decisiones de la página con cada recomendación:
time_onlypor 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 nombrescapsula-<apertura en UTC>. /createcifra un fichero propio en un.dkcde formato 2 y, si se pide, en una.dkkportable, en el navegador y sin red. Antes de cifrar muestra el instante efectivo, la ronda, ladk1_, el tamaño exacto del.dkcy lo que deja ver hasta la fecha. El.dkcva a un fichero temporal de OPFS, o a memoria hasta 64 MiB, y la escritura se puede cancelar. La.dkkvive 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:sealedControlLengthsale dewriter.ts, ycapsuleLengthda el tamaño del.dkcantes de escribirlo; el bucle de propiedades lo comprueba en cada cápsula.datekey.ts:LONG_HORIZON_SECONDSeisLongHorizon.localtime.ts,create-input.tsycreator.ts, al 100 %./inspectlimpia también la zona de crear.check-build.mjscomprueba 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
/inspectcon el release pegado y condatekeys decryptde Go, con el mismo contenido. - Una revisión adversarial encontró un fallo mayor y ocho menores, todos corregidos. El mayor: la
.dkkque 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.tscompara 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.tsytesting/capsule-vectors.json: Go abre concapsule.Openlas trece cápsulas de muestra que escribeencrypt, 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.mjsyscripts/capsule-go-verdicts.go, y se congela; el test comprueba en cada ejecución los veredictos de Go y queopenda lo mismo sobre los bytes congelados.
Pasos 3 y 4: el writer
encrypt.tsywriter.ts:encrypt(src, opts)escribe un.dkcde formato 2 y, si se pide, una.dkkportable, comocapsule.Encrypt: L conocida de antemano, rellenoreforzadopor defecto, de 1 a 16 credenciales con señuelos en un orden uniforme,SEALED_CONTROL_LENcon la fórmula del §62.1 y las autocomprobaciones de la regla 11 y dos más. Streaming desdeUint8Array,BloboReadableStream, hacia memoria o hacia unWritableStreamque 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-encryptionsustituido y un bucle de propiedades (50 semillas en cada ejecución; 500 pasaron a mano).
Paso 2: piezas de apoyo
recipient.ts: recipientsage1…comoage1.3.2, las reglas de §37 con los textos deagewrap.CheckX25519Recipienty 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 ficherosageenteros que antes eran privados de la apertura, para compartirlos con el writer.x25519.ts:newX25519Identityyx25519PublicKey, con los vectores de RFC 7748.digest.ts:sha256Hasher.datekey.ts:compareInstants, que usaopen.ts, eisInstant.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.tsy los tests importanage-encryption; soloencrypt.tsytesting/importanwriter.ts;index.tsno reexporta la apertura ni el writer.
0.1.0 — 29 de septiembre de 2026
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); otroVERSIONesERR_UNSUPPORTED_VERSIONen el paso 2.DKC_FRAMING_VERSIONdesaparece:FORMAT_1,FORMAT_2eisFormat. CONTROL_CBORse lee y se escribe para un formato,decodeControl(b, format)yencodeControl(c, format): su versión de schema es la del formato, y en el formato 2 llevapayload_length(8 bytes, hasta L_MAX) ypadding(claves 6 y 7).padding.ts: las reglasbloque256yreforzadode §29.1, exactas hasta L_MAX = 2⁵³ − 2⁴⁶, y la longitud dePAYLOAD_AGE.open: exactamente 16 stanzas enINNER_ACCESS_AGEdel 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.Openeddaformat,payloadLengthy, en el formato 2,paddingypaddedLength.- La vista JSON de
inspectllevaformat, comodatekeys 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.
testdatasincronizado conspec-v0.9: doce fixtures, siete de ellos del formato 2,padding.json, 125 casos de mutación y 4 380 del diferencial.ibe-vectors.jsonañ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_CBORy.dkk. - Tramas DKC1 y DKK1, cabeceras
agey 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-encryption0.3.1,@noble/curvesy@noble/hashes2.4.0) con sus guardas; - 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 deagewrapse apoyan enx25519.ts, que abre cada stanza X25519 por separado, y enbech32.ts. Los 65 casos del corpus de mutaciones pasan poropencon el código y el paso de Go, y los cinco fixtures oficiales se abren a su texto en claro; @noble/ciphers2.4.0 como dependencia directa, aprobada el 28-09-2026: la copia que ya traeage-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 descifraPAYLOAD_AGEen streaming. La salida puede ser unWritableStream, 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. - el cifrado del stanza tlock (
encryptOnG2RFC9380) y elRecipientdeOUTER_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 contlock.TimeUnlocky el ficheroageconagewrap.NewTimeIdentity; - la acción "abrir" de
/inspect(paso 8), cuyo código, con noble yage-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_keyson una.dkko identidadesAGE-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;
readAccessKeyenprefix.ts.
- dependencias de ejecución (
VERSIONySPEC_VERSION, también en el pie de la página.licenses.txten el sitio, con los avisos detlock-jsyagey los de cada paquete del bundle.