|
|
# Handoff DateKeys, 26 de septiembre de 2026 (actualizado el 6 de octubre: las etapas 2 a 5 de Dart, hechas)
|
|
|
|
|
|
Sirve para retomar sin contexto previo, sea una persona o una sesión de Claude. Las secciones 0 a 4, al final, son el historial; el estado actual es este apartado.
|
|
|
|
|
|
**Antes de empezar:** comprueba que la sesión corre en Opus. La del 1-10 por la tarde y noche corrió por descuido con Sonnet 5.5, y hubo que revisarla entera. Los trailers `Co-Authored-By` de los commits dicen qué modelo escribió cada uno.
|
|
|
|
|
|
---
|
|
|
|
|
|
## La segunda sesión del 5 de octubre: etapas 2 a 5 de Dart
|
|
|
|
|
|
Corrió en Opus 5.5, del 5 al 6 de octubre. Se abrió en `App` y a los pocos minutos pasó a la raíz con la herramienta de carpetas de la app, sin cerrarse. Hizo los puntos 1 a 4 de la lista de abajo y, a petición del autor, las etapas 4 y 5 de Dart:
|
|
|
- **Repos:** comprobados; estaban como dice la lista.
|
|
|
- **Dart, etapas 2 y 3**, en paralelo: la 2 en `v0.11` y la 3 en un worktree, integrada encima.
|
|
|
- **`datekeys-go`:** el generador de las tablas de Unicode escribe también una librería de Dart (`internal/pathrule/gen -dart`). Es `c531e93` en `v0.12`, subido con permiso del autor. La salida de TypeScript y `tables.go` no cambian.
|
|
|
- **Dart, etapa 4**, en tres partes: 4a, las rutas, los textos y la llave de palabras; 4b, los formatos; 4c, el head, la nota, la inspección y la apertura de los formatos 1 a 3.
|
|
|
- **Dart, etapa 5**, en tres partes:
|
|
|
- 5a, el lector CMS, ECDSA y RSA;
|
|
|
- 5b, `testdata` en la v0.12, los compromisos, `SECURITY_CBOR`, `alg` 1 y los veredictos;
|
|
|
- 5c, `alg` 2 y `seal_type` 2 en los veredictos.
|
|
|
|
|
|
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. Las revisiones están en [PLAN_dart.md](PLAN_dart.md), al final.
|
|
|
|
|
|
**Estado al cerrar:**
|
|
|
- `datekeys-dart`: rama `v0.11` en `a14a3b8`, limpia, solo en local, sin remoto. El gate pasa con 1 572 pruebas en la VM y 332 en Node.
|
|
|
- La librería Dart ya inspecciona y abre cápsulas de los formatos 1 a 3, también grandes y en streaming, con todas sus credenciales, y evalúa la firma y el sello como Go.
|
|
|
- `testdata` está en `c531e93`, el borrador v0.12 sin aprobar; `specVersion` sigue en 0.11.
|
|
|
- `datekeys-go`: `v0.12` en `c531e93`, subida. `App` no se tocó.
|
|
|
- G: tiene 26 GB libres desde el 5-10, porque el autor liberó unos 24 GB.
|
|
|
|
|
|
**Siguiente:**
|
|
|
1. **Dart, etapa 6:** el escritor, con el formato 3, el área de 32 KiB, `time_only` y `time_and_key`, la llave de palabras y la nota pública. Antes conviene decidir cómo se cifra el stanza tlock sin que el tiempo de `BigInt` revele sigma y r (README de `datekeys-dart`).
|
|
|
2. **Dart, etapa 7:** el localizador y el sobre, y las claves de autor `dkauthor1…` con su fichero cifrado con scrypt.
|
|
|
3. Lo que sigue abierto de la lista de abajo:
|
|
|
- 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;
|
|
|
- las observaciones sin decisión.
|
|
|
4. **Medir en un móvil de gama media,** cuando haya app: BLS12-381, PBKDF2, scrypt y la apertura.
|
|
|
5. **Un posible fallo de dart2js en Dart 3.13,** que encontró el agente de la 4c: un objeto que llega al campo de otro a través de `c ? null : objeto` puede perder sus escrituras. Está documentado en el README de `datekeys-dart`. Reportarlo al equipo de Dart sería publicar fuera: solo con permiso del autor.
|
|
|
|
|
|
## Retomar aquí (al cerrar la sesión del 5 de octubre)
|
|
|
|
|
|
**Para empezar la sesión siguiente.** La del 5-10 se cerró porque tenía el contexto casi lleno.
|
|
|
1. Abre la sesión en `G:\bussines\datekeys`, la raíz, no en `App`, y comprueba que corre en Opus.
|
|
|
2. Comprueba que los repos están como dice este apartado (`git status` y `git log` en cada uno). Todos estaban limpios al cerrar:
|
|
|
- `datekeys-go`: rama `v0.12` en `424cdf3`, subida;
|
|
|
- `App`: rama `v0.10` en `289fe71`, subida;
|
|
|
- `datekeys-dart`: rama `v0.11` en `c8bf3c0`, solo en local;
|
|
|
- `docs`: en el commit de este handoff, solo en local.
|
|
|
3. **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](PLAN_dart.md), apartado «Cómo se hacen las etapas», revisar su resultado y pasar `tool/check.sh`.
|
|
|
4. **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.json` con 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ón `http` y otra de NAT64, que se rechazan, y una tercera que se usa;
|
|
|
- `rest_cases`, `extension_cases`, con el localizador de otra ronda, y `plaintext_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.go` y comprueba cada caso contra Go.
|
|
|
- `e22d358`: `testdata/README.md` al día, y sin marcas *pending* en `docs/traceability.md` ni en el CHANGELOG. El README decía que el release de la ronda 1000 estaba en `quicknet_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 `0x` y 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 `:0443` y `:00443`, y `checkPort` ahora los rechaza.
|
|
|
|
|
|
`locator.json` pasa a 247 direcciones.
|
|
|
- **Verificación:** `scripts/check.sh 60s` completo sobre `e22d358`, y sobre `601e6d2` `check.sh` sin fuzzing y `fuzz.sh 60s`, los 25 objetivos: todo limpio. Cobertura de `capsule`, 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 (`checkWrite` en `extension.ts`, con `NOTE_ID` y `CAPSULE_ID`), que aplican el escritor de cápsulas y el de `.dkk` con los textos de Go; `checkNoteData` y `unusableNote`. Comprobado también contra el `testdata` de `spec-v0.11`.
|
|
|
- `95329ee`, el borrador v0.12, en un solo commit porque nada pasaba por separado:
|
|
|
- `testdata` en `601e6d2`; `SPEC_VERSION` sigue 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.json` y los 135 casos de `security_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 en `inspect`, 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) y `testdata:check` contra Go.
|
|
|
|
|
|
**`datekeys-dart`, rama `v0.11`, solo local (no tiene remoto):**
|
|
|
- `5aa5eed`, etapa 0:
|
|
|
- el paquete `datekeys`, Dart 3.13, sin publicar;
|
|
|
- `testdata` en `spec-v0.11`, 124 ficheros, con el mismo `SOURCE.json` que escribe el TypeScript;
|
|
|
- `tool/sync_testdata.dart`, pruebas de integridad y de versión, y `tool/check.sh` como gate;
|
|
|
- licencia Apache-2.0;
|
|
|
- dependencias: `crypto` en ejecución y `test` en desarrollo, aprobado por el autor el 5-10.
|
|
|
- `da63bc3` a `10b0895`, etapa 1, también de un agente:
|
|
|
- errores del §69;
|
|
|
- bytes: UTF-8 estricto propio, porque el `Utf8Decoder` de Dart quita un U+FEFF inicial; y el `%q` de Go con su tabla `IsPrint`;
|
|
|
- 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 `int` hasta 2^53 − 1 y un `BigInt` por 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**
|
|
|
1. **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`, `SpecVersion` 0.12, el tag `spec-v0.12` y `main` avanzado 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 `givenName` y `surname` solo si los dos tienen texto no vacío, y el emisor toma el `organizationName` si no tiene un `commonName` con texto. Es lo que ya hacían Go y el TypeScript. Está en `424cdf3`, subido.
|
|
|
- **`dart test -p node` en el gate de Dart:** `c8bf3c0`.
|
|
|
2. **Dart, etapa 2:** las primitivas y `age`, según [PLAN_dart.md](PLAN_dart.md). Se encargó el 5-10 y se detuvo sin escribir nada al cerrar la sesión: hay que relanzarla.
|
|
|
3. **Dart, etapa 3:** BLS12-381 y tlock, pedida por el autor para después de la 2.
|
|
|
4. **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.json` y el TypeScript lo copia: cambiarlo exige tocar los dos lados.
|
|
|
- `testdata` no tiene vectores compartidos de la llave de palabras. El §64 de la v0.11 los pide, y solo están en las pruebas de Go (`wordkey.TestKeyVector`). TypeScript y Dart los van a necesitar.
|
|
|
- A G: le quedan 1,5 GB libres.
|
|
|
- Flutter está instalado en `C:\dev\flutter`, y su Dart 3.13.0 es el `dart` del PATH.
|
|
|
- La carpeta sigue llamándose `App`, y `enquiry.php` sigue 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.sh` corre 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](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 rama **`v0.12`**, subida, implementa el borrador v0.12. `main` y el tag `spec-v0.11` siguen en `ae33434`, sin tocar, y `SpecVersion` sigue en 0.11 hasta la aprobación.
|
|
|
- **`App` (`datekeys-ts`):** la rama `v0.10`, subida, con cinco commits nuevos (`06e992f` a `fc5fb24`). Su `testdata` sigue sincronizado con `ae33434` (`spec-v0.11`).
|
|
|
- **`docs`:** local. La revisión está en `d60b856`, los planes de Dart y de la firma en `ac47bf6`, 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, y `ParsePublic` exige 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 -sign` muestra el código; `-expect-author` no 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 `ParseInfo` ata el localizador a su ronda.
|
|
|
- **Lector CMS** (`839e117`, `b06ab4f`):
|
|
|
- un perfil de certificado propio, campo a campo, sin `encoding/asn1` ni `crypto/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 `givenName` y `surname`, delante del CN que lleva el NIF.
|
|
|
- **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 con `TestVectors`), y `-force` ya no rompe (`e597760`);
|
|
|
- `format3_seal_unsupported` usa `seal_type` 4294967295, y hay `format3_unsigned` (32 KiB y la misma P que la firmada), `format3_note`, `security.json` con contexto y líneas (`aaf0f41`), y 8 mutaciones nuevas de `alg` 1, del área y de la nota (`6c78c94`, 218 casos);
|
|
|
- `note.json` (`88ccbfd`);
|
|
|
- `security_cms.json`, que pasa de 22 a 135 casos con sus `lines` (`edff5d1`).
|
|
|
- **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`).
|
|
|
- **Documentación** (`858c5f1`, `2aff4a0`): los README, `SECURITY.md`, `docs/traceability.md` y el CHANGELOG, puestos en la v0.11 y el borrador v0.12.
|
|
|
- **Verificación:** `go test ./...` en verde en `ad40329`. `scripts/check.sh` pasó entero sobre `2aff4a0` (`-race`, cobertura de `capsule` 91,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: `testVectors` y `areaLen` salen del API público y pasan a `testing/`.
|
|
|
- T10: `capsule-vectors.json` regenerado 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: `evaluateSecurity` no lanza nunca, y los lectores de OID son lineales.
|
|
|
- T14: README y CHANGELOG.
|
|
|
|
|
|
**Siguiente, en orden**
|
|
|
1. **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 ` ↳ `;
|
|
|
- `givenName` y `surname` delante del CN;
|
|
|
- la lista de bloques no públicos de IANA y de nombres locales;
|
|
|
- el perfil del certificado;
|
|
|
- `accuracy` hasta 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`, `SpecVersion` 0.12, el tag `spec-v0.12` y `main` avanzado sin fusión, siempre con permiso del autor.
|
|
|
2. **Go, lo que falta:**
|
|
|
- **`locator.json` ampliado:**
|
|
|
- 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.
|
|
|
- **`testdata/README.md`,** que sigue en la v0.10. Debe recoger:
|
|
|
- `security.json` con contexto y líneas;
|
|
|
- `note.json`;
|
|
|
- `format3_unsigned` y `format3_note`;
|
|
|
- las 218 mutaciones;
|
|
|
- `security_cms.json`, con el texto que dejó su agente: está en el informe de su commit `edff5d1` y se puede rehacer leyendo el generador;
|
|
|
- `locator.json`, cuando se amplíe.
|
|
|
- Las marcas *pending* de `docs/traceability.md` y el apartado «Pending in this branch» del CHANGELOG.
|
|
|
- Un `scripts/check.sh 60s` completo.
|
|
|
3. **TypeScript, segunda parte:**
|
|
|
- **Datos:** sincronizar `testdata` con la cabeza de `v0.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, `t` en RFC 3339 con fracción), el titular por `givenName` y `surname`, y las reglas de 64 puntos de código y espacios dobles.
|
|
|
- **Escritor:** la regla de `CheckWrite`.
|
|
|
- **Vectores y fixtures:** `security.json` con su estructura nueva; `note.json`; los fixtures `format3_unsigned` y `format3_note`, y los `ibe-vectors` de los fixtures nuevos o cambiados; las 8 mutaciones; los 135 casos de `security_cms.json` con 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.
|
|
|
4. **Dart:** el plan está en su v2, [PLAN_dart.md](PLAN_dart.md), con las tres decisiones del autor del 2-10: solo `package:crypto`, primero la lectura y paquete `datekeys`.
|
|
|
- Se empieza por la etapa 0, el esqueleto con `testdata` sincronizado. Para la etapa 4, el generador `pathrule/gen` necesita una salida `-dart`.
|
|
|
- La etapa 5, la de firmas y sello, se sincroniza con `v0.12`, no con `spec-v0.11`.
|
|
|
|
|
|
**Para trabajar**
|
|
|
- **Gates:**
|
|
|
- `scripts/check.sh` en `datekeys-go`: los tests con `-race` de `capsule` tardan minutos. Si lo paras, mata también `fuzz.sh` y los procesos `*.test.exe`, que quedan huérfanos.
|
|
|
- `npm run verify` y `npm run testdata:check` en `datekeys-ts`.
|
|
|
- **El generador:**
|
|
|
- `go run ./internal/testkit/genfixtures -out testdata` no 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 `\uXXXX` en caracteres literales; en Go, escribe esos escapes con un script.
|
|
|
- `go test … | tail` esconde el código de salida: mira `$?` antes de hacer commit. Una vez se hizo commit con una prueba rota (`e597760`, arreglada en `0f51af7`).
|
|
|
- **Agentes:** el trabajo en paralelo en Go se hizo con agentes en clones propios del scratchpad y ficheros repartidos, integrados con `git fetch` y `cherry-pick`. Los subagentes, con `model: "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](README.md) de este repo. Los cambios:
|
|
|
- **Documentos:** los del proyecto, este incluido, pasaron de `App/docs` a este repo, `docs`, que es privado y no tiene remoto. Su primer commit es `6e8d6c6`. Los papeles de trabajo de la v0.9, que solo estaban en una carpeta temporal, están en [spec_v0.9/](spec_v0.9/README.md).
|
|
|
- **`App`:** quitó `docs/`, y el paquete, el README y el aviso de licencias del sitio pasan a llamarse `datekeys-ts` (`5ee8813`, subido). `npm run verify` sigue en verde, con 2 611 tests.
|
|
|
- **Archivo y logos:**
|
|
|
- `AppOld` pasó a `archive/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 `App` queda 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.json` para las vistas previas.
|
|
|
- **Nombres:** en las secciones siguientes, `App` es el repo que ahora se llama `datekeys-ts`. Su remoto sigue siendo `go/DateKeys-App`.
|
|
|
|
|
|
Pendiente del autor, antes de seguir:
|
|
|
1. Cerrar la sesión abierta en `App` y renombrar la carpeta a `datekeys-ts`. Windows no deja renombrar una carpeta en uso.
|
|
|
2. Abrir las sesiones siguientes en `G:\bussines\datekeys`. La primera comprueba `npm run verify` y `npm run testdata:check` en `datekeys-ts`.
|
|
|
3. Borrar `G:\bussines\datekeys\enquiry.php`, que es una copia idéntica de `web/static/api/enquiry.php`. Claude no tiene permiso para borrarlo.
|
|
|
4. `docs` y `web` solo 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 60s` sobre `9ac9cd9`, el commit del tag, limpio (28-09), y sobre el estado de `6fa2b54`, 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/grpc` 1.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.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 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 sobre `c57ed48` que absorbe el WIP `69a3342`. 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_UNAVAILABLE` y ningún otro código.
|
|
|
- La regla del encoder no se comprueba en la librería: `capsule.Encrypt` y `accesskey.Encode` no reciben `Registry`, y la aplica la aplicación. Está documentado en `extension.Placement`.
|
|
|
- El autor aprobó el texto el 28-09. El spec lleva esa fecha, y el SHA-256 de sus bytes LF, `5cfa3203…`, está en `spec/README.md` y en el mensaje del tag.
|
|
|
- `main` avanzó por fast-forward hasta `9ac9cd9` y lleva el tag `spec-v0.8.2`. Los dos están subidos.
|
|
|
- `App` sincronizó `testdata` con `9ac9cd9` en `71ab8fb`. Solo cambia `testdata/README.md`.
|
|
|
|
|
|
Las reglas que siguen valiendo (testdata, textos de error y versiones cerradas del spec) están en el [README](README.md#reglas).
|
|
|
|
|
|
### 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-encryption` 0.3.1 y noble 2.4.0 como dependencias de ejecución, con sus guardas en `src/lib/dependencies.test.ts` y `check-build.mjs`. El README de `App` recoge el coste medido en el bundle, 73 KB con gzip para todo, y `npm audit`;
|
|
|
- hecho el 28-09 (`35be27c`): `ibe.ts` sobre noble 2, con vectores de Go en `src/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 al `Stanza` de `age-encryption`, que guarda el tipo en `args[0]`, van al paso 7;
|
|
|
- hecho el 28-09 (`076f3db`): `release.ts`, con `verifyRelease` en el orden y con los textos de `provider.Verify`, `ReleaseSource` y `suppliedRelease`. Solo verifica el scheme de Quicknet: otro da `ERR_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 de `agewrap` se apoyan en `x25519.ts`, que abre los stanzas de uno en uno. Usa `@noble/ciphers` 2.4.0, dependencia directa aprobada ese día: es la copia que ya usa `age-encryption`. Las identidades `AGE-SECRET-KEY-1…` se leen con `bech32.ts`. `index.ts` no reexporta aún la apertura, que metería noble en `/inspect`;
|
|
|
- hecho el 28-09 (`a89bee5`), paso 5b. `open` acepta un `Blob` del que solo lee el prefijo de los pasos 1 a 8 (`prefix.ts`, movido de la página a la librería), calcula el `capsule_digest` en streaming (`digest.ts`) y descifra `PAYLOAD_AGE` en streaming. La salida puede ser un `WritableStream`, 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: `encryptOnG2RFC9380` y `timeRecipient`. Con sigma fijo, el cifrado reproduce byte a byte los vectores de Go. Go abrió los cuerpos IBE y los ficheros `age` que cifró esta librería, con `tlock.TimeUnlock` y con `agewrap.NewTimeIdentity`. Todo está en `src/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`, en `main` de `datekeys-go`), y las dos implementaciones leen el formato 2: Go desde `f24a280`, que también lo escribe, y TypeScript desde `0118890`.
|
|
|
- Paso 6 hecho: la fase 3 está completa en `datekeys-ts` (pasos 0 a 7 del plan, hasta `3a9d2b1`, subido). La librería escribe el formato 2, Go abre lo que escribe y la página `/create` cifra en el navegador. La versión `0.2.0` sigue sin publicar: cerrarla es decisión del autor (§2.3). Después, a petición del autor, `/inspect` muestra el contenido al abrir, debajo del veredicto, y nombra la descarga por su tipo. Las páginas explican las claves de `age`, y la vista previa sirve las páginas sin caché (`da2000a`, `da26862`, subidos).
|
|
|
- Las 22 correcciones del repaso final ([spec_v0.9/review.md](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](PLAN_fase3_escritura.md), el plan del writer TypeScript, y [REVISION_completitud_protocolo.md](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:
|
|
|
1. L es un `bstr` de 8 bytes, no un `uint`.
|
|
|
2. El lector SHOULD informar del formato.
|
|
|
3. Se mantienen el objetivo 8 de §4 y el no objetivo nuevo de §5.
|
|
|
4. Solo un generador de vectores de prueba MAY escribir el formato 1 (§62.1, regla 1, y §70).
|
|
|
5. Los fixtures nuevos llevan el prefijo `format2_`.
|
|
|
6. Se mantiene D1: los señuelos son identidades generadas cuya clave privada se descarta en el acto.
|
|
|
7. Rechazar puntos del twist sigue siendo MAY.
|
|
|
8. 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_key` lleva siempre exactamente 16 stanzas X25519 en `INNER_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_CBOR` versió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 (`VERSION` 2 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_policy` sigue visible.
|
|
|
- D6: nueva sección de privacidad, §55.2.
|
|
|
- D7: reglas normativas del escritor, §62.1:
|
|
|
- `I_PAYLOAD` sale 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`; `EncodeControl` y `DecodeControl` reciben el formato; `Open` aplica los pasos 12 a 18 del formato 2.
|
|
|
- `agewrap`: `AccessSlots` y `CheckX25519Recipient`.
|
|
|
- **Escritura:**
|
|
|
- `Encrypt` escribe solo el formato 2.
|
|
|
- `EncryptOptions.Length` es obligatorio; `Padding` es reforzado por defecto.
|
|
|
- Acepta de 1 a 16 credenciales, con señuelos, orden aleatorio y autocomprobaciones.
|
|
|
- La CLI mide la entrada, acepta `-padding` e 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.
|
|
|
- **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 60s` limpio:**
|
|
|
- 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.md` y `testdata/README.md` están al día.
|
|
|
|
|
|
**Orden de trabajo:**
|
|
|
1. Aplicar y verificar las 22 correcciones. Hecho el 29-09 (`4a025d1`).
|
|
|
2. El autor aprueba el texto de la v0.9. Hecho el 29-09.
|
|
|
3. La referencia Go implementa el formato 2, con fixtures nuevos y mutaciones, y pasa `check.sh`. Hecho el 29-09 (`f24a280`).
|
|
|
4. Se pone el tag `spec-v0.9`. Hecho el 29-09, con la autorización del autor:
|
|
|
- `7e2d83c` anota el SHA-256 del spec en `spec/README.md`, que también va en el mensaje del tag;
|
|
|
- `main` avanzó hasta ese commit sin merge;
|
|
|
- `main`, `v0.9` y el tag están subidos.
|
|
|
5. `datekeys-ts` sincroniza `testdata` y el lector TypeScript abre el formato 2. Hecho el 29-09 (`0118890`, subido):
|
|
|
- `testdata` a `7e2d83c`;
|
|
|
- el prelude lee el formato; `decodeControl` y `encodeControl` reciben el formato; `padding.ts` con las dos reglas, exactas hasta L_MAX;
|
|
|
- `open` exige 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.json` añade los siete fixtures del formato 2, calculados con `scripts/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 un `Blob`.
|
|
|
6. 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](PLAN_fase3_escritura.md) pasó a su v2, sobre las reglas del §62.1:
|
|
|
- 16 huecos con señuelos y orden uniforme;
|
|
|
- relleno `reforzado` por defecto;
|
|
|
- L conocida de antemano;
|
|
|
- autocomprobaciones;
|
|
|
- recipients canónicos y no de orden bajo, como Go;
|
|
|
- `SEALED_CONTROL_LEN` con 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 con `npm run verify` en verde en cada paso:
|
|
|
- paso 0: el autor confirma las 17 decisiones con su recomendación, entre ellas cerrar `0.1.0` ya (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 (`b97dee2` en este repo);
|
|
|
- paso 1: `0.1.0` cerrada (`d577283`, tag `v0.1.0`) y `0.2.0-dev` abierta (`8c08c97`);
|
|
|
- paso 2 (`8838c7d`): `recipient.ts`, `random.ts` y `agefile.ts`, y las guardas nuevas;
|
|
|
- pasos 3 y 4 (`8473fdf`): `encrypt.ts` y `writer.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 en `src/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_only` por 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`, con `lengths.ts` (el tamaño del `.dkc` antes de escribirlo), `localtime.ts`, `create-input.ts` y `creator.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 con `datekeys decrypt` de 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 `.dkk` que es la única credencial se podía borrar sin confirmación.
|
|
|
|
|
|
- después, a petición del autor (`da2000a`): `/inspect` muestra 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 de `age`: qué es un destinatario `age1…`, cómo se consigue con `age-keygen` y qué se pega al abrir.
|
|
|
|
|
|
**Siguiente:** que el autor decida si cierra `0.2.0` (tag `v0.2.0` en `datekeys-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`, como `security | 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.
|
|
|
- Un flujo de diseño con revisión adversarial produjo [spec_v0.10/formato3_diseno.md](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](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.protectHFS` incluye 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 `security` va 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_commit` y `head_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.
|
|
|
- **Decisiones del autor del 30-09 sobre la revisión:**
|
|
|
1. **Tres entregas,** con el formato congelado desde la primera y `security` presente 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.
|
|
|
2. **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 cabeceras `nosniff` y `CSP: sandbox` de todos modos.
|
|
|
- La CSP de `/create` añade ese origen a `connect-src`, solo en esa página.
|
|
|
- Es de la entrega 3 y se puede revisar entonces.
|
|
|
3. **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 de `security` con un área fija mayor.
|
|
|
4. **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](spec_v0.10/formato3_diseno.md) es la única fuente del diseño. Se borraron `formato3_revision_intro.md` y `formato3_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 `security` van 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 `security` con un área fija mayor». El diseño hace que el área la fije la versión del spec y deja el mapa `security` en 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.
|
|
|
- **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`, rama `v0.10`, sin subir: `fa7f95e` lo redacta y `9d1cd2e` aplica la revisión final. Lleva el spec, el CDDL y `spec/README.md`. La referencia sigue implementando la v0.9, y su `SpecVersion` no 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](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 `alg` futuro puede definir una lista de firmas sin cambiar el formato (pregunta 3 de la entrega 2 del diseño).
|
|
|
- **Siguiente:**
|
|
|
1. 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.
|
|
|
2. Hecho: el autor aprobó la regla de invisibles («sí a las dos»), que el spec recoge en R4b y en §29.6 (`631d09c`).
|
|
|
3. Hecho: con su permiso se descargaron los 19 ficheros de datos, 8,25 MB, en `datekeys-go/.cache/`, fuera de git.
|
|
|
4. Hecho: la referencia Go implementa el formato 3, con el [plan](PLAN_formato3_go.md) y el detalle de abajo. Con la autorización del autor («sí, sube la rama y pon el tag»), la rama `v0.10` y el tag anotado `spec-v0.10` están en el remoto, en `cc35d2c`, que solo cambia textos para nombrar el tag. Después, a petición suya («sí, avanza main hasta la v0.10»), `main` avanzó hasta `cc35d2c` sin fusión y está subida.
|
|
|
5. **En curso:** `datekeys-ts` lee y escribe el formato 3 con su [plan](PLAN_formato3_ts.md). En la rama `v0.10` de `App`, 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 con `testdata` en `spec-v0.10`) y el paso 4 (de `3daa1f7` a `2efc8bc`: `encryptFiles`, `encrypt` solo con `testVectors`, `/create` en formato 3 con un fichero, y la interoperabilidad con Go). El paso 5, el ZIP y el sumidero de la página, está en `ee82f43`, el paso 6, la página `/inspect` con los ficheros del formato 3, en `651178a`, y el paso 7, la página `/create` con ficheros, carpetas, rutas editables, comentario y autor, en `7dc88ef`. El paso 8 está hecho (`7527c35`, `57e0a8a`, `e6cca0b` y el CHANGELOG): README, `testdata:check` contra `cc35d2c`, tres revisiones adversariales con subagentes y sus correcciones, y, a petición del autor, `/create` rediseñado (una carta al futuro, sobre de correo aéreo, fuentes del sistema) y el sitio siempre claro. Pendiente, sin urgencia:
|
|
|
- `/inspect` solo 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-encryption` retiene 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 `TypeError` sin sumidero llega tras los pasos 3 a 8 con un `Blob`; `tempfile.remove()` marca borrado antes de lograrlo; `measureFiles` en cada tecla con 65 535 ficheros; un bundle `.app` no avisa (igual que la CLI).
|
|
|
- Subido el 01-10 por la noche, con permiso del autor: la rama `v0.10` de `App`, y `main` y `v0.11` de `datekeys-go`.
|
|
|
6. 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 `/inspect` pueda 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/pathrule` con las tablas de Unicode 18.0.0 y best-fit generadas y su `TablesDigest`; `72e86b8`, paso 2, el códec de `BODY`, `security` y el head.
|
|
|
- `7249ef4`, paso 3, el lector: `capsule.Sink`, `ErrSinkRequired` justo tras el paso 2, el paso 17 en subpasos con su precedencia, y lecturas de `BODY` que crecen con los bytes recibidos (§57).
|
|
|
- `8955c0f`, paso 4, el escritor `capsule.EncryptFiles`, que lee cada fichero dos veces; `Encrypt` solo escribe el formato 2 con `EncryptOptions.TestVectors`.
|
|
|
- `a0de80f`, paso 5, el CLI: `encrypt -in` con ficheros y carpetas, `-comment`, `-author` y `-no-mtime`; `decrypt -out CARPETA` con `os.Root`; la presentación de §29.7, con el ancho del terminal pedido por `syscall`, sin dependencias nuevas.
|
|
|
- Paso 6, datos de prueba: `3c39336` (`SpecVersion` 0.10 y `ERR_HEAD_INVALID`), `e070f89` (las nueve fixtures), `db862d5` (`paths.json`, `path_fold.json`, `head_schema.json`, `security.json` y el control de versión 3 en `cbor.json`) y `18eb3c3` (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 en `spec/README.md`.
|
|
|
- Verificación: `go test ./...` y `scripts/check.sh 60s` limpios, cobertura de `capsule` 93,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.md` es 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.
|
|
|
- Para `datekeys-ts`:
|
|
|
- hecho: el generador escribe el módulo TypeScript con la bandera `-ts` (`13910b3`, en `main` de `datekeys-go`, un commit por delante de `origin/main` y sin subir), y el digest recalculado en TypeScript coincide con `TablesDigest`;
|
|
|
- `testdata` cambia entero de `"spec"`, y añade nueve fixtures, cuatro ficheros de vectores, `mutations.json` con 209 casos (`version changed` pone ahora `VERSION` 4, y hay casos con `verdicts`) y el diferencial con 5 110;
|
|
|
- los textos de las reglas de rutas y de texto deben coincidir byte a byte: `paths.json` y `head_schema.json` los traen en `result` y `detail`.
|
|
|
- Herramientas: en esta máquina los heredocs de Bash rompen apóstrofos y barras invertidas, y la herramienta Write convierte `\uXXXX` en 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 `.dkc` completo, guardado aparte.
|
|
|
- Un fichero único `.dk` con `.dkc` y `.dkk` juntos no conviene: con `time_and_key` equivaldría a `time_only`. Ya se envía un solo fichero con `time_only` o con destinatarios `age1…`.
|
|
|
- `datekeys-ts` cerró `0.1.0` el 29-09 (`d577283`, tag `v0.1.0`), y la fase 3 va en `0.2.0-dev`.
|
|
|
|
|
|
### 2.3 Depende del autor
|
|
|
|
|
|
- Crear `security@datekeys.com` y, si se quiere, un `security.txt` en la web. Después, actualizar `SECURITY.md`, que hoy dice `info@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ágina `go-import` en `datekeys.com`. Después: renombrar el módulo y poner el tag `v0.1.0` cuando `go get` funcione desde una máquina limpia.
|
|
|
- Decidir si `datekeys-ts` cierra `0.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](README.md#reglas) 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](README.md#documentos) los lista.
|
|
|
- En `datekeys-go`:
|
|
|
- `spec/DateKeys_Protocol_Specification_v0.10.md`, cerrado con el tag `spec-v0.10`; `spec/DateKeys_Protocol_Specification_v0.9.md`, cerrado con el tag `spec-v0.9`; `spec/DateKeys_Protocol_Specification_v0.8.2.md`, `spec/datekeys.cddl` y `spec/README.md`;
|
|
|
- `testdata/README.md`, que documenta los ficheros compartidos para segundas implementaciones;
|
|
|
- `docs/traceability.md` y `CHANGELOG.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 congeladas `dkgo-ref-<commit>`. Su descripción está en los mensajes de los commits de `datekeys-ts` y en su README.
|