68 KiB
Historial del handoff de DateKeys
Lo que fue el HANDOFF desde el 26 de septiembre hasta el 6 de octubre de 2026, tal como estaba al reorganizarlo, sin cambios. Lo actual está en el HANDOFF; esto es para buscar por qué se decidió algo, qué hizo cada sesión o en qué commit quedó cada cosa. Los commits que cita siguen en sus repos.
Estado al 6 de octubre por la noche, antes de reorganizar el handoff
Para empezar:
-
Abre la sesión en
G:\bussines\datekeys, la raíz, no enApp. Comprueba que corre en Opus. La memoria buena es la de la raíz. -
Comprueba los repos con
git statusygit log:datekeys-go: ramav0.14ymainen39b2033, con el tagspec-v0.14; las ramasv0.13yv0.12se quedan en sus tags;App: ramav0.10en4e23f88,0.3.0-dev;mainen8cf0685, con el tagv0.2.0;datekeys-dart: ramav0.14en013b069; lasv0.13,v0.12yv0.11se quedan atrás; lav0.11se queda enbb66e48;docs: ramamainen el commit de este handoff.
Si no se subieron al cerrar,
git statuslo dice: todo lo del 6-10 por la tarde y la noche se subió solo con permiso del autor. -
Lo siguiente lo decide el autor. Lo abierto:
- medir el área de 32 KiB con firmas reales: la v0.12 se aprobó sin esa medida.
La app Flutter queda archivada para más adelante, por decisión del autor del 6-10 («la aplicación de Flutter de momento se archiva para un futuro»). La librería Dart está lista para cuando se retome.
La v0.14, aprobada (6-10, noche). El autor dijo «apruebo el borrador, continua», con las diez recomendaciones de spec_v0.14/decisiones.md. La decisión 8 se aplicó antes de cerrar: §12.1 admite solo bls-unchained-g1-rfc9380, y profile.Validate rechaza los otros dos schemes (Go c041fa3, cambio 7 del §76). Cierre como la v0.13: SHA-256 390922135931dd61a263ed90259c7a978b5d92944405e641e94cc194f84fb459, tag spec-v0.14 en 39b2033, main avanzado. TypeScript (4e23f88) y Dart (013b069, rama v0.14), de dos agentes Opus: la 0.14, la decisión 8 con el texto de Go, una prueba que recorre tlock_steps.json y el comentario de H3 corregido. Los tres gates pasan: Go entero, TypeScript con 8 030 pruebas y Dart con 2 193 en la VM y 681 en Node.
Borrador v0.14 (6-10, noche). El autor dijo «sí, empieza por el 1»: el paso 2 de la revisión, escribir lo que falta. Rama v0.14 de datekeys-go, 49b3764, sin aprobar: §5, §7.6, §7.7, §7.10, §36.1, §38.1, §50, §53, §59, §71 y erratas del §76 (de la sesión); y la raíz de confianza byte a byte en §12, §35, §51 y los pasos 10 y 11 del §63, con testdata/vectors/tlock_steps.json (de un agente Opus). Las decisiones, en spec_v0.14/decisiones.md; la 8, los tres schemes de §12.1, es la única que cambia código, y la recomendación es B, solo Quicknet. TypeScript y Dart no cambian hasta la aprobación.
Revisión de completitud contra la v0.13 (6-10, noche). REVISION_completitud_v0.13.md, de un agente Opus: de los ocho puntos de la revisión de la v0.8.2, el escritor está hecho; el versionado, lo que no se garantiza y la firma con la .dkk protegida, en parte; y el riesgo del proveedor, la revisión externa, la raíz de confianza y la recuperación a largo plazo, pendientes. Los tres pasos que propone antes de la v1.0: medir el área y cerrar el perfil CMS, una versión solo de texto que escriba lo que falta, y una revisión criptográfica externa. Para la próxima versión del spec, dos erratas: el título del §76 dice «v0.8.1», y el bloque de la v0.13 va antes que el de la v0.12. FuzzCheckResolvedIP es el objetivo 26 del fuzzing (Go 416c155).
Fuzzing (6-10, noche). FUZZ_PARALLEL=4 scripts/fuzz.sh 60s sobre 69dbb0c, los 25 objetivos, FuzzParseInfo y FuzzCheckURI incluidos: limpio, sin entradas nuevas que fallen.
datekeys-ts 0.2.0 (6-10, noche). El autor dijo «cierra la 0.2.0 y continua». 8cf0685, «Release 0.2.0», con el tag anotado v0.2.0 y main avanzado hasta él sin fusión; después f7cdb5a abre 0.3.0-dev. Cubre la especificación 0.13: lee los formatos 1 a 3 y escribe el 3, con firma, sello, llave de palabras, nota y localizador.
ParseInfo, endurecido (6-10, noche). El autor dijo «deja el 1 MiB y endurece ParseInfo, continua». Sin cambio normativo, porque el §44.1 ya lo pedía: ParseInfo comprueba la cadena del stanza sellado (hexadecimal en minúsculas, y la de Quicknet para una DateKey de Quicknet) y que el cuerpo lleve un texto de 4096 bytes o un múltiplo, así que una cabecera sin cuerpo se rechaza; Info.Extension rechaza una DateKey de un perfil no fijado. Go 69dbb0c, y TypeScript y Dart con sus vectores de Go regenerados. locator.Open sigue leyendo como mucho 1 MiB, por decisión del autor.
La v0.13, aprobada (6-10, noche). El autor dijo «si, lo apruebo continua». Como la v0.12: solo cambia la fecha de la cabecera; SpecVersion 0.13; el campo spec de todo testdata, y a mano en los dos congelados; SHA-256 796f176f51119e287211428496b0d30fd8f941617780c5a5d2954243431fdaaf en spec/README.md y en el tag anotado spec-v0.13 (913dd60); main avanzó hasta él sin fusión. TypeScript y Dart pasan a la 0.13 con testdata en el tag. Los tres gates pasan.
Lo último del 6-10 por la noche. El autor dijo «continua» dos veces:
App2c2a28d: la nota pública en/inspect, debajo del veredicto, con el aviso deshowNotede Go; los errores inesperados de las páginas dicen en español qué hacer (unexpectedProblem), sin el mensaje de la excepción, tras una queja del autor por «Failed to fetch dynamically imported module: http://localhost:5188/…»; yvite.config.tsprepara las dependencias que se cargan bajo demanda, porque el servidor de desarrollo recargaba la página en la primera apertura y la rompía.- El CID no canónico y
https://[[2000::]/ya se rechazan: Goe801e03, Dart450b3f8, TypeScript900700b, con los vectores de Go regenerados. No era una decisión: el §44.1 de la v0.12 ya los rechazaba, y era Go el que no lo cumplía. - El servidor del Gitea: el nombre
g.activething.comresuelve a veces a 89.46.247.16, que no responde; se sube con la URL de la IP de la red local,https://192.168.18.112/go/<repo>.git, sin cambiar el remoto, y se mueve despuésorigin/<rama>congit update-ref. .claude/launch.jsontieneinspector-dev-app, que arrancaApp: la carpeta sigue sin renombrar.
NAT64 y el TypeScript (6-10, noche). El autor dijo «adelante con el NAT64» y «sigues con TypeScript».
-
Borrador v0.13,
datekeys-goramav0.13(a83b44d,e9d4cec), sin aprobar. El §44.1 cuenta una dirección de NAT64 a la que resuelve un nombre, de64:ff9b::/96o del prefijo de la red (RFC 6052, RFC 7050), por la IPv4 que lleva dentro; una dirección de NAT64 escrita en el localizador se sigue rechazando. El prefijo de la red tiene una longitud de RFC 6052 y está en64:ff9b::/16o es público, y una dirección suya cuenta solo por su IPv4 aunque el prefijo sea público: el primer código no lo hacía, y la sesión lo corrigió antes del commit. El §76 tiene el cambio 1 con su caso.locator.CheckResolvedIPytestdata/vectors/resolved_ip.json, 42 casos.SpecVersionsigue en 0.12. -
Dart, rama
v0.13(d65e218,4a0d4f7):checkResolvedIp(ip, nat64:), con los textos de Go. -
TypeScript,
v0.10, de dos agentes Opus en paralelo, revisados e integrados:- el localizador (
0d895bf,e2c51bc): el paquetelocatorde Go entero, con un lector y escritor deagepropio (ageio.ts) para reproducir los textos deagey fijar el azar. 6 531 casos contra Go con el mismo texto, sellado y sobres byte a byte, y Go abre lo que escribe TypeScript; - NAT64 (
28f0c3f), por la sesión; - las claves de autor y la firma al escribir (
96614d5,9e5e3ba,a741efe):authorkey.ts,ed25519sign.ts(firma propia) y los enganchesauthorKey,cmsSigner,sealerylargeAreadel escritor. Ocho cápsulas firmadas y selladas byte a byte como Go, y Go abre las de TypeScript con los mismos veredictos.
Ningún módulo nuevo: todos los de noble y
age-encryptionque importan ya estaban.npm run verifypasa con 8 017 pruebas y una aplazada. - el localizador (
-
Los gates de Go y Dart pasan, con 2 175 pruebas en la VM de Dart y 665 en Node.
La v0.12, aprobada (6-10, tarde). El autor dijo «apruebo el borrador». Se aprobó el texto tal como estaba, sin añadir texto normativo, para no repetir el fallo E1 de la v0.11:
datekeys-gofe405e2: la cabecera del spec dice «6 octubre 2026, aprobado por su autor ese día», y es lo único que cambia del texto.SpecVersion0.12; el campospecde todotestdata, regenerado, y en los congeladossecurity_cms.jsonylocator.json, cambiado a mano, solo ese campo.spec/README.mdregistra el SHA-256,afc31fd8105d650773d093ac01bd2f5e0b56af04726f4e75c652e2cf9308ac3f. Los README,SECURITY.md, la trazabilidad,testdata/README.mdy el CHANGELOG nombran la v0.12.- El tag anotado
spec-v0.12está enfe405e2, ymainavanzó hasta él sin fusión. App45e7e49:SPEC_VERSION0.12,testdataenfe405e2ymutation-texts.jsonregenerado con Go; solo cambia su campospec.datekeys-dart62107d7, en la rama nuevav0.12, como dice el plan:specVersion0.12 ytestdataenfe405e2. Sus vectores detest/vectors/cambian solo el campospec, porque entrec531e93yfe405e2Go solo cambiaSpecVersiony añadewordkey.json.- Los tres gates pasan:
scripts/check.shde Go sin fuzzing,npm run verifycon 7 832 pruebas ytestdata:check, ytool/check.shcon 2 131 pruebas en la VM y 665 en Node.
Los vectores de la llave de palabras (6-10, tarde). El autor pidió «haz los vectores de la llave de palabras», la observación del 5-10:
datekeys-go084728d:testdata/vectors/wordkey.json, que generagenfixturesy compruebaTestVectorFilesAreCurrent. Tiene 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, la primera el vector del §38.1. No es un cambio normativo: el §64 de la v0.11 ya lo pedía.App4031bd1ydatekeys-dartbb66e48:testdatasincronizado en084728d, con una prueba que corre el fichero. Ninguna librería tuvo que cambiar.- Los tres gates pasan:
scripts/check.shde Go sin fuzzing,npm run verifycon 7 832 pruebas ytestdata:check, ytool/check.shcon 2 131 pruebas en la VM y 665 en Node.
Qué hizo la sesión del 6 de octubre por la tarde. Corrió en Opus 5.5, abierta en la raíz. El autor dijo «SI» a la fase 2 de las etapas 6 y 7 de Dart:
- 6b, el escritor del formato 3 (
4c9bc72a6239e30), de un agente Opus en la copia principal: escribe cápsulas byte a byte comoEncryptFilesde Go con los mismos valores al azar, y Go las abre con cada credencial. - 7b, las claves de autor y el sellado del localizador (
3358f5cad77ef9e), de otro agente Opus en un worktree:authorkey, la firma Ed25519 propia, ySealyNewEnvelope, también byte a byte como Go. - Integración: la 7b, encima de la 6b con
rebase. El enganche de la firma dealg1 pasó a llamarseAuthorSigner, y laAuthorKeyde la 7b lo implementa: el escritor firma ya con la clave real. El gate pasa con 2 059 pruebas en la VM y 665 en Node. - Revisión de la sesión contra Go: sin fallos. Los detalles están en PLAN_dart.md, al final.
- Cosas de Go que Dart copia, encontradas por los agentes:
- el texto de
PublicStringdeauthorkeycon una clave de otra longitud tiene los números al revés: «a public key has 32 bytes, not 31»; - el error de una nota pública con un carácter de control habla del «declared author», ya anotado el 5-10;
- un comentario que es solo
\rpasa a\ny se acepta.
- el texto de
La sesión del 5 y 6 de octubre (histórico: lo actual está arriba)
Qué hizo. Corrió en Opus 5.5. Se abrió en App y pasó a la raíz sin cerrarse. Cada parte la hizo un agente Opus, y la sesión la revisó contra Go, la integró y pasó el gate. Ninguna revisión encontró fallos.
datekeys-go:internal/pathrule/gen -dartescribe las tablas de Unicode para Dart. Esc531e93, subido.- Etapas de Dart:
- 2, primitivas y
age; y 3, BLS12-381 y tlock, en paralelo; - 4, en tres partes: 4a, rutas, textos y llave de palabras; 4b, formatos; 4c, head, nota, inspección y apertura de los formatos 1 a 3;
- 5, en tres partes: 5a, lector CMS, ECDSA y RSA; 5b,
testdataen la v0.12, compromisos,SECURITY_CBOR,alg1 y veredictos; 5c,alg2 yseal_type2; - 6a, el escritor de
age; - 7a, el localizador y el sobre, sin el sellado.
- 2, primitivas y
- Resultado: la librería Dart inspecciona y abre cápsulas de los formatos 1 a 3, también grandes y en streaming, con todas sus credenciales; evalúa la firma y el sello como Go; escribe ficheros
age, y Go los abre; y valida localizadores. El gate pasa con 1 713 pruebas en la VM y 432 en Node. - Decisiones del autor:
- el cifrado tlock queda en
BigInt, sin tiempo constante, y está documentado («continúa», 6-10); - los repos
datekeys-dartydocstienen remoto desde el 6-10; - G: tiene 26 GB libres, porque el autor liberó unos 24 GB.
- el cifrado tlock queda en
Decisiones pendientes del autor, encontradas el 6-10 al portar el localizador. Todas afectan a Go, y Dart copia hoy su comportamiento:
- Un CID no canónico pasa. El §44.1 de la v0.12 pide el CID en su forma canónica, pero
isCIDv1solo mira que los bits sobrantes sean cero, no cuántos hay: un CID válido con unaade más se acepta. Arreglarlo es tocar Go, con un vector nuevo, y después el Dart. https://[[2000::]/se acepta, por elstrings.Trim(host, "[]")de Go.- NAT64 en móviles. En redes móviles solo IPv6, un host solo IPv4 resuelve a
64:ff9b::/96, que el §44.1 rechaza, así que la app no podría descargar de él. Es una cuestión del spec, y el README dedatekeys-dartla anota. ParseInfocomprueba menos de lo que podría: no mira la cadena del stanza sellado, acepta una cabeceraagesin cuerpo, eInfo.Extensionno comprueba que el perfil esté pinneado.locator.Opensolo lee 1 MiB del localizador. Un defecto posterior queda oculto tras el error deUnmarshal. Es así por diseño, pero conviene saberlo.
Lo demás abierto:
- la aprobación del borrador v0.12 y la medida del área de 32 KiB, que el autor dejó para luego;
- el TypeScript sin urgencia: el localizador, la nota en la página y cerrar
0.2.0; - las observaciones del 5-10, más abajo;
- medir en un móvil de gama media, cuando haya app: BLS12-381, PBKDF2, scrypt y la apertura;
- reportar al equipo de Dart el posible fallo de dart2js de Dart 3.13 que encontró la 4c, solo con permiso del autor. Está documentado en el README de
datekeys-dart; websigue sin remoto.
Para trabajar:
- Encargos a agentes:
- en un worktree junto a los repos, para que
../datekeys-godetool/check.shresuelva; - nunca dos agentes en los mismos ficheros;
- los subagentes, con
model: "opus"; - el scratchpad es compartido: que nadie borre con comodines.
- en un worktree junto a los repos, para que
- Generadores de vectores: los de Go que necesitan paquetes
internal/corren en una exportacióngit archivededatekeys-go, sin tocarlo. - Bash:
cdmueve el directorio de la sesión. Usa( cd … && … )ogit -C.
Estado al cerrar la primera sesión del 5 de octubre (histórico: lo actual está arriba)
Para empezar la sesión siguiente. La del 5-10 se cerró porque tenía el contexto casi lleno.
- Abre la sesión en
G:\bussines\datekeys, la raíz, no enApp, y comprueba que corre en Opus. - Comprueba que los repos están como dice este apartado (
git statusygit logen cada uno). Todos estaban limpios al cerrar:datekeys-go: ramav0.12en424cdf3, subida;App: ramav0.10en289fe71, subida;datekeys-dart: ramav0.11enc8bf3c0, solo en local;docs: en el commit de este handoff, solo en local.
- Dart, etapa 2. Se encargó a un agente y se detuvo antes de que escribiera nada en el repo. Hay que relanzarla con el encargo de PLAN_dart.md, apartado «Cómo se hacen las etapas», revisar su resultado y pasar
tool/check.sh. - Dart, etapa 3, BLS12-381 y tlock: el autor la pidió el 5-10 para después de la 2.
Qué pasó. Una sesión en Opus, abierta otra vez en App, hizo los puntos 2, 3 y 4 de la lista del 2-10: lo que faltaba de Go, la segunda parte del TypeScript y las etapas 0 y 1 de Dart. El autor decidió además una ampliación del borrador v0.12. El trabajo grande se repartió entre agentes Opus en worktrees y repos aparte, y cada resultado se revisó e integró en la sesión.
datekeys-go, rama v0.12, subida:
-
da9fd2c: arreglo editorial del borrador. Faltaba una línea en blanco antes de cinco---, y dos párrafos, el final del §70 y el del §72, se veían como títulos. La v0.11 etiquetada tiene el mismo fallo y no se toca. -
ea5c6eb:locator.jsoncon los casos del §64 de la v0.11 y la v0.12:- 217 direcciones: la primera y la última de cada bloque IPv4, con sus vecinas públicas; los bloques IPv6; los nombres locales; los caracteres fuera de RFC 3986; los segmentos
..; y los CID que no decodifican; mixed: un localizador con una direcciónhttpy otra de NAT64, que se rechazan, y una tercera que se usa;rest_cases,extension_cases, con el localizador de otra ronda, yplaintext_cases, con el caso del cambio 7;- las bases de relleno 3837, 4070, 4094 y 4095 y las del múltiplo siguiente: la spec pide ocho, y la lista del 2-10 daba seis.
El generador pasa a
internal/testkit/genfixtures/locatorvectors.goy comprueba cada caso contra Go. - 217 direcciones: la primera y la última de cada bloque IPv4, con sus vecinas públicas; los bloques IPv6; los nombres locales; los caracteres fuera de RFC 3986; los segmentos
-
e22d358:testdata/README.mdal día, y sin marcas pending endocs/traceability.mdni en el CHANGELOG. El README decía que el release de la ronda 1000 estaba enquicknet_rounds.json, y no estaba. -
601e6d2, con la decisión del autor del 5-10 («sí, aplícalo así»): el §44.1 escribe lo que Go ya rechazaba y el texto no decía, y el cambio 6 del §76 y el §64 lo recogen:- segmentos de 1 a 63 caracteres, sin guion en los extremos;
- el esquema en minúsculas, y
0xy los nombres locales sin distinguir mayúsculas; - IPv4 sin ceros a la izquierda y CID en su forma canónica;
- el puerto sin ceros a la izquierda: Go aceptaba
:0443y:00443, ycheckPortahora los rechaza.
locator.jsonpasa a 247 direcciones. -
Verificación:
scripts/check.sh 60scompleto sobree22d358, y sobre601e6d2check.shsin fuzzing yfuzz.sh 60s, los 25 objetivos: todo limpio. Cobertura decapsule, 92,2 %. govulncheck da los dos avisos de siempre, sin llamada alcanzable.
App (datekeys-ts), rama v0.10, subida (fc5fb24..289fe71):
-
997f331: la regla de los codificadores del §72 (checkWriteenextension.ts, conNOTE_IDyCAPSULE_ID), que aplican el escritor de cápsulas y el de.dkkcon los textos de Go;checkNoteDatayunusableNote. Comprobado también contra eltestdatadespec-v0.11. -
95329ee, el borrador v0.12, en un solo commit porque nada pasaba por separado:testdataen601e6d2;SPEC_VERSIONsigue en 0.11;- el lector de certificados campo a campo, los OID por bytes, los SET OF con repetidos y los casos límite: T2, T6, T7, T8 y lo de TypeScript de E7, E8 y E9;
- los textos de los veredictos de la v0.12: E2, E3 y E4;
security.jsony los 135 casos desecurity_cms.json, comparados campo a campo, con sus líneas;- los textos de las 218 mutaciones y los vectores IBE de los fixtures nuevos;
note.json, y la nota pública eninspect, que la lee bajo demanda.
El port del CMS lo hizo un agente: un diferencial suyo de 63 623 áreas no dio ninguna diferencia con Go, y el código anterior difería en 13 296 de 42 986.
-
289fe71: README y CHANGELOG. -
Verificación:
npm run verify(7 759 pruebas, cobertura y build con sus guardas) ytestdata:checkcontra Go.
datekeys-dart, rama v0.11, solo local (no tiene remoto):
-
5aa5eed, etapa 0:- el paquete
datekeys, Dart 3.13, sin publicar; testdataenspec-v0.11, 124 ficheros, con el mismoSOURCE.jsonque escribe el TypeScript;tool/sync_testdata.dart, pruebas de integridad y de versión, ytool/check.shcomo gate;- licencia Apache-2.0;
- dependencias:
cryptoen ejecución ytesten desarrollo, aprobado por el autor el 5-10.
- el paquete
-
da63bc3a10b0895, etapa 1, también de un agente:- errores del §69;
- bytes: UTF-8 estricto propio, porque el
Utf8Decoderde Dart quita un U+FEFF inicial; y el%qde Go con su tablaIsPrint; - el códec CBOR de
codec.go; - el DER de la v0.12.
Los enteros son exactos en la VM y en la web: un
inthasta 2^53 − 1 y unBigIntpor encima. Hay 169 pruebas en la VM y 56 también en Node, y una comparación con Go de 263 611 casos no dio ninguna diferencia.
Siguiente, en orden
-
El autor aprueba el borrador v0.12: §76, cambios 1 a 9, con el 6 ampliado y el 3 precisado el 5-10. Sigue abierto si se mide antes el área de 32 KiB con firmas reales. El 5-10 el autor dejó las dos cosas para más adelante («la aprobación y la medida, luego»). Con la aprobación: el SHA-256 en
spec/README.md,SpecVersion0.12, el tagspec-v0.12ymainavanzado sin fusión, siempre con permiso del autor.Decidido el 5-10 («sí a las dos»):
- «Con texto» en el §29.7: el titular toma
givenNameysurnamesolo si los dos tienen texto no vacío, y el emisor toma elorganizationNamesi no tiene uncommonNamecon texto. Es lo que ya hacían Go y el TypeScript. Está en424cdf3, subido. dart test -p nodeen el gate de Dart:c8bf3c0.
- «Con texto» en el §29.7: el titular toma
-
Dart, etapa 2: las primitivas y
age, según PLAN_dart.md. Se encargó el 5-10 y se detuvo sin escribir nada al cerrar la sesión: hay que relanzarla. -
Dart, etapa 3: BLS12-381 y tlock, pedida por el autor para después de la 2.
-
TypeScript, sin urgencia: el localizador, que aún no está portado; que la página muestre la nota pública, que ya lee
inspect; y lo pendiente del §2.5.
Observaciones del 5-10, sin decisión:
- El error de una nota pública con un tabulador dice «in the declared author», porque la nota usa las reglas del autor declarado. Está en
note.jsony el TypeScript lo copia: cambiarlo exige tocar los dos lados. - Hecho el 6-10:
testdataya tiene los vectores compartidos de la llave de palabras,vectors/wordkey.json. - A G: le quedan 1,5 GB libres.
- Flutter está instalado en
C:\dev\flutter, y su Dart 3.13.0 es eldartdel PATH. - La carpeta sigue llamándose
App, yenquiry.phpsigue en la raíz (§0).
Para trabajar: lo del apartado del 2-10, y además:
- Un worktree en el scratchpad permite trabajar mientras
check.shcorre en la copia principal. - Dos fuzzings a la vez no deben solaparse, porque comparten la caché de fuzzing de
GOCACHE.
Estado al cerrar la sesión del 2 de octubre (histórico: lo actual está arriba)
Qué pasó. La sesión que cerró la v0.11 (1-10, de 19:42 a 01:05) corrió con Sonnet 5.5. El 2-10 se revisó todo lo que hizo con seis revisores de Opus: spec_v0.11/revision_sesion_1_2_octubre.md.
- Resultado: nada bloqueante. El núcleo criptográfico estaba bien.
- Fallos encontrados:
- cómo se puso el tag;
- la paridad entre Go y TypeScript con los certificados;
- unos vectores que cubrían mucho menos de lo que decían;
- la presentación (un nombre de certificado podía imitar una línea de veredicto);
- comprobaciones del escritor que faltaban;
- documentación desfasada.
- Arreglos: casi todos hechos el mismo 2-10. Lo pendiente está abajo.
Decisión aplicada (E1). El tag spec-v0.11 no se toca: es una versión cerrada. Los cambios de texto normativo van a un borrador v0.12 sin aprobar: datekeys-go/spec/DateKeys_Protocol_Specification_v0.12.md, cuyo §76 «Cambios normativos de la v0.12» lista los nueve cambios con su caso.
Repositorios
datekeys-go: la ramav0.12, subida, implementa el borrador v0.12.mainy el tagspec-v0.11siguen enae33434, sin tocar, ySpecVersionsigue en 0.11 hasta la aprobación.App(datekeys-ts): la ramav0.10, subida, con cinco commits nuevos (06e992fafc5fb24). Sutestdatasigue sincronizado conae33434(spec-v0.11).docs: local. La revisión está end60b856, los planes de Dart y de la firma enac47bf6, y este handoff en el commit siguiente.
Hecho el 2-10 en Go (rama v0.12)
- Claves de autor, escritor, CLI, extensiones y localizador (
fee531b):Key.String()oculta la clave secreta, yParsePublicexige un punto de la curva;- un nil con tipo da error;
- un pánico al evaluar la firma o el sello solo afecta a su parte (F1 o S2);
OpenOptions.Accept;extension.CheckWrite, la regla del encoder del §72;- en la CLI,
encrypt -signmuestra el código;-expect-authorno escribe nada si la clave no coincide; las líneas de veredicto se parten con↳; y se avisa de una nota inutilizable; - en el localizador, las direcciones no públicas de IANA y los nombres locales se rechazan, se descarta una dirección mala sin perder las demás, y
ParseInfoata el localizador a su ronda.
- Lector CMS (
839e117,b06ab4f):- un perfil de certificado propio, campo a campo, sin
encoding/asn1nicrypto/x509; - los OID se comparan por sus bytes, y un SET OF puede repetir elementos;
- una clave que no casa con su algoritmo es F2, y un imprint de otra longitud es S3;
- los tiempos DER se comprueban, y NumericString y los demás tipos de cadena son DER válido;
- el titular sale de
givenNameysurname, delante del CN que lleva el NIF.
- un perfil de certificado propio, campo a campo, sin
- Borrador v0.12 y textos de los veredictos (
840c87e):- los nombres de certificado van entre «», con 64 puntos de código como máximo y sin espacios dobles;
- la línea de cada firmante de F6 nombra su autoridad de sellado, seguida de «DateKeys no comprueba quién emitió los sellos.»;
- el resultado de un firmante ajeno sale en español.
- Datos de prueba:
- el generador vuelve a escribir los fixtures de la v0.10 con 512 bytes (
EncryptOptions.TestAreaLen, solo conTestVectors), y-forceya no rompe (e597760); format3_seal_unsupportedusaseal_type4294967295, y hayformat3_unsigned(32 KiB y la misma P que la firmada),format3_note,security.jsoncon contexto y líneas (aaf0f41), y 8 mutaciones nuevas dealg1, del área y de la nota (6c78c94, 218 casos);note.json(88ccbfd);security_cms.json, que pasa de 22 a 135 casos con suslines(edff5d1).
- el generador vuelve a escribir los fixtures de la v0.10 con 512 bytes (
- Pruebas y fuzzing:
- pruebas negativas de cada regla del lector CMS: de 949 mutantes, los 91 que sobreviven son equivalentes (
4ce4d59); - siete objetivos de fuzzing nuevos, del localizador, de DER y de CMS (
ec08ec9,ad40329); - pruebas de la regla 25, de la nota inutilizable y de la recuperación ante un pánico (
9b1123d).
- pruebas negativas de cada regla del lector CMS: de 949 mutantes, los 91 que sobreviven son equivalentes (
- Documentación (
858c5f1,2aff4a0): los README,SECURITY.md,docs/traceability.mdy el CHANGELOG, puestos en la v0.11 y el borrador v0.12. - Verificación:
go test ./...en verde enad40329.scripts/check.shpasó entero sobre2aff4a0(-race, cobertura decapsule91,6 %, govulncheck y vectores reproducibles). Su fuzzing se paró tras tres objetivos limpios, para cerrar la sesión. Los objetivos nuevos se pasaron aparte, de 40 a 60 s cada uno, limpios.
Hecho el 2-10 en TypeScript (rama v0.10 de App), con npm run verify en verde (7 432 tests): lo que no dependía del borrador v0.12.
- T1: el emisor que incumple las reglas se muestra con el hash de su nombre.
- T3: solo claves EC sin comprimir.
- T4: la nota con UTF-16 mal formado se rechaza.
- T5: ningún decodificador quita un BOM.
- T9:
testVectorsyareaLensalen del API público y pasan atesting/. - T10:
capsule-vectors.jsonregenerado con 32 KiB y nota; Go lo abre. - T11 y T12: la longitud con nota, y el formato 2 sin nota ni área.
- T13, en parte:
evaluateSecurityno lanza nunca, y los lectores de OID son lineales. - T14: README y CHANGELOG.
Siguiente, en orden
-
El autor revisa y aprueba el borrador v0.12 (§76, cambios 1 a 9). Las decisiones que contiene, todas con la recomendación de la revisión:
- las líneas de F6 con la autoridad y el aviso;
- las reglas de los nombres de certificado y la marca
↳; givenNameysurnamedelante del CN;- la lista de bloques no públicos de IANA y de nombres locales;
- el perfil del certificado;
accuracyhasta 2³¹ − 1;- los tamaños del localizador en el CDDL.
Queda también abierto si se quiere medir el área de 32 KiB con firmas reales antes de cerrar (pregunta 6 de la sesión anterior). Con la aprobación: el SHA-256 en
spec/README.md,SpecVersion0.12, el tagspec-v0.12ymainavanzado sin fusión, siempre con permiso del autor. -
Go, lo que falta:
-
locator.jsonampliado:- en
uri_cases, una dirección de cada bloque no público, los nombres locales, los caracteres fuera de RFC 3986, los segmentos..y un CID que no decodifica; - un localizador con una dirección rechazada y otra válida;
- otra ronda, un resto con otro SHA-256 y un recurso que sigue tras el resto;
- las bases de relleno 3837, 4094, 4095, 7933, 8166 y 8191.
El generador está en
internal/testkit/genfixtures/cmsvectors.go. Es un vector congelado: se borra y se regenera. - en
-
testdata/README.md, que sigue en la v0.10. Debe recoger:security.jsoncon contexto y líneas;note.json;format3_unsignedyformat3_note;- las 218 mutaciones;
security_cms.json, con el texto que dejó su agente: está en el informe de su commitedff5d1y se puede rehacer leyendo el generador;locator.json, cuando se amplíe.
-
Las marcas pending de
docs/traceability.mdy el apartado «Pending in this branch» del CHANGELOG. -
Un
scripts/check.sh 60scompleto.
-
-
TypeScript, segunda parte:
- Datos: sincronizar
testdatacon la cabeza dev0.12. - Lector CMS: portar el perfil de certificado de la v0.12 (T2, T6, T7, T8), los OID por bytes, los SET OF con repetidos, NumericString y los demás tipos de cadena como DER, y los casos límite (E9).
- Textos: los nuevos de los veredictos (comillas, autoridad de cada firmante, aviso, resultados en español,
ten RFC 3339 con fracción), el titular porgivenNameysurname, y las reglas de 64 puntos de código y espacios dobles. - Escritor: la regla de
CheckWrite. - Vectores y fixtures:
security.jsoncon su estructura nueva;note.json; los fixturesformat3_unsignedyformat3_note, y losibe-vectorsde los fixtures nuevos o cambiados; las 8 mutaciones; los 135 casos desecurity_cms.jsoncon sus líneas. - Pruebas: la tautología de
cms.test.ts:106.
El TypeScript no tiene todavía el localizador. Es una función pendiente, no un fallo.
- Datos: sincronizar
-
Dart: el plan está en su v2, PLAN_dart.md, con las tres decisiones del autor del 2-10: solo
package:crypto, primero la lectura y paquetedatekeys.- Se empieza por la etapa 0, el esqueleto con
testdatasincronizado. Para la etapa 4, el generadorpathrule/gennecesita una salida-dart. - La etapa 5, la de firmas y sello, se sincroniza con
v0.12, no conspec-v0.11.
- Se empieza por la etapa 0, el esqueleto con
Para trabajar
- Gates:
scripts/check.shendatekeys-go: los tests con-racedecapsuletardan minutos. Si lo paras, mata tambiénfuzz.shy los procesos*.test.exe, que quedan huérfanos.npm run verifyynpm run testdata:checkendatekeys-ts.
- El generador:
go run ./internal/testkit/genfixtures -out testdatano toca los fixtures que ya existen, ni sus registros.- No uses
-only mutations: regenera los 33 casos congelados del corpus. Para añadir mutaciones basta una ejecución normal. - Los vectores congelados (
security_cms.json,locator.json) se rehacen borrándolos.
- Herramientas de esta máquina:
- Los heredocs de Bash rompen las barras invertidas y los apóstrofos.
- La herramienta Write convierte
\uXXXXen caracteres literales; en Go, escribe esos escapes con un script. go test … | tailesconde el código de salida: mira$?antes de hacer commit. Una vez se hizo commit con una prueba rota (e597760, arreglada en0f51af7).
- Agentes: el trabajo en paralelo en Go se hizo con agentes en clones propios del scratchpad y ficheros repartidos, integrados con
git fetchycherry-pick. Los subagentes, conmodel: "opus".
0. Reorganización del espacio de trabajo (29-09, mediodía)
G:\bussines\datekeys se reorganizó el 29-09. El mapa de carpetas y las reglas del proyecto están ahora en el README de este repo. Los cambios:
- Documentos: los del proyecto, este incluido, pasaron de
App/docsa este repo,docs, que es privado y no tiene remoto. Su primer commit es6e8d6c6. Los papeles de trabajo de la v0.9, que solo estaban en una carpeta temporal, están en spec_v0.9/. App: quitódocs/, y el paquete, el README y el aviso de licencias del sitio pasan a llamarsedatekeys-ts(5ee8813, subido).npm run verifysigue en verde, con 2 611 tests.- Archivo y logos:
AppOldpasó aarchive/prototype, sin cambios;- los borradores v0.1 a v0.8.1, que estaban en Descargas, pasaron a
archive/spec-drafts, con los hashes comprobados; - los logos pasaron a
brand/.
- Claude:
- la memoria de Claude es ahora la de la raíz. La de
Appqueda congelada, con una nota que remite a la nueva; - en la raíz hay un
CLAUDE.md, que carga el README, y un.claude/launch.jsonpara las vistas previas.
- la memoria de Claude es ahora la de la raíz. La de
- Nombres: en las secciones siguientes,
Appes el repo que ahora se llamadatekeys-ts. Su remoto sigue siendogo/DateKeys-App.
Pendiente del autor, antes de seguir:
- Cerrar la sesión abierta en
Appy renombrar la carpeta adatekeys-ts. Windows no deja renombrar una carpeta en uso. - Abrir las sesiones siguientes en
G:\bussines\datekeys. La primera compruebanpm run verifyynpm run testdata:checkendatekeys-ts. - Borrar
G:\bussines\datekeys\enquiry.php, que es una copia idéntica deweb/static/api/enquiry.php. Claude no tiene permiso para borrarlo. docsywebsolo existen en esta máquina. Para tener una copia fuera de ella, hay que darles un remoto.
El 30-09 a mediodía seguían pendientes los cuatro: la carpeta se llama todavía App, y la sesión de ese día también se abrió en ella.
1. Repositorios
Histórico, del 30-09: el estado actual está en «Retomar aquí».
Los repos con remoto están en el Gitea privado g.activething.com (solo LAN, certificado autofirmado para git.activething.com; git funciona, curl necesita -k). Ese servidor no es del autor: no se proponen cambios en él. La integración continua es el gate local.
| Repo | Rama | Commit | Estado |
|---|---|---|---|
datekeys-go (go/DateKeys) |
main |
cc35d2c |
Spec v0.10, entrega 1 del formato 3, aprobada por el autor el 30-09 y cerrada con el tag anotado spec-v0.10 en cc35d2c; SHA-256 del spec 7f26419a444aa3e89a3aa8afbbba9d952af69e048aee1e93cd70732c2d1d99d1. Implementa el formato 3: lo escribe y lee los formatos 1 a 3, con SpecVersion 0.10. scripts/check.sh 60s limpio. La v0.9 sigue en su tag, spec-v0.9 (7e2d83c), y la v0.8.2 en el suyo, spec-v0.8.2 (9ac9cd9). |
v0.8.2 |
9ac9cd9 |
El commit del tag; ya no hace falta. | |
v0.9 |
7e2d83c |
El commit del tag spec-v0.9; ya no hace falta. |
|
v0.10 |
cc35d2c |
Igual que main; ya no hace falta. |
|
datekeys-ts, antes App (go/DateKeys-App) |
main |
da26862 |
Desde 5ee8813, sin docs/ y con el paquete datekeys-ts (§0). Versión 0.2.0-dev desde 8c08c97, con v0.1.0 cerrada en d577283; implementa el spec 0.9 desde 0118890 (VERSION y SPEC_VERSION, también en el pie de la página). Escribe el formato 2 y tiene la página /create (fase 3, §2.5). Librería TypeScript con la inspección (pasos 1 a 8) y la apertura (pasos 9 a 18) de los formatos 1 y 2, en memoria o desde un Blob hacia un stream de salida, como un fichero OPFS. Página /inspect con la acción "abrir", que muestra el formato y avisa del 1. testdata sincronizado a 7e2d83c (spec-v0.9). Fase 2 completa (pasos 2 a 8), incluidos el cifrado tlock y la interoperabilidad de TypeScript a Go. Los 125 casos del corpus pasan por open con el código, el paso y el texto de Go. En 0118890, 5 425 tests, ninguno saltado; la fase 3 añadió los suyos, con npm run verify en verde en cada paso (§2.5). |
docs (solo local) |
main |
Este repo: handoff, planes, revisiones y reglas. | |
web (solo local) |
main |
f2b8a38 |
Landing de datekeys.com. |
archive/prototype, antes AppOld (solo local) |
master |
4d2b0a1 |
Prototipo antiguo. No se toca. |
Verificación ya hecha sobre datekeys-go:
- fuzzing de 30 min en cada uno de los 15 objetivos sobre
3820066, limpio; - diferencial Go/TypeScript de 407 196 entradas contra
f6f2e9f, con cero diferencias, textos de error incluidos; scripts/check.sh 60ssobre9ac9cd9, el commit del tag, limpio (28-09), y sobre el estado de6fa2b54, con tres objetivos de fuzzing nuevos del formato 3, limpio (30-09);- govulncheck no encuentra nada alcanzable. Avisa, sin llamada alcanzable, de dos problemas:
- GO-2026-6443, en
google.golang.org/grpc1.84.0, arreglado solo en una versión-dev. Hay que subir grpc cuando salga la 1.85.0. - GO-2026-5932, en
golang.org/x/crypto/openpgp, sin arreglo. No lo importamos.
- GO-2026-6443, en
2. Qué queda, en orden
2.1 Hecho el 28-09: cierre de la v0.8.2
- Los 9 retoques de la 2.ª revisión están en
9ac9cd9, un solo commit sobrec57ed48que absorbe el WIP69a3342. La rama WIP está borrada. - §76 los recoge como correcciones 4 a 6:
- un encoder MUST NOT escribir una extensión fuera de su registro;
- §17 y §51 dan los códigos del paso 10 solo para un release suministrado directamente;
- en el paso 9, cualquier fallo de la fuente es
ERR_RELEASE_UNAVAILABLEy ningún otro código.
- La regla del encoder no se comprueba en la librería:
capsule.Encryptyaccesskey.Encodeno recibenRegistry, y la aplica la aplicación. Está documentado enextension.Placement. - El autor aprobó el texto el 28-09. El spec lleva esa fecha, y el SHA-256 de sus bytes LF,
5cfa3203…, está enspec/README.mdy en el mensaje del tag. mainavanzó por fast-forward hasta9ac9cd9y lleva el tagspec-v0.8.2. Los dos están subidos.Appsincronizótestdatacon9ac9cd9en71ab8fb. Solo cambiatestdata/README.md.
Las reglas que siguen valiendo (testdata, textos de error y versiones cerradas del spec) están en el README.
2.2 Fase 2: abrir cápsulas en el navegador
Plan: docs/PLAN_fase2_ibe_noble2.md v2, con las decisiones confirmadas por el autor. Los pasos 2 a 8 de su sección 10:
- hecho el 28-09 (
74e1215):age-encryption0.3.1 y noble 2.4.0 como dependencias de ejecución, con sus guardas ensrc/lib/dependencies.test.tsycheck-build.mjs. El README deApprecoge el coste medido en el bundle, 73 KB con gzip para todo, ynpm audit; - hecho el 28-09 (
35be27c):ibe.tssobre noble 2, con vectores de Go ensrc/lib/dkc/testing/ibe-vectors.json(scripts/ibe-go-vectors.go) y cobertura del 100 % fijada como umbral. Los argumentos del stanza y su paso alStanzadeage-encryption, que guarda el tipo enargs[0], van al paso 7; - hecho el 28-09 (
076f3db):release.ts, converifyReleaseen el orden y con los textos deprovider.Verify,ReleaseSourceysuppliedRelease. Solo verifica el scheme de Quicknet: otro daERR_UNKNOWN_PROFILE. Reproduce los 7 casos del corpus que fallan en el paso 10; - hecho el 28-09 (
97827ae), paso 5a:open.ts, los pasos 9 a 18 con el texto en claro en memoria. Las identidades estrictas deagewrapse apoyan enx25519.ts, que abre los stanzas de uno en uno. Usa@noble/ciphers2.4.0, dependencia directa aprobada ese día: es la copia que ya usaage-encryption. Las identidadesAGE-SECRET-KEY-1…se leen conbech32.ts.index.tsno reexporta aún la apertura, que metería noble en/inspect; - hecho el 28-09 (
a89bee5), paso 5b.openacepta unBlobdel que solo lee el prefijo de los pasos 1 a 8 (prefix.ts, movido de la página a la librería), calcula elcapsule_digesten streaming (digest.ts) y descifraPAYLOAD_AGEen streaming. La salida puede ser unWritableStream, que se cierra tras el paso 18 y se aborta ante cualquier fallo. Comprobado en el navegador con OPFS real: un fallo de STREAM deja intacto el fichero; - el paso 6 está cubierto: la enmienda de canonicidad entró en la v0.8.2;
- hecho el 28-09 (
66970cf), paso 7:encryptOnG2RFC9380ytimeRecipient. Con sigma fijo, el cifrado reproduce byte a byte los vectores de Go. Go abrió los cuerpos IBE y los ficherosageque cifró esta librería, contlock.TimeUnlocky conagewrap.NewTimeIdentity. Todo está ensrc/lib/dkc/testing/tlock-vectors.json; - hecho el 28 y 29-09 (
48d6704), paso 8: la acción "abrir" en/inspect, cargada bajo demanda, con la política aprobada por el autor el 28-09 tras revisar lo que dice el protocolo:- el release lo pega quien abre, o sale del registro del fixture, y la página nunca lo pide a la red;
- el texto en claro de un fichero propio va a un fichero temporal de OPFS (§56), que se borra;
- los avisos de licencia se publican en
licenses.txt. Una revisión adversarial confirmó 15 hallazgos, todos corregidos. Los detalles y las comprobaciones en el navegador están en la fila 8 del plan.
La lectura del protocolo del 28-09 deja dos SHOULD para más adelante: §48 (varios relays) y §49 (obtener el release directamente del proveedor). Los cubrirá una fuente drand opcional del SDK, nunca activa por defecto en la página (sección 12 del plan).
El vector de GT (vectors/tlock_ibe.json) ya está cubierto en App. El paso 9 de open.ts debe seguir la corrección 6: cualquier fallo de una fuente es ERR_RELEASE_UNAVAILABLE y ningún otro código.
2.5 Sesiones del 29-09: v0.9 del spec y formato 2 en Go (retomar aquí)
Estado al parar (30-09 por la noche). Retomar por el formato 3, al final de esta sección: la spec v0.10, entrega 1 del formato 3, está aprobada, implementada en la referencia Go y cerrada con el tag spec-v0.10, todo subido en main de datekeys-go (cc35d2c). Lo siguiente es el formato 3 en datekeys-ts.
Estado al cerrar la fase 3 (29-09 por la noche):
- Pasos 1 a 5 hechos. El spec v0.9 está cerrado con el tag
spec-v0.9(7e2d83c, enmaindedatekeys-go), y las dos implementaciones leen el formato 2: Go desdef24a280, que también lo escribe, y TypeScript desde0118890. - Paso 6 hecho: la fase 3 está completa en
datekeys-ts(pasos 0 a 7 del plan, hasta3a9d2b1, subido). La librería escribe el formato 2, Go abre lo que escribe y la página/createcifra en el navegador. La versión0.2.0sigue sin publicar: cerrarla es decisión del autor (§2.3). Después, a petición del autor,/inspectmuestra el contenido al abrir, debajo del veredicto, y nombra la descarga por su tipo. Las páginas explican las claves deage, y la vista previa sirve las páginas sin caché (da2000a,da26862, subidos). - Las 22 correcciones del repaso final (spec_v0.9/review.md) se aplicaron en
4a025d1, más cuatro sitios que repetían los mismos problemas: las reglas 1 y 4 del §62.1 y los cambios 4 y 10 del §76. Los números de la corrección 1 se recalcularon con un Padmé en BigInt. - La corrección 2 la decidió el autor el 29-09: se suaviza el §56.
- El lector MUST NOT presentar el contenido como válido antes de que termine el paso 17.
- Un lector en streaming MUST NOT escribir el relleno y MUST señalar el error para que se descarte lo escrito.
- Así siguen valiendo
Open(dst)de Go y la salida en streaming de TypeScript.
- En este repo están PLAN_fase3_escritura.md, el plan del writer TypeScript, y REVISION_completitud_protocolo.md, la revisión del protocolo. El plan está en su v3: el autor confirmó sus 17 decisiones el 29-09.
Aprobación del 29-09. El autor aprobó el texto de la v0.9 con las respuestas recomendadas a las preguntas abiertas:
- L es un
bstrde 8 bytes, no unuint. - El lector SHOULD informar del formato.
- Se mantienen el objetivo 8 de §4 y el no objetivo nuevo de §5.
- Solo un generador de vectores de prueba MAY escribir el formato 1 (§62.1, regla 1, y §70).
- Los fixtures nuevos llevan el prefijo
format2_. - Se mantiene D1: los señuelos son identidades generadas cuya clave privada se descarta en el acto.
- Rechazar puntos del twist sigue siendo MAY.
- Se confirman las reglas añadidas: L_MAX = 2⁵³ − 2⁴⁶, el orden uniforme de los stanzas, que el SDK SHOULD mostrar el instante efectivo de la ronda y que el lector MAY comprobar la longitud de PAYLOAD_AGE.
Decisiones del autor del 29-09 para la v0.9:
- D1:
time_and_keylleva siempre exactamente 16 stanzas X25519 enINNER_ACCESS_AGE. Los que sobran son señuelos, y todos van en orden aleatorio. Como mucho hay 16 credenciales, contando la.dkk. - D2: el contenido se rellena siempre. El código 1 redondea al siguiente múltiplo de 256, con un mínimo de 256. El código 2, "reforzado", es max(bloque256, Padmé) y es el de por defecto. No hay opción sin relleno.
- D3: la longitud real y el código van en
CONTROL_CBORversión 2 (claves 6 y 7). El lector entrega solo L bytes y comprueba que el relleno sea todo ceros y que siga la regla. - D4: el formato pasa a 2 (
VERSION2 del PRELUDE), así que un lector v0.8.2 lo rechaza en el paso 2, sin red. Un lector v0.9 sigue abriendo el formato 1. - D5:
access_policysigue visible. - D6: nueva sección de privacidad, §55.2.
- D7: reglas normativas del escritor, §62.1:
I_PAYLOADsale de un CSPRNG y no se reutiliza;- límites;
- la fecha pedida tiene que ser futura;
- el escritor se autocomprueba;
- rechaza claves X25519 no canónicas o de orden bajo.
Hecho en Go, paso 3 (f24a280):
- Formato 2 en la librería:
capsule:Format,Padding,PaddedLength,PayloadAgeLength;EncodeControlyDecodeControlreciben el formato;Openaplica los pasos 12 a 18 del formato 2.agewrap:AccessSlotsyCheckX25519Recipient.
- Escritura:
Encryptescribe solo el formato 2.EncryptOptions.Lengthes obligatorio;Paddinges reforzado por defecto.- Acepta de 1 a 16 credenciales, con señuelos, orden aleatorio y autocomprobaciones.
- La CLI mide la entrada, acepta
-paddinge informa del formato.
testdata:- 7 fixtures
format2_*, dos de ellos con.dkk; vectors/padding.json;- los vectores CBOR del formato 2;
- un corpus de mutaciones de 125 casos: 88 del §64 (33 en cada formato y los 22 de la tercera lista) y 37 más;
- un diferencial de 4 380 casos, en el que los 1 825 anteriores no cambian.
- Los fixtures del formato 1 se conservan byte a byte.
- 7 fixtures
- Mutaciones sin aleatoriedad: se vuelven a sellar los fixtures con sus claves y nonces conocidos (
internal/testkit/reseal.go), así que se regeneran byte a byte. scripts/check.sh 60slimpio:- cobertura: codec 100 %, capsule 94,2 %, accesskey 97,2 %, datekey 94,6 %, agewrap 92,8 %;
- govulncheck, con los mismos dos avisos de §1;
- 60 s de fuzzing en cada uno de los 15 objetivos.
- Documentación: la copia del spec del repo pierde las marcas "(por implementar)". README, README.es, CHANGELOG,
docs/traceability.mdytestdata/README.mdestán al día.
Orden de trabajo:
-
Aplicar y verificar las 22 correcciones. Hecho el 29-09 (
4a025d1). -
El autor aprueba el texto de la v0.9. Hecho el 29-09.
-
La referencia Go implementa el formato 2, con fixtures nuevos y mutaciones, y pasa
check.sh. Hecho el 29-09 (f24a280). -
Se pone el tag
spec-v0.9. Hecho el 29-09, con la autorización del autor:7e2d83canota el SHA-256 del spec enspec/README.md, que también va en el mensaje del tag;mainavanzó hasta ese commit sin merge;main,v0.9y el tag están subidos.
-
datekeys-tssincronizatestdatay el lector TypeScript abre el formato 2. Hecho el 29-09 (0118890, subido):testdataa7e2d83c;- el prelude lee el formato;
decodeControlyencodeControlreciben el formato;padding.tscon las dos reglas, exactas hasta L_MAX; openexige 16 stanzas en el paso 12, calcula P en el 16 y comprueba el relleno en el 17, entregando solo los L primeros bytes; el paso 17 se registra también cuando se supera;- la página muestra el formato, avisa del 1 y, al abrir una cápsula del formato 2, da la regla y P;
ibe-vectors.jsonañade los siete fixtures del formato 2, calculados conscripts/ibe-go-vectors.go; los valores congelados no cambian;- comprobado: los 125 casos del corpus dan en TypeScript el código, el paso y el texto de error de
capsule.Open, en memoria y desde unBlob.
-
Se replantea el plan de la fase 3 y se escribe el writer TypeScript del formato 2. Hecho el 29-09. El 29-09 por la noche, PLAN_fase3_escritura.md pasó a su v2, sobre las reglas del §62.1:
- 16 huecos con señuelos y orden uniforme;
- relleno
reforzadopor defecto; - L conocida de antemano;
- autocomprobaciones;
- recipients canónicos y no de orden bajo, como Go;
SEALED_CONTROL_LENcon la fórmula del §62.1 y comprobada. Una revisión crítica con sondas no encontró nada bloqueante ni grave, y sus 12 correcciones menores están incorporadas.
Hecho el 29-09 en
datekeys-ts, todo subido y connpm run verifyen verde en cada paso:-
paso 0: el autor confirma las 17 decisiones con su recomendación, entre ellas cerrar
0.1.0ya (D14), la fórmula del §62.1 comprobada con el sellado real (D3) y aceptar los puntos del twist, como Go (D6). El plan pasa a v3 (b97dee2en este repo); -
paso 1:
0.1.0cerrada (d577283, tagv0.1.0) y0.2.0-devabierta (8c08c97); -
paso 2 (
8838c7d):recipient.ts,random.tsyagefile.ts, y las guardas nuevas; -
pasos 3 y 4 (
8473fdf):encrypt.tsywriter.ts. Reproducen byte a byte las secciones deterministas de los siete fixtures del formato 2 de Go, escriben en streaming y abortan la salida ante cualquier fallo. El bucle de propiedades pasa con 500 semillas; -
paso 5 (
da0b39f): Go abre con cada credencial las trece cápsulas de muestra que escribe TypeScript, y las reencodifica a los mismos bytes. Rechaza cuatro mezclas con el mismo código y paso, codifica igual 500 entradas aleatorias y da los mismos textos en 22 recipients y 21 opciones inválidas. Todo queda congelado ensrc/lib/dkc/testing/capsule-vectors.json. -
paso 6: el autor confirma las decisiones de la página con cada recomendación (sección 9 del plan, «Decidido en el paso 6»):
time_onlypor defecto, la zona del dispositivo con un selector, los avisos de §53 y §50 desde 365 días y un aviso de protocolo preliminar; -
paso 7 (
3a9d2b1): la página/create, conlengths.ts(el tamaño del.dkcantes de escribirlo),localtime.ts,create-input.tsycreator.ts. En la compilación de producción, una cápsula creada para dentro de cuatro minutos se abrió después en/inspect, con el release pegado de drand, y condatekeys decryptde Go, con red y su.dkk, al 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. -
después, a petición del autor (
da2000a):/inspectmuestra el texto en claro de cualquier cápsula que se abre, si es texto, y no solo el de los fixtures. Las dos páginas explican las claves deage: qué es un destinatarioage1…, cómo se consigue conage-keygeny qué se pega al abrir.
Siguiente: que el autor decida si cierra
0.2.0(tagv0.2.0endatekeys-ts). Después, lo de §2.4.
Formato de cápsula 3, en diseño (30-09). El autor quiere que una cápsula guarde varios ficheros y carpetas con sus nombres, tamaños, hashes y fechas, más una firma de autor y un sello de tiempo, ambos opcionales. Hoy el nombre del fichero se pierde: §6 y §55.2 lo dejan fuera del protocolo.
- Decisiones del autor:
- todo va cifrado dentro de
PAYLOAD_AGE, comosecurity | head | content; - hash SHA-256 por fichero, sin hash global;
- con carpetas;
- la fecha de modificación se toma al cargar, marcada por defecto;
- un comentario y un autor declarado, opcionales;
- sin tipo de contenido;
- firma Ed25519 y sello de DateKeys, con registro anclado en OpenTimestamps.
- todo va cifrado dentro de
- Un flujo de diseño con revisión adversarial produjo spec_v0.10/formato3_diseno.md: 28 objeciones, que resultaron ser 24 distintas, corregidas o aceptadas.
- El paquete para la revisión de seguridad externa, con el contexto del protocolo, el modelo de amenazas y las preguntas, era
spec_v0.10/formato3_para_revision.md(56851a9). Se borró al unificar el diseño, pero sigue en git y publicado como artefacto privado, en la versión que revisó Fable: https://claude.ai/artifact/5NY9YxBjZA6DCadZ1aT5Ln. - Revisión de Fable (30-09), guardada en spec_v0.10/revision_fable.md.
- Veredicto: la parte criptográfica aguanta, y confirma la aritmética de tamaños y la necesidad del verificador Ed25519 propio. Los problemas están en los bordes.
- Diez hallazgos, cuatro mayores y seis menores; también hay observaciones sobre el documento.
- Valoración: coincido con todos. Comprobados de memoria: el 2 (la lista de git en
core.protectHFSincluye ZWJ, ZWNJ y U+206A–206F) y el 6 (JavaScript compara en UTF-16: U+FF5E y un emoji quedan al revés que en Go).
- Arreglos que no necesitan decisión:
- 2. R4 por la propiedad
Default_Ignorable_Code_Point, con lista blanca corta (ZWJ, ZWNJ, VS15, VS16); la clave de R7 descarta lo permitido; tags U+E0000 a U+E007F prohibidos. - 5. El tamaño del área de
securityva en la trama, fijo por versión y reservado siempre. - 6. TypeScript compara bytes UTF-8, con un vector en
paths.json. - 7. En la CLI, prefijo en cada línea visual del comentario, y los veredictos repetidos al final.
- 8. Se declara como fuga aceptada que el POST al servicio delata el sello.
- 9. Tabla de verdad firma/sello, expresión regular de R6b y regla para una mtime negativa.
- 10. Prefijos de dominio en
control_commityhead_digest, y el nombre.datekeys-*reservado. - El documento: 24 objeciones en vez de 28, marcadas «corregida» o «aceptada»; un glosario (capas 2 a 4, L_MAX, la sal); un texto para un sello que el lector no sabe verificar; una sola fuente en vez de tres ficheros que repiten el texto.
- 2. R4 por la propiedad
- Decisiones del autor del 30-09 sobre la revisión:
-
Tres entregas, con el formato congelado desde la primera y
securitypresente pero vacío:- 1: contenedor, varios ficheros y rutas;
- 2: firma y claves de autor;
- 3: el sello, cuando exista el documento «Servicio de sellado v1».
Las entregas 2 y 3 no cambian el formato: un lector anterior muestra «no soportado» y abre igual.
-
Origen del servicio (hallazgo 1): el autor no tiene preferencia, así que se toma la recomendación.
- Un subdominio aparte,
seal.datekeys.com, que solo sirve la API y nunca HTML, con cabecerasnosniffyCSP: sandboxde todos modos. - La CSP de
/createañade ese origen aconnect-src, solo en esa página. - Es de la entrega 3 y se puede revisar entonces.
- Un subdominio aparte,
-
Vida del sello (hallazgo 3): la prueba va dentro de la cápsula.
- El token lleva la prueba de inclusión y el checkpoint firmado, y una raíz offline, fijada desde ya, certifica las claves anuales. Así el sello se verifica sin red para siempre, y la auditoría del anclaje queda como comprobación online opcional.
- Esto agranda el área de
security: con el arreglo del hallazgo 5, la entrega 3 define una versión desecuritycon un área fija mayor.
-
Abuso (hallazgo 4): prueba de trabajo SHA-256 en cada petición, de un segundo en el navegador, sin guardar estado sobre quién pide.
-
- Hecho el 30-09 a mediodía (
57dc659), sin flujo y con un único revisor adversarial:- formato3_diseno.md es la única fuente del diseño. Se borraron
formato3_revision_intro.mdyformato3_para_revision.md, que repetían su texto. - Estructura: una parte 0 de contexto, con glosario, decisiones y modelo de amenazas; una parte por entrega, cada una con sus pruebas y sus preguntas abiertas; y tres anexos con las revisiones. El de Fable dice dónde se resuelve cada hallazgo, el de la revisión interna marca sus 24 objeciones como corregidas o aceptadas, y el tercero recoge la revisión adversarial de esta versión.
- Aplicados los arreglos 2 y 5 a 10, los del documento y las cuatro decisiones.
- La revisión adversarial no encontró nada bloqueante ni mayor. Sus 15 hallazgos menores están resueltos en el diseño (anexo C), y una segunda pasada comprobó los arreglos. Los que cambian el diseño:
- el head va siempre en su versión 1, porque §22 exige un formato nuevo para una versión nueva;
- las claves 2 y 3 de
securityvan codificadas aparte, así que una firma o un sello mal formados no arrastran al otro; - el área depende solo de la versión del spec, nunca de
-seal, y hay dos fugas nuevas declaradas: un área de 512 delata que no hay sello, y el registro publica la t de cada sello; - R3 limita el NFD de cada segmento a 255 unidades UTF-16, por HFS+, y R4 prohíbe U+F000–U+F0FF;
- un sello que no verifica se descarta y ya no aborta la cápsula.
- Interpretación que confirmar: la decisión 3 hablaba de «una versión de
securitycon un área fija mayor». El diseño hace que el área la fije la versión del spec y deja el mapasecurityen su versión 1, para que un lector de la entrega 2 siga comprobando la firma en una cápsula de la entrega 3. Es la pregunta 3 de la entrega 1.
- formato3_diseno.md es la única fuente del diseño. Se borraron
- Hecho el 30-09 por la tarde:
- El autor cerró las diez preguntas de la entrega 1, todas con la recomendación (
afd9f76). Los límites quedan como se propusieron y congelados con el formato. Un único fichero dentro de una carpeta se descarga directamente, con el ZIP como opción, y la página ofrece cada fichero del ZIP como un corte suyo. - El borrador del spec v0.10 de la entrega 1 está en
datekeys-go, ramav0.10, sin subir:fa7f95elo redacta y9d1cd2eaplica la revisión final. Lleva el spec, el CDDL yspec/README.md. La referencia sigue implementando la v0.9, y suSpecVersionno cambia. - La revisión final, como la de la v0.9, encontró un problema bloqueante, tres mayores y once menores, todos corregidos (spec_v0.10/revision_borrador.md). El bloqueante: R6c rechazaba «¿», porque bestfit1250 lo lleva a '?'. Ahora solo rechaza '/', '', ':' y U+0000 en una proyección. El diseño recoge los cambios que le afectan en su anexo D.
- Pregunta del autor: la firma de autor con su clave privada está prevista, en la entrega 2. Varias firmas no hace falta decidirlas ahora: un
algfuturo puede definir una lista de firmas sin cambiar el formato (pregunta 3 de la entrega 2 del diseño).
- El autor cerró las diez preguntas de la entrega 1, todas con la recomendación (
- Siguiente:
- Hecho: el autor eligió Unicode 18.0.0 («no vamos a trabajar con unicodes ya pasados») y dio el visto bueno al texto. El borrador lo recoge en su rama, y el diseño, en su decisión 4.
- Hecho: el autor aprobó la regla de invisibles («sí a las dos»), que el spec recoge en R4b y en §29.6 (
631d09c). - Hecho: con su permiso se descargaron los 19 ficheros de datos, 8,25 MB, en
datekeys-go/.cache/, fuera de git. - Hecho: la referencia Go implementa el formato 3, con el plan y el detalle de abajo. Con la autorización del autor («sí, sube la rama y pon el tag»), la rama
v0.10y el tag anotadospec-v0.10están en el remoto, encc35d2c, que solo cambia textos para nombrar el tag. Después, a petición suya («sí, avanza main hasta la v0.10»),mainavanzó hastacc35d2csin fusión y está subida. - En curso:
datekeys-tslee y escribe el formato 3 con su plan. En la ramav0.10deApp, sin subir, están hechos los pasos 0 y 1 (fbb90b2, las tablas y las reglas de rutas y de texto), del paso 5 el CRC-32 y la disposición del ZIP (36096a9), el paso 2 (d9a9cf5, el códec) el paso 3 (b176ad2, la lectura del formato 3 contestdataenspec-v0.10) y el paso 4 (de3daa1f7a2efc8bc:encryptFiles,encryptsolo contestVectors,/createen formato 3 con un fichero, y la interoperabilidad con Go). El paso 5, el ZIP y el sumidero de la página, está enee82f43, el paso 6, la página/inspectcon los ficheros del formato 3, en651178a, y el paso 7, la página/createcon ficheros, carpetas, rutas editables, comentario y autor, en7dc88ef. El paso 8 está hecho (7527c35,57e0a8a,e6cca0by el CHANGELOG): README,testdata:checkcontracc35d2c, tres revisiones adversariales con subagentes y sus correcciones, y, a petición del autor,/createrediseñado (una carta al futuro, sobre de correo aéreo, fuentes del sistema) y el sitio siempre claro. Pendiente, sin urgencia:/inspectsolo cambió de aspecto con los estilos globales: falta poner el resultado delante y plegar los pasos 1 a 18, como en/create.- El texto del paso 17 aún difiere del de Go cuando la cápsula se corta justo tras un chunk completo:
age-encryptionretiene ese chunk hasta ver un byte más. Igualarlo exige descifrar el STREAM como Go (código propio con@noble/ciphers). - Un head de 16 MiB tarda de 10 a 40 s en la página, en el hilo principal (Go tarda la mitad):
open()en un worker. - Menores: el
TypeErrorsin sumidero llega tras los pasos 3 a 8 con unBlob;tempfile.remove()marca borrado antes de lograrlo;measureFilesen cada tecla con 65 535 ficheros; un bundle.appno avisa (igual que la CLI). - Subido el 01-10 por la noche, con permiso del autor: la rama
v0.10deApp, ymainyv0.11dedatekeys-go.
- La entrega 2 abre la versión siguiente del spec, y la 3 espera al documento «Servicio de sellado DateKeys v1». En esa versión entra también la llave de palabras que pidió el autor el 01-10: palabras que elige la persona y abren la cápsula en lugar de la
.dkk, ya hechas en la página y en la CLI (apartado «Retomar aquí»). Además, el 01-10 el autor pidió que/inspectpueda pedir la firma a drand: ya lo hace, con un botón (2ec7102), lo que cambia la decisión 4 del plan de la fase 2. Para otra revisión externa, el artefacto hay que volver a publicarlo desde el diseño nuevo.
Hecho el 30-09 por la noche: el formato 3 en Go. Rama v0.10 de datekeys-go, subida con el tag spec-v0.10 en cc35d2c, un commit o varios por paso del plan:
631d09c, el spec con la regla de invisibles;6fba1dd, paso 1,internal/pathrulecon las tablas de Unicode 18.0.0 y best-fit generadas y suTablesDigest;72e86b8, paso 2, el códec deBODY,securityy el head.7249ef4, paso 3, el lector:capsule.Sink,ErrSinkRequiredjusto tras el paso 2, el paso 17 en subpasos con su precedencia, y lecturas deBODYque crecen con los bytes recibidos (§57).8955c0f, paso 4, el escritorcapsule.EncryptFiles, que lee cada fichero dos veces;Encryptsolo escribe el formato 2 conEncryptOptions.TestVectors.a0de80f, paso 5, el CLI:encrypt -incon ficheros y carpetas,-comment,-authory-no-mtime;decrypt -out CARPETAconos.Root; la presentación de §29.7, con el ancho del terminal pedido porsyscall, sin dependencias nuevas.- Paso 6, datos de prueba:
3c39336(SpecVersion0.10 yERR_HEAD_INVALID),e070f89(las nueve fixtures),db862d5(paths.json,path_fold.json,head_schema.json,security.jsony el control de versión 3 encbor.json) y18eb3c3(las mutaciones: 209 casos, 169 del §64, tres de los cuales se abren con su veredicto). 20f9959, paso 7, la documentación;735885c, una corrección del CLI: una carpeta de salida sin su carpeta padre falla antes de pedir el release;6fa2b54, paso 8, tres objetivos de fuzzing nuevos (FuzzDecodeHead,FuzzEvaluateSecurity,FuzzCheckPath) y el SHA-256 del spec enspec/README.md.- Verificación:
go test ./...yscripts/check.sh 60slimpios, cobertura decapsule93,1 %; la prueba en vivo contra Quicknet abrió cápsulas de formato 3 de las dos políticas; los tres objetivos nuevos, cerca de un millón de ejecuciones cada uno, sin fallos. - Para el autor, sin urgencia:
- un cambio editorial en el texto aprobado: §67 decía «Serán … (por implementar)» de las fixtures del formato 3, y ahora dice «Son …». El SHA-256 de
spec/README.mdes el del texto con ese cambio; - el corpus de mutaciones pasa de 168 KB a 706 KB. 476 KB son el caso de 65 536 carpetas implícitas que pide el §64, cuyo head mide 235 KB;
- los textos del CLI que el spec no fija son de la referencia: la cabecera «Ficheros escritos en CARPETA (N):», los avisos de nombres peligrosos y los mensajes del escritor. Los que fija, los veredictos y las dos etiquetas, van literales.
- un cambio editorial en el texto aprobado: §67 decía «Serán … (por implementar)» de las fixtures del formato 3, y ahora dice «Son …». El SHA-256 de
- Para
datekeys-ts:- hecho: el generador escribe el módulo TypeScript con la bandera
-ts(13910b3, enmaindedatekeys-go, un commit por delante deorigin/mainy sin subir), y el digest recalculado en TypeScript coincide conTablesDigest; testdatacambia entero de"spec", y añade nueve fixtures, cuatro ficheros de vectores,mutations.jsoncon 209 casos (version changedpone ahoraVERSION4, y hay casos converdicts) y el diferencial con 5 110;- los textos de las reglas de rutas y de texto deben coincidir byte a byte:
paths.jsonyhead_schema.jsonlos traen enresultydetail.
- hecho: el generador escribe el módulo TypeScript con la bandera
- Herramientas: en esta máquina los heredocs de Bash rompen apóstrofos y barras invertidas, y la herramienta Write convierte
\uXXXXen caracteres literales. Funciona escribir los cambios como scripts de Python en el scratchpad.
Conclusiones de la conversación, sin decisión pendiente:
- El protocolo no contempla un sello de tiempo de creación (§5, §55.1). Si se quiere, lo recomendado es un sello RFC 3161 u OpenTimestamps sobre el SHA-256 del
.dkccompleto, guardado aparte. - Un fichero único
.dkcon.dkcy.dkkjuntos no conviene: contime_and_keyequivaldría atime_only. Ya se envía un solo fichero contime_onlyo con destinatariosage1…. datekeys-tscerró0.1.0el 29-09 (d577283, tagv0.1.0), y la fase 3 va en0.2.0-dev.
2.3 Depende del autor
- Crear
security@datekeys.comy, si se quiere, unsecurity.txten la web. Después, actualizarSECURITY.md, que hoy diceinfo@activething.com. - Elegir la ruta pública del módulo Go (propuesta:
datekeys.com/go/datekeys, en minúsculas) y el espejo público, que no puede ser GitHub (por ejemplo Codeberg). Publicar la páginago-importendatekeys.com. Después: renombrar el módulo y poner el tagv0.1.0cuandogo getfuncione desde una máquina limpia. - Decidir si
datekeys-tscierra0.2.0, ahora que la fase 3 está completa.
2.4 Más adelante
Release API sobre la librería, traducción del spec al inglés y revisión externa antes de la v1.0. Opcional: escribir en OPFS en trozos de 1 MiB, que ahorra un 10 % al cifrar ficheros grandes en la página (README de datekeys-ts, «Crear»).
3. Reglas del proyecto
Están en el README de este repo, que el CLAUDE.md de la raíz carga en cada sesión.
4. Documentos
- En este repo están los planes, la revisión del protocolo y los papeles de la v0.9. El README los lista.
- En
datekeys-go:spec/DateKeys_Protocol_Specification_v0.10.md, cerrado con el tagspec-v0.10;spec/DateKeys_Protocol_Specification_v0.9.md, cerrado con el tagspec-v0.9;spec/DateKeys_Protocol_Specification_v0.8.2.md,spec/datekeys.cddlyspec/README.md;testdata/README.md, que documenta los ficheros compartidos para segundas implementaciones;docs/traceability.mdyCHANGELOG.md.
- Las herramientas de verificación de las sesiones del 26 al 28-09 estaban en carpetas temporales y pueden haber desaparecido: el diferencial Go/TypeScript de
tsreview/y las copias congeladasdkgo-ref-<commit>. Su descripción está en los mensajes de los commits dedatekeys-tsy en su README.