18 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.
Especificación 0.10, en la rama v0.10 — sin versión
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
/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.
0.2.0 — sin publicar
Fase 3: la escritura de cápsulas de formato 2, según PLAN_fase3_escritura.md (v3, en ../docs). Hecha, pasos 0 a 7; la versión sigue sin publicar hasta que el autor la cierre.
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.