Spec v0.15 approved: handoff, README and the review package

The review package now freezes spec v0.15 (fe50885), TypeScript 0.4.0
(7650418) and Dart faa2c4c, with the gates and the fuzz run of 7 October.
The recovery design and the v0.15 decisions get a note: the .dkr file was
dropped before approval.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main
dev 19 hours ago
parent 0a654871f3
commit 56a2edb970

@ -1,6 +1,6 @@
# Handoff DateKeys
*Estado al 6 de octubre de 2026 por la noche. Lo que pasó hasta aquí, sesión a sesión, está en [HANDOFF_historial.md](HANDOFF_historial.md).*
*Estado al 7 de octubre de 2026. Lo que pasó hasta aquí, sesión a sesión, está en [HANDOFF_historial.md](HANDOFF_historial.md).*
Sirve para retomar sin contexto previo, sea una persona o una sesión de Claude.
@ -15,29 +15,31 @@ Sirve para retomar sin contexto previo, sea una persona o una sesión de Claude.
| Repo | Rama y commit | Tags | Qué es |
|---|---|---|---|
| `datekeys-go` | `v0.14` en `22f184c`; `main` en `39b2033` | `spec-v0.14` en `39b2033`, y los de las versiones anteriores | Spec v0.14 aprobada, implementación de referencia, `testdata` compartido |
| `App` (`datekeys-ts`) | `v0.10` y `main` en `3abd7bf` | `v0.3.0` en `3abd7bf`, `v0.2.0`, `v0.1.0` | Librería TypeScript 0.3.0, de la spec 0.14, y páginas `/inspect` y `/create` |
| `datekeys-dart` | `v0.14` en `013b069` | ninguno | Librería Dart completa, de la spec 0.14; las ramas `v0.11` a `v0.13` se quedan atrás |
| `datekeys-go` | `v0.15` y `main` en `fe50885` | `spec-v0.15` en `fe50885`, y los de las versiones anteriores | Spec v0.15 aprobada, implementación de referencia, `testdata` compartido |
| `App` (`datekeys-ts`) | `v0.10` y `main` en `7650418` | `v0.4.0` en `7650418`, `v0.3.0`, `v0.2.0`, `v0.1.0` | Librería TypeScript 0.4.0, de la spec 0.15, y páginas `/inspect` y `/create` |
| `datekeys-dart` | `v0.15` en `faa2c4c` | ninguno | Librería Dart completa, de la spec 0.15; las ramas `v0.11` a `v0.14` se quedan atrás |
| `docs` | `main` | — | Este repo |
| `web` | `main` en `f2b8a38` | — | Landing de datekeys.com, sin remoto |
- **Spec:** la v0.14 está aprobada desde el 6-10, con SHA-256 `390922135931dd61a263ed90259c7a978b5d92944405e641e94cc194f84fb459`. No hay ningún borrador abierto. Las versiones aprobadas y sus SHA-256 están en `datekeys-go/spec/README.md`.
- **Las tres implementaciones** coinciden en todos los vectores compartidos de `datekeys-go/testdata` en `39b2033`, 136 ficheros. Gates el 6-10:
- Go: `scripts/check.sh` entero, y `scripts/fuzz.sh 20s` en `39b2033` con sus 26 objetivos;
- TypeScript: `npm run verify` en `3abd7bf`, con 8 030 pruebas;
- Dart: `tool/check.sh` en `013b069`, con 2 193 pruebas en la VM y 681 en Node.
- **La revisión externa:** el paquete está listo en [revision_externa/](revision_externa/NOTA_PARA_EL_AUTOR.md), con commits congelados (`39b2033`, `22f184c` para la documentación de Go, `3abd7bf` y `013b069`). Su nota dice qué decidió el autor y qué falta: elegir revisor, alcance y presupuesto, el NDA, los bundles y el envío.
- **Spec:** la v0.15 está aprobada desde el 7-10, con SHA-256 `45105e693be4187af4dd30f4d254402612587b6427c746f5d29f07a541c1e3f3`. Es la recuperación a largo plazo: el objeto release, los archivos y servicios de caché que guardan todas las rondas, el release en la mano en el paso 9.c (opción B: no se compara con el reloj) y el anexo de recuperación del §79. No cambia ningún formato de `.dkc` ni de `.dkk`. No hay ningún borrador abierto. Las versiones aprobadas y sus SHA-256 están en `datekeys-go/spec/README.md`.
- **El fichero `.dkr` se descartó** antes de aprobar (7-10). El autor no lo había aprobado conscientemente, y no tiene sentido: al crear la cápsula no hay release que guardar, y cuando llega la ronda la cápsula ya se abre. El objeto release no tiene extensión propia; sale de un archivo o de un servicio de caché. El §76 lo registra.
- **Las tres implementaciones** coinciden en todos los vectores compartidos de `datekeys-go/testdata` en `fe50885`, 142 ficheros. Gates el 7-10:
- Go: `scripts/check.sh` entero en `fe50885`, con el anexo de recuperación abriendo fixtures sin código de DateKeys, y `scripts/fuzz.sh 20s` en `fe50885` con sus 27 objetivos, sin fallos;
- TypeScript: `npm run verify` en `7650418`, con 8 106 pruebas;
- Dart: `tool/check.sh` en `faa2c4c`, con 2 211 pruebas en la VM y 694 en Node.
- **La revisión externa:** el paquete de [revision_externa/](revision_externa/NOTA_PARA_EL_AUTOR.md) está al día con la v0.15. Su nota dice qué decidió el autor y qué falta: elegir revisor, alcance y presupuesto, el NDA, los bundles y el envío.
---
## Qué queda
En el orden que recomendó la sesión del 6-10 y aceptó el autor: este HANDOFF, después la recuperación a largo plazo y después las recomendaciones de la v0.14 en los clientes.
La recuperación a largo plazo quedó hecha con la v0.15 (7-10). Lo siguiente que recomendó la sesión del 6-10 son las recomendaciones de la v0.14 en los clientes.
### Protocolo
1. **La revisión externa.** El paquete está listo; lo que falta es del autor. Al recibir el informe, se abre la versión siguiente con sus hallazgos, el párrafo de idioma y precedencia del final del §1, las etiquetas del §76 que hoy llaman independientes a revisiones de IA, y el registro de la revisión (§75, punto 10). Todo eso lo aprobó el autor el 6-10; ver [revision_externa/precedence_and_language.md](revision_externa/precedence_and_language.md).
2. **La recuperación a largo plazo.** Es lo más grave que queda abierto: una cápsula a veinte años depende de que alguien conserve el release de su ronda. El §74 lo deja como trabajo futuro: un objeto de release, su fuente de archivo y el uso del reloj local en el paso 9.c. El diseño está en [diseno_recuperacion.md](diseno_recuperacion.md); el autor eligió la opción A y sus ocho recomendaciones (6-10). El borrador v0.15 está en la rama `v0.15` de Go (`b7402bd`), sin aprobar, con sus decisiones en [spec_v0.15/decisiones.md](spec_v0.15/decisiones.md).
Con ellos, dos retoques editoriales que el texto no puede llevar tras su tag: los de K17 del paquete (la cabecera «prevista», el §1 con la Release API y la Release Cache, el punto y coma del §74), y el §79, que nombra solo `drand/kyber-bls12381` cuando `scripts/recovery` usa también las interfaces de `drand/kyber`.
2. **Un archivo o servicio de caché de releases** (§50). El protocolo ya lo admite y las librerías leen un archivo local, pero nadie aloja uno todavía. Es decisión del autor: dónde, quién lo mantiene y si DateKeys ofrece el suyo.
3. **Medir el área de 32 KiB y cerrar el perfil CMS** (§74; §75, punto 13), con firmas reales con certificado de varios países y sellos de autoridades reales. Necesita firmas del autor o permiso para pedir sellos a una autoridad pública.
4. **Lo que el §74 aún llama provisional:** los esquemas de bytes de la cabecera, el control y la `.dkk`, los límites de los campos y los vectores definitivos del perfil. Conviene congelarlo con el informe de la revisión delante.
5. **El registro de perfiles firmado** (§71), que no existe.
@ -45,10 +47,11 @@ En el orden que recomendó la sesión del 6-10 y aceptó el autor: este HANDOFF,
### Librerías y clientes
- **Las recomendaciones de la v0.14 al SDK oficial**, que no aplican ni `/create` ni la CLI de Go:
- **Las recomendaciones de la v0.14 y la v0.15 al SDK oficial**, que no aplican ni `/create` ni la CLI de Go:
- recomendar `time_and_key` para horizontes largos (§7.6);
- ofrecer por defecto palabras al azar (§38.1). El autor tiene que elegir la lista: cuál, en qué idioma y con qué licencia;
- avisar del estado de un perfil (§71).
- avisar del estado de un perfil (§71);
- explicar al crear cómo se abrirá la cápsula dentro de veinte años: el anexo de recuperación (§79) y los archivos de releases (§50).
- **La página web, cuando se publique** (§59): builds reproducibles con sus hashes, Subresource Integrity y un cliente sin conexión.
- **El localizador en las páginas:** las tres librerías lo tienen, pero `/create` no crea sobres e `/inspect` no descarga el resto.
- **Go no tiene ninguna release del módulo**; la primera, cuando haya un repo accesible desde fuera para `go get`. govulncheck avisa de GO-2026-6443 en grpc, que el código no alcanza: subir grpc cuando salga la 1.85.0.
@ -69,7 +72,8 @@ En el orden que recomendó la sesión del 6-10 y aceptó el autor: este HANDOFF,
- dos niveles de alcance, con presupuesto cerrado por nivel;
- código entero en bundles de git cifrados con `age`;
- un NDA mutuo;
- la v0.15, después del informe.
- la versión siguiente, después del informe. La v0.15 se adelantó a petición del autor (7-10).
- **Sin fichero `.dkr`** (7-10): el objeto release no se guarda junto a la cápsula ni tiene extensión propia.
- **`locator.Open` sigue leyendo como mucho 1 MiB** del localizador (6-10).
- **El cifrado tlock queda en `BigInt`, sin tiempo constante**, documentado en Dart y TypeScript («continúa», 6-10).
- **El reporte del posible fallo de dart2js** al equipo de Dart, solo con permiso del autor. Está documentado en el README de `datekeys-dart`.
@ -87,7 +91,7 @@ En el orden que recomendó la sesión del 6-10 y aceptó el autor: este HANDOFF,
```
y después `git -C <repo> update-ref refs/remotes/origin/<rama> <rama>`. Los remotos son `go/DateKeys`, `go/DateKeys-App`, `go/dateKeys-dart` y `go/datekeys-doc`. El servidor no es del autor: no se propone ningún cambio en él.
- **Cerrar una versión del spec**, como la v0.12, la v0.13 y la v0.14:
- **Cerrar una versión del spec**, como la v0.12 a la v0.15:
1. en Go, la cabecera del spec con «aprobado por su autor ese día» y nada más del texto;
2. `SpecVersion`;
3. `go run ./internal/testkit/genfixtures -out testdata`, y el campo `spec` a mano en los dos congelados, `security_cms.json` y `locator.json`;
@ -119,4 +123,4 @@ En el orden que recomendó la sesión del 6-10 y aceptó el autor: este HANDOFF,
El [README](README.md#documentos) los lista. Para retomar, lo principal es:
- [revision_externa/](revision_externa/NOTA_PARA_EL_AUTOR.md): el paquete y su nota;
- [REVISION_completitud_v0.13.md](REVISION_completitud_v0.13.md): qué falta antes de la v1.0;
- [spec_v0.14/decisiones.md](spec_v0.14/decisiones.md): las decisiones de la última versión.
- [spec_v0.15/decisiones.md](spec_v0.15/decisiones.md): las decisiones de la última versión, y [diseno_recuperacion.md](diseno_recuperacion.md), su diseño.

@ -11,8 +11,8 @@ Para retomar el trabajo, lee [HANDOFF.md](HANDOFF.md): el estado de cada repo, l
| Carpeta | Qué es | Remoto |
|---|---|---|
| `datekeys-go/` | Especificación del protocolo (`spec/`), CDDL, testdata compartido e implementación de referencia en Go: librería y CLI | `go/DateKeys` |
| `datekeys-ts/` | Implementación en TypeScript y páginas `/inspect` y `/create`; la carpeta sigue llamándose `App`. Versión `0.2.0` (tag `v0.2.0`), de la especificación 0.13 | `go/DateKeys-App` |
| `datekeys-dart/` | Librería Dart para la app Flutter, según [PLAN_dart.md](PLAN_dart.md). Rama `v0.12`: todas las etapas hechas, de la 0 a la 7, con `testdata/` en el tag `spec-v0.12`. La app Flutter está archivada desde el 6-10 | `go/dateKeys-dart`, desde el 6-10 |
| `datekeys-ts/` | Implementación en TypeScript y páginas `/inspect` y `/create`; la carpeta sigue llamándose `App`. Versión `0.4.0` (tag `v0.4.0`), de la especificación 0.15 | `go/DateKeys-App` |
| `datekeys-dart/` | Librería Dart para la app Flutter, según [PLAN_dart.md](PLAN_dart.md). Rama `v0.15`: todas las etapas hechas, de la 0 a la 7, con `testdata/` en el tag `spec-v0.15`. La app Flutter está archivada desde el 6-10 | `go/dateKeys-dart`, desde el 6-10 |
| `web/` | Landing de datekeys.com, con `api/enquiry.php` | ninguno |
| `docs/` | Este repositorio | `go/datekeys-doc`, desde el 6-10 |
| `brand/` | Logos | no es un repo |
@ -49,8 +49,8 @@ Para retomar el trabajo, lee [HANDOFF.md](HANDOFF.md): el estado de cada repo, l
| [REVISION_completitud_v0.13.md](REVISION_completitud_v0.13.md) | La misma revisión contra la v0.13 (6-10): qué está hecho, los huecos nuevos y los tres pasos siguientes antes de la v1.0 |
| [spec_v0.14/](spec_v0.14/decisiones.md) | El borrador v0.14: las [decisiones para el autor](spec_v0.14/decisiones.md), con su recomendación |
| [revision_externa/](revision_externa/NOTA_PARA_EL_AUTOR.md) | El paquete para una revisión criptográfica externa, en inglés, con una [nota para el autor](revision_externa/NOTA_PARA_EL_AUTOR.md) |
| [diseno_recuperacion.md](diseno_recuperacion.md) | Diseño de la recuperación a largo plazo: el objeto de release `.dkr`, el reloj del paso 9.c, el archivo de releases y el anexo de recuperación, con las decisiones para el autor |
| [spec_v0.15/](spec_v0.15/decisiones.md) | El borrador v0.15, la recuperación a largo plazo: las [decisiones para el autor](spec_v0.15/decisiones.md) |
| [diseno_recuperacion.md](diseno_recuperacion.md) | Diseño de la recuperación a largo plazo: el objeto de release, el reloj del paso 9.c, el archivo de releases y el anexo de recuperación, con las decisiones para el autor. Su fichero `.dkr` se descartó al aprobar la v0.15 |
| [spec_v0.15/](spec_v0.15/decisiones.md) | La v0.15, aprobada el 7-10, la recuperación a largo plazo: las [decisiones del autor](spec_v0.15/decisiones.md), sin el fichero `.dkr`, que se descartó |
| [spec_v0.9/](spec_v0.9/README.md) | Papeles de trabajo del borrador v0.9: diseño, revisiones y correcciones pendientes |
| [spec_v0.10/](spec_v0.10/formato3_diseno.md) | Formato de cápsula 3 en diseño, en tres entregas: varios ficheros, firma de autor y sello de tiempo. El diseño, con sus revisiones incorporadas, la revisión de Fable y la revisión final del borrador del spec |
| [spec_v0.11/](spec_v0.11/llave_palabras.md) | Papeles de trabajo de la v0.11, ya etiquetada. Contiene: <br>la [llave de palabras](spec_v0.11/llave_palabras.md); <br>la [consulta a Fable y Astra sobre el tamaño del área de firmas y sellos](spec_v0.11/area_firmas_para_revision.md) y [su propuesta](spec_v0.11/revision_fable_astra.md); <br>la [revisión del borrador](spec_v0.11/revision_borrador.md); <br>la [revisión de lo hecho en la sesión del 1 y 2 de octubre](spec_v0.11/revision_sesion_1_2_octubre.md), con los fallos pendientes de arreglar |

@ -2,6 +2,8 @@
Propuesta para cerrar los dos puntos que §74 de la v0.14 deja como trabajo futuro: «el formato de un objeto de release y de su fuente de archivo» y «el uso del reloj local en el paso 9.c de §63». Recoge el punto 6 de [REVISION_completitud_protocolo.md](REVISION_completitud_protocolo.md) y el 2.6 de [REVISION_completitud_v0.13.md](REVISION_completitud_v0.13.md). No cambia nada todavía: la v0.14 está cerrada, así que todo lo de aquí iría a una v0.15.
> **Nota del 7-10.** La v0.15 aprobada no sigue este diseño en un punto: **el fichero `.dkr` se descartó**. El autor no lo había aprobado conscientemente, y guardarlo junto a la cápsula no tiene sentido: al crearla no hay release que guardar, y cuando llega la ronda la cápsula ya se abre. El objeto release se queda, sin extensión propia, y sale de archivos y servicios de caché que guardan todas las rondas (§50). Lo que aquí se dice del `.dkr` es historia; lo vigente está en la spec v0.15 y en [spec_v0.15/decisiones.md](spec_v0.15/decisiones.md).
## 1. El problema
Una cápsula de Quicknet se abre con el release de su ronda: la firma BLS de 48 bytes que drand publica en `round_time` (§15, §63 paso 10). Sin ese release no hay apertura, ni en `time_only` ni en `time_and_key` (§7.6). El `.dkc` no lo contiene y el protocolo no lo guarda (§6, §50).

@ -1,6 +1,16 @@
# Nota para el autor: el paquete de la revisión externa
*6 de octubre de 2026. En el repo `docs`, corregida el mismo día con una revisión del paquete y con tus decisiones.*
*6 de octubre de 2026, corregida ese día con una revisión del paquete y con tus decisiones. Puesta al día el 7 de octubre de 2026: el paquete congela ahora la especificación v0.15.*
## Qué congela
El paquete congelaba la v0.14. Desde el 7-10 congela:
- **Especificación v0.15**, aprobada el 7-10: tag `spec-v0.15`, commit `fe50885` de `datekeys-go` (también la cabeza de la rama `v0.15` y de `main`). SHA-256 del texto `45105e69…e3f3`, y del CDDL, que gana la regla `release`, `63565d5e…19b5`. La documentación de Go que arregló `22f184c` está dentro de `fe50885`: un solo commit congelado para Go.
- **TypeScript 0.4.0**: tag `v0.4.0`, commit `7650418`, con `testdata` en `fe50885`.
- **Dart**: rama `v0.15`, commit `faa2c4c`, sin tag, con `testdata` en `fe50885`.
La v0.15 es la recuperación a largo plazo, y el paquete la cuenta: el objeto release (§47.1), el release en la mano y el paso 9.c (§49, §63), los archivos y servicios de caché de todas las rondas (§50), las reglas 26 y 27 de §62.1 y el anexo de recuperación sin software de DateKeys (§79). Q12 pasa a preguntar por ese diseño, y de K3 queda solo lo que la v0.15 no cierra: no hay ningún archivo ni servicio alojado.
## Qué contiene
@ -9,18 +19,19 @@ En inglés, porque el revisor puede no leer español:
| Fichero | Para qué |
|---|---|
| `README.md` | La carta: qué es DateKeys, qué se pide, qué se entrega, qué queda congelado y que todas las revisiones hasta hoy son de IA |
| `design_overview.md` | El diseño criptográfico, autocontenido y con sus §, para leer en una hora |
| `threat_model.md` | Objetivos, no objetivos y modelo de amenazas (§4, §5, §7, §36.1, §55), con lo nuevo de la v0.14 |
| `design_overview.md` | El diseño criptográfico, autocontenido y con sus §, para leer en una hora; la sección 8, nueva, es el objeto release y la recuperación |
| `threat_model.md` | Objetivos, no objetivos y modelo de amenazas (§4, §5, §7, §36.1, §55), con lo nuevo de la v0.14 y de la v0.15: la recuperación tras la fecha (§7.6, §50) y el reloj local (4.11) |
| `scope_and_questions.md` | Alcance, 12 preguntas ordenadas y 17 problemas ya conocidos (K1 a K17), para que no se redescubran |
| `artifacts.md` | Repos, commits, cómo pasar los gates, los vectores uno a uno, las dependencias con versión y la trazabilidad |
| `artifacts.md` | Repos, commits, cómo pasar los gates, los vectores uno a uno, los 27 objetivos de fuzzing, las dependencias con versión y la trazabilidad |
| `precedence_and_language.md` | **Propuesta**: español normativo, precedencia texto > CDDL > testdata > implementación, y los cambios de texto para la próxima versión |
## Tus decisiones (6-10)
1. **Idioma y precedencia: aprobada la propuesta**, con dos cambios: un párrafo al final de §1, no un §0, para no descolocar la numeración; y la regla 4 sin «vectores disputados». Una discrepancia es un defecto, decide el texto, se anota en el HANDOFF y se corrige en la versión siguiente con su caso en §76; hasta entonces los vectores no se tocan, porque los gates no lo permiten. Entre implementaciones, la de referencia primero, como dicen §16 y §67. Si el inglés pasa a normativo se decide en la v1.0.
2. **Las etiquetas del §76: la v0.15 no se abre ahora.** La carta ya declara que todas las revisiones anteriores son de IA. El texto corregido, con la precedencia y el registro de la revisión externa (§75, punto 10), va en la versión que se abra con los hallazgos del revisor. Así se evita un ciclo de tres repos antes de enviar.
3. **TypeScript: la `0.3.0`, cerrada el 6-10** en `3abd7bf`, sobre `4e23f88`, con el tag `v0.3.0` y `main` avanzado; ese commit está en la tabla congelada de la carta y en `artifacts.md`. No es estética: `v0.2.0` tiene el `testdata` en `spec-v0.13` y no tiene la prueba de `tlock_steps.json`, así que el revisor no podría pasar el TypeScript contra los vectores congelados. Renombrar la carpeta `App` no hace falta: el revisor ve el nombre del bundle.
4. **Traducción: primero, buscar un revisor que lea español.** Elimina la decisión y el trabajo de contrastar cada hallazgo con el texto normativo. Si no lo hay, traducir solo el núcleo normativo, con un borrador de IA y tu revisión: §4 a §7, §10 a §13, §26 a §44.1, §51 a §57, §62.1, §63 y §69 a §72, unas 30 600 palabras de las 52 600 del texto. El resto lo cubre `design_overview.md`, y §76 se resume en una página. La carta dice que toda traducción es informativa y que tú contrastas cada hallazgo con el texto español: ese trabajo es tuyo.
2. **Las etiquetas del §76 no abren versión.** La carta ya declara que todas las revisiones anteriores son de IA. El texto corregido, con la precedencia y el registro de la revisión externa (§75, punto 10), va en la versión que se abra con los hallazgos del revisor. La v0.15 se abrió después para la recuperación a largo plazo y no los lleva: irán en la v0.16 o la que siga al informe.
3. **TypeScript: una versión cerrada con el `testdata` congelado.** El 6-10 fue la `0.3.0` (`3abd7bf`); desde el 7-10 es la `0.4.0`, en `7650418`, con el tag `v0.4.0`, que implementa la 0.15. El motivo sigue: el revisor tiene que poder pasar el TypeScript contra los mismos vectores que la referencia. Renombrar la carpeta `App` no hace falta: el revisor ve el nombre del bundle.
4. **Traducción: primero, buscar un revisor que lea español.** Elimina la decisión y el trabajo de contrastar cada hallazgo con el texto normativo. Si no lo hay, traducir solo el núcleo normativo, con un borrador de IA y tu revisión: §4 a §7, §10 a §13, §26 a §44.1, §51 a §57, §62.1, §63 y §69 a §72. En la v0.15 son unas 31 300 palabras de las 58 300 del texto (en la v0.14, 30 600 de 52 600). El resto lo cubre `design_overview.md`, y §76 se resume en una página. La carta dice que toda traducción es informativa y que tú contrastas cada hallazgo con el texto español: ese trabajo es tuyo.
- Para decidir: esa lista no incluye §47.1, §49 y §50, el objeto release, las fuentes y los archivos, unas 1 500 palabras más, sobre los que pregunta Q12. Hoy los cubre la sección 8 de `design_overview.md`. El anexo §79 (unas 1 700) es informativo.
5. **Revisor y alcance: dos niveles, con presupuesto cerrado por nivel.**
- Nivel 1, obligatorio: el protocolo y el Go de referencia como evidencia, con Q1 a Q4, Q6 a Q8 y Q10 a Q12.
- Nivel 2, aparte u opcional: Q5 y Q9, el lector CMS/X.509/RFC 3161 y las reglas del localizador, que son revisión de parsers y piden otro perfil.
@ -28,25 +39,26 @@ En inglés, porque el revisor puede no leer español:
El paquete sirve tal cual como pliego para pedir precio. Una opción gratuita antes de pagar: enseñar Q1 y Q10 al equipo de drand, que son preguntas sobre su propio IBE. Es decisión tuya, porque supone enseñar el proyecto fuera.
6. **Qué se comparte y cómo.**
- `git bundle` de los tres repos con todo el historial y los tags, porque §76 cita commits y el `testdata` de TypeScript apuntaba a `spec-v0.13`; y un `.tar` de cada árbol en el commit congelado, con su SHA-256, para quien no quiera bundles.
- `git bundle` de los tres repos con todo el historial y los tags, porque §76 cita commits; y un `.tar` de cada árbol en el commit congelado, con su SHA-256, para quien no quiera bundles. Dart no tiene tag: el bundle lleva la rama `v0.15`, y el `.tar` se hace en `faa2c4c`.
- El código entero: sin él no puede decir dónde discrepa la implementación ni pasar los gates.
- El repo `docs`, no. Si el revisor lee español, los cinco ficheros que cita `artifacts.md` §6, en una carpeta aparte; si no, se quitan esas referencias.
- El repo `docs`, no. Si el revisor lee español, los siete ficheros que cita `artifacts.md` §6, en una carpeta aparte; si no, se quitan esas referencias. `spec_v0.15/decisiones.md` y `diseno_recuperacion.md` describen el fichero `.dkr` que quitaste antes de aprobar, con una nota al principio que lo dice; el spec lo da por descartado (§76, v0.15, cambio 4).
- Un NDA mutuo simple hasta la publicación, y en el encargo, el consentimiento para nombrarle en §76.
- La entrega, cifrada con `age` a la clave pública del revisor, con el SHA-256 del archivo por otro canal. El contacto de la revisión es tu dirección directa; `info@` queda como contacto de seguridad del repo.
### Documentación atrasada: arreglada
### Documentación de Go
La sesión corrigió el 6-10 lo que el paquete encontró atrasado en `datekeys-go`, en `22f184c` de la rama `v0.14`, sin tocar el texto normativo: el título y la fila §12.1 de `docs/traceability.md`, los tres schemes y los 18 errores de los README (son uno y 19), la cabecera de `spec/datekeys.cddl` y las releases firmadas de `SECURITY.md`, que aún no existen. Queda `docs/README.md`, que llama `datekeys-ts/` a la carpeta que en esta máquina es `App`: se arregla al renombrarla.
La documentación atrasada de la v0.14 (la trazabilidad, los README, la cabecera del CDDL y `SECURITY.md`) se arregló el 6-10 en `22f184c`, y está dentro de `fe50885`, que la pone además en la v0.15. Queda `docs/README.md`, que llama `datekeys-ts/` a la carpeta que en esta máquina es `App`: se arregla al renombrarla.
### Lo que no he podido comprobar
- Que el H3 del texto coincide con `h3` de kyber: lo dice el spec y lo comprueban los vectores (`tlock_steps.json`, generado contra kyber), pero quien escribió el paquete no leyó kyber. Está como pregunta Q10.
- Los gates del 7-10 no los volvió a pasar quien puso el paquete al día: las cifras (Go `scripts/check.sh` en `fe50885`; TypeScript 8 106 pruebas, 1 omitida; Dart 2 211 en la VM y 694 en Node) son las de la sesión que cerró la v0.15.
## Orden
1. Cerrar la `0.3.0` de TypeScript: hecho, `3abd7bf`.
2. Pasar los tres gates en los commits congelados: hecho el 6-10. Go, `scripts/check.sh` entero en `39b2033` y `scripts/fuzz.sh 20s` con los 26 objetivos, limpio (una primera pasada se cortó por un «context deadline exceeded» del motor de fuzzing de Go, sin entrada que falle; la segunda pasó entera). TypeScript, `npm run verify` en `3abd7bf`, con 8 030 pruebas; Dart, `tool/check.sh` en `013b069`.
3. Corregir la nota y el paquete: hecho el 6-10 (la cabecera, el paso duplicado, `artifacts.md` §5, la propuesta, los dos hashes del CDDL), y la tabla congelada con la `0.3.0`: hecho.
1. Cerrar la versión de TypeScript: hecho, la `0.4.0` en `7650418`.
2. **Pasar los gates en los commits congelados.** Hecho el 7-10: Go, `scripts/check.sh` entero en `fe50885`, con la comprobación del anexo, y `FUZZ_PARALLEL=4 scripts/fuzz.sh 20s` con sus 27 objetivos, `FuzzDecodeRelease` entre ellos, sin fallos; TypeScript, `npm run verify` en `7650418`, con 8 106 pruebas y 1 omitida; Dart, `tool/check.sh` en `faa2c4c`, con 2 211 pruebas en la VM y 694 en Node.
3. Corregir la nota y el paquete: hecho el 6-10 para la v0.14, y el 7-10 para la v0.15 (esta puesta al día).
4. Elegir revisor y nivel de alcance, y pedir presupuesto.
5. Traducir el núcleo, solo si el revisor no lee español.
6. NDA, bundles y envío.

@ -1,6 +1,6 @@
# DateKeys: request for an external cryptographic review
*Draft package, 6 October 2026. Prepared for the author before it is sent; see `NOTA_PARA_EL_AUTOR.md` for what is still to be decided.*
*Draft package, 6 October 2026; brought up to specification v0.15 on 7 October 2026. Prepared for the author before it is sent; see `NOTA_PARA_EL_AUTOR.md` for what is still to be decided.*
## What DateKeys is
@ -19,6 +19,8 @@ Format 3, the only one a writer produces, holds several files with their paths,
The guiding principle is: never trust the server for a property the client can verify cryptographically (spec §3). The profile is pinned, the round is computed locally and the release is verified locally.
Version 0.15 adds long-term recovery, without changing the `.dkc` or `.dkk` formats: a **release object**, the public BLS signature of one round as a small CBOR record (spec §47.1); a distinction between a release fetched from a network source and a **release in hand**, which the local clock no longer vetoes (spec §49, §63 step 9.c); recovery from **release archives and cache services** that keep the releases of all rounds, with an informative archive format and no promise of hosting (spec §50); and an informative **annex to open a capsule without DateKeys software** (spec §79), which the reference proves on fixtures with code that imports nothing from DateKeys, tlock or drand.
## What we ask
We ask for a cryptographic review of the protocol as specified, with the reference implementation as an aid. In particular:
@ -27,6 +29,7 @@ We ask for a cryptographic review of the protocol as specified, with the referen
2. Whether the bindings and commitments are sufficient and correctly placed (header binding, control and payload binding, the author-signature commitments, the seal subject).
3. Whether the byte-level description of the root of trust (spec §12.2, §63 steps 10 and 11 and the paragraphs after the flow) is complete and correct, so that an implementer needs no other source.
4. Whether the parsing surfaces (CBOR profile, age headers, the CMS/X.509/RFC 3161 reader of §29.10–§29.11, locator addresses) are specified tightly enough to avoid divergence and attack.
5. Whether the long-term recovery design of v0.15 is sound: the release object and its check at step 10, accepting a release in hand without comparing it with the clock (§63 step 9.c), archives and cache services as the recovery path (§50), and the annex of §79.
The ranked questions are in `scope_and_questions.md`, in two levels of scope: level 1, the protocol with the Go reference as evidence, and level 2, the parsers of the CMS/X.509/RFC 3161 reader and of the locator, which may be commissioned separately. Known open problems are listed there too, so that you do not spend time rediscovering them.
@ -45,15 +48,15 @@ Scope, budget and timeline are to be agreed with the author.
| Item | Identifier |
|---|---|
| Specification | `datekeys-go/spec/DateKeys_Protocol_Specification_v0.14.md`, tag `spec-v0.14`, commit `39b2033e3ccf54a91bda8d7e3ced39b26dbfa58c`, approved 6 October 2026 |
| Its SHA-256 | `390922135931dd61a263ed90259c7a978b5d92944405e641e94cc194f84fb459` (recorded in `spec/README.md`; checked on 6 October 2026) |
| CBOR schemas | `datekeys-go/spec/datekeys.cddl`: SHA-256 `35c6e5fb74d65907bcb436242079bcc99cfb81a654a1174f2cac68576bf24a51` at the tag, and `9607d1c7ebd2c09df3969a2749a588cf39bc24fe49a05a5f308b798a3ca621fa` at `22f184c`, which changes only its header comment |
| Shared test data | `datekeys-go/testdata/` at the same tag: 136 files, documented in `testdata/README.md` |
| Reference implementation (Go) | `datekeys-go` at `spec-v0.14` / `39b2033`; its documentation (README, SECURITY.md, `docs/traceability.md`, the header comment of `spec/datekeys.cddl`) brought up to v0.14 at `22f184c`, the head of branch `v0.14`. That commit changes no specification text, no schema rule and no code: in `datekeys.cddl` only its header comment, so its SHA-256 differs from the tag's (row above) |
| TypeScript implementation | `datekeys-ts` 0.3.0, tag `v0.3.0`, commit `3abd7bfee88d5e5c09bda20fcec8a4762d6beb19` |
| Dart implementation | `datekeys-dart`, branch `v0.14`, commit `013b0695228bae6a4a61e244e679d38f2b8b93fd` |
| Specification | `datekeys-go/spec/DateKeys_Protocol_Specification_v0.15.md`, tag `spec-v0.15`, commit `fe5088549186465e08d55f89680be986076bf165`, approved 7 October 2026 |
| Its SHA-256 | `45105e693be4187af4dd30f4d254402612587b6427c746f5d29f07a541c1e3f3` (recorded in `spec/README.md`; checked on 7 October 2026) |
| CBOR schemas | `datekeys-go/spec/datekeys.cddl` at the same commit: SHA-256 `63565d5e969d08d761cf8f302e767d457372ff0543dd6a6fad9d9fcff9c519b5` (v0.15 adds the rule `release`) |
| Shared test data | `datekeys-go/testdata/` at the same tag: 142 files, documented in `testdata/README.md` |
| Reference implementation (Go) | `datekeys-go` at `spec-v0.15` / `fe50885`, which is also the head of branch `v0.15` and of `main`. Its documentation (README, SECURITY.md, `docs/traceability.md`, the header comment of `spec/datekeys.cddl`) is at v0.15 in the same commit: one frozen commit for Go |
| TypeScript implementation | `datekeys-ts` 0.4.0, tag `v0.4.0`, commit `76504183d3bc59051106bae57d1427ae228ae918` |
| Dart implementation | `datekeys-dart`, branch `v0.15`, commit `faa2c4c89154b4ff405941227682b949a1cda5d3` (no tag) |
Note on TypeScript: `datekeys-ts` 0.3.0 implements specification 0.14, with its `testdata/` at tag `spec-v0.14`, so it runs against the same frozen vectors as the reference. Its previous version, 0.2.0, implemented 0.13.
Note on TypeScript and Dart: `datekeys-ts` 0.4.0 and `datekeys-dart` at `faa2c4c` implement specification 0.15, with their `testdata/` at tag `spec-v0.15` (`fe50885`), so they run against the same frozen vectors as the reference. The previous TypeScript version, 0.3.0, implemented 0.14.
## How this package is organised
@ -67,7 +70,7 @@ Note on TypeScript: `datekeys-ts` 0.3.0 implements specification 0.14, with its
| `precedence_and_language.md` | A proposal for the author: which language is normative, and precedence between the text, the CDDL, the test vectors and the implementation |
| `NOTA_PARA_EL_AUTOR.md` | A short note in Spanish for the author: what is still missing before sending |
The normative text is the Spanish specification. The English files here are informative summaries; where they disagree with the specification, the specification wins. Section numbers (§) refer to `DateKeys_Protocol_Specification_v0.14.md`.
The normative text is the Spanish specification. The English files here are informative summaries; where they disagree with the specification, the specification wins. Section numbers (§) refer to `DateKeys_Protocol_Specification_v0.15.md`.
## Prior reviews: all by AI systems
@ -75,6 +78,7 @@ No human has reviewed DateKeys so far. Every review to date was done by AI syste
- Claude (Anthropic), in the working sessions that wrote the specification and the implementations, including the completeness reviews of 29 September 2026 (`docs/REVISION_completitud_protocolo.md`, against v0.8.2) and 6 October 2026 (`docs/REVISION_completitud_v0.13.md`, against v0.13).
- Fable and Astra, also AI systems (confirmed by the author on 6 October 2026), for the design of format 3 (v0.10) and of the signature and the seal (v0.11).
- The long-term recovery of v0.15 (6 and 7 October 2026) was designed and drafted in the same Claude working sessions (`docs/diseno_recuperacion.md`, `docs/spec_v0.15/decisiones.md`) and approved by the author; it has had no review outside those AI-assisted sessions.
Some passages of spec §76 describe these reviews with words that suggest otherwise:

@ -1,33 +1,35 @@
# Artifacts
*State on 6 October 2026. Paths are relative to each repository.*
*State on 7 October 2026, specification v0.15. Paths are relative to each repository.*
## 1. Repositories and frozen commits
| Repository | Role | Frozen at | Language of docs |
|---|---|---|---|
| `datekeys-go` | Specification (`spec/`), CDDL, shared test data (`testdata/`), reference implementation in Go: library and CLI | tag `spec-v0.14`, commit `39b2033e3ccf54a91bda8d7e3ced39b26dbfa58c` | English README (a Spanish one too); spec in Spanish |
| `datekeys-ts` | TypeScript library and static pages `/inspect` and `/create` | tag `v0.3.0`, commit `3abd7bfee88d5e5c09bda20fcec8a4762d6beb19` (implements spec 0.14) | Spanish README |
| `datekeys-dart` | Pure Dart library, for a future Flutter app | branch `v0.14`, commit `013b0695228bae6a4a61e244e679d38f2b8b93fd` | Spanish README |
| `datekeys-go` | Specification (`spec/`), CDDL, shared test data (`testdata/`), reference implementation in Go: library and CLI | tag `spec-v0.15`, commit `fe5088549186465e08d55f89680be986076bf165` (also the head of branch `v0.15` and of `main`) | English README (a Spanish one too); spec in Spanish |
| `datekeys-ts` | TypeScript library and static pages `/inspect` and `/create` | tag `v0.4.0`, commit `76504183d3bc59051106bae57d1427ae228ae918` (implements spec 0.15) | Spanish README |
| `datekeys-dart` | Pure Dart library, for a future Flutter app | branch `v0.15`, commit `faa2c4c89154b4ff405941227682b949a1cda5d3`, no tag (implements spec 0.15) | Spanish README |
- The repositories are private, on a Gitea server on the author's LAN (`g.activething.com`). They are not reachable from outside. The author will provide them by another means (for example `git bundle` files or archives); see `NOTA_PARA_EL_AUTOR.md`.
- The gates of `datekeys-ts` and `datekeys-dart` compare their `testdata/` with a sibling checkout `../datekeys-go`. Lay the three out side by side:
```text
work/
datekeys-go/ at spec-v0.14
datekeys-ts/ at v0.3.0 (the author's machine names this folder App)
datekeys-dart/ at 013b069
datekeys-go/ at spec-v0.15
datekeys-ts/ at v0.4.0 (the author's machine names this folder App)
datekeys-dart/ at faa2c4c
```
Specification files at the tag:
| File | SHA-256 |
|---|---|
| `spec/DateKeys_Protocol_Specification_v0.14.md` (4 412 lines, about 52 600 words, Spanish) | `390922135931dd61a263ed90259c7a978b5d92944405e641e94cc194f84fb459` |
| `spec/datekeys.cddl` (322 lines, English comments) | `35c6e5fb74d65907bcb436242079bcc99cfb81a654a1174f2cac68576bf24a51` at the tag; `9607d1c7ebd2c09df3969a2749a588cf39bc24fe49a05a5f308b798a3ca621fa` at `22f184c`, which changes only its header comment |
| `spec/DateKeys_Protocol_Specification_v0.15.md` (4 734 lines, about 58 300 words, Spanish) | `45105e693be4187af4dd30f4d254402612587b6427c746f5d29f07a541c1e3f3` |
| `spec/datekeys.cddl` (341 lines, English comments; v0.15 adds the rule `release`) | `63565d5e969d08d761cf8f302e767d457372ff0543dd6a6fad9d9fcff9c519b5` |
`spec/README.md` lists the SHA-256 of every frozen version from v0.8.2 to v0.14. Earlier versions are in the same folder; §76 records each normative change with its reproducible case. The specification is CC-BY-4.0; the code is Apache-2.0.
Both were checked on 7 October 2026 with `git show spec-v0.15:<file> | sha256sum`. The documentation of the Go repository (README, SECURITY.md, `docs/traceability.md`, the header comment of the CDDL) is at v0.15 in the same commit, so one commit freezes Go.
`spec/README.md` lists the SHA-256 of every frozen version from v0.8.2 to v0.15. Earlier versions are in the same folder; §76 records each normative change with its reproducible case. The specification is CC-BY-4.0; the code is Apache-2.0.
## 2. Build and gates
@ -42,13 +44,19 @@ go test -tags interop ./capsule # the official age and tle CLIs open our
go test -tags integration ./capsule ./provider/drand # live Quicknet (network)
```
`scripts/check.sh` runs, in order: `gofmt`; `go mod verify`; `go mod tidy` leaves `go.mod` and `go.sum` unchanged; `go vet`; `go test -race`; coverage of at least 90 % in `codec`, `capsule`, `accesskey`, `datekey` and `agewrap`; `govulncheck` v1.8.0 (downloads the tool); and `genfixtures`, which regenerates `testdata/` and fails if any committed file changes.
`scripts/check.sh` runs, in order: `gofmt`; `go mod verify`; `go mod tidy` leaves `go.mod` and `go.sum` unchanged; `go vet`; `go test -race`; coverage of at least 90 % in `codec`, `capsule`, `accesskey`, `datekey` and `agewrap`; `govulncheck` v1.8.0 (downloads the tool); `scripts/recovery_check.sh` (v0.15, below); and `genfixtures`, which regenerates `testdata/` and fails if any committed file changes.
`scripts/recovery_check.sh` proves the annex of spec §79: it opens the fixtures `format3_single` (`time_only`) and `format3_time_and_key_portable` (`time_and_key`, with its `.dkk`) with `scripts/recovery`, using the release objects of `testdata/releases/`, and compares the BODY it recovers with the plaintext fixture. `scripts/recovery` imports no DateKeys, tlock or drand package: only the Go standard library, `golang.org/x/crypto` (ChaCha20-Poly1305), `filippo.io/age` and drand's BLS12-381 library (`github.com/drand/kyber-bls12381`, with the interfaces of `github.com/drand/kyber`). Its test checks that rule and runs over eight fixtures of the three formats (spec §76, v0.15 change 4).
`scripts/fuzz.sh` has 26 targets: `codec` (Decoder, Walk, Peek, Unmarshal, EncodeImpliesWalk), `extension` (DecodeArray), `profile` (Decode), `datekey` (Parse), `agewrap` (Stanzas), `accesskey` (Decode), `capsule` (ParsePrelude, DecodeHeader, DecodeControl, DecodeHead, EvaluateSecurity, Inspect, EncodeImpliesDecode), `internal/pathrule` (CheckPath), `locator` (Unmarshal, ParseInfo, CheckURI, CheckResolvedIP), `internal/der` (DERCheck), `internal/cms` (ParseSignature, ParseToken, ParseCert). Each worker keeps a 100 MB shared-memory file in the temporary directory. Last recorded run: 60 s per target on `69dbb0c`, clean (`docs/HANDOFF.md`, 6 October 2026).
`scripts/fuzz.sh` has 27 targets: `codec` (Decoder, Walk, Peek, Unmarshal, EncodeImpliesWalk), `extension` (DecodeArray), `profile` (Decode), `provider` (DecodeRelease, new in v0.15: the release object of §47.1), `datekey` (Parse), `agewrap` (Stanzas), `accesskey` (Decode), `capsule` (ParsePrelude, DecodeHeader, DecodeControl, DecodeHead, EvaluateSecurity, Inspect, EncodeImpliesDecode), `internal/pathrule` (CheckPath), `locator` (Unmarshal, ParseInfo, CheckURI, CheckResolvedIP), `internal/der` (DERCheck), `internal/cms` (ParseSignature, ParseToken, ParseCert). Each worker keeps a 100 MB shared-memory file in the temporary directory; `FUZZ_MINIMIZE` (default 0) sets the time spent minimising a new input.
The CLI (`cmd/datekeys`) has `encrypt`, `decrypt`, `inspect`, `author keygen`, `author public`, `profile hash`, `datekey resolve` and `version` (`README.md`).
The CLI (`cmd/datekeys`) has `encrypt`, `decrypt`, `inspect`, `author keygen`, `author public`, `profile hash`, `datekey resolve` and `version` (`README.md`). Since v0.15, `decrypt -release <file>` takes a release in hand (a release object, drand's JSON or a local release archive), makes no request and does not compare it with the clock.
On 6 October 2026, `scripts/fuzz.sh 20s` ran the 26 targets on `39b2033`, the frozen commit, with no failing input.
Gate and fuzzing record:
- On 7 October 2026, `scripts/check.sh` (without fuzzing) passed on `fe50885`, the frozen commit.
- On 7 October 2026, `FUZZ_PARALLEL=4 scripts/fuzz.sh 20s` ran the 27 targets on `fe50885`, `FuzzDecodeRelease` among them, with no failing input. The previous run, on 6 October 2026, covered the 26 targets of v0.14 on `39b2033`.
- Earlier: 60 s per target on `69dbb0c`, clean (`docs/HANDOFF.md`, 6 October 2026).
### datekeys-ts (Node.js 20 or later)
@ -59,7 +67,7 @@ npm run verify # svelte-check, typecheck, tests with coverage threshold
npm run testdata:check # testdata/ equals ../datekeys-go at the recorded commit
```
Coverage thresholds are 100 % for the cryptographic and format modules listed in its README. A guard test fails if a file of `testdata/` is not used by any test, and `src/lib/dependencies.test.ts` pins the exact runtime dependencies. On 6 October 2026, `npm run verify` passed with 8 030 tests on `3abd7bf`, the release commit of 0.3.0.
Coverage thresholds are 100 % for the cryptographic and format modules listed in its README. A guard test fails if a file of `testdata/` is not used by any test, and `src/lib/dependencies.test.ts` pins the exact runtime dependencies. On 7 October 2026, `npm run verify` passed with 8 106 tests (1 skipped) on `7650418`, the release commit of 0.4.0, with `testdata/` at `fe50885` (`testdata/SOURCE.json`).
### datekeys-dart (Dart SDK 3.13 or later; Node.js for the JavaScript run)
@ -70,11 +78,11 @@ tool/check.sh # dart format, dart analyze --fatal-infos, dart test, da
# and testdata/ against ../datekeys-go
```
On 6 October 2026 the gate passed with 2 193 tests on the VM and 681 on Node (`docs/HANDOFF.md`).
On 7 October 2026 the gate passed on `faa2c4c` with 2 211 tests on the VM and 694 on Node, with `testdata/` at `fe50885` (142 files).
## 3. Shared test vectors (`datekeys-go/testdata/`)
Generated by the reference implementation (`go run ./internal/testkit/genfixtures -out testdata`). The `.dkc` and `.dkk` fixtures, `security_cms.json` and `locator.json` hold randomness and are frozen. TypeScript and Dart copy `testdata/` from a Go commit and never generate fixtures. Every file says `"spec": "0.14"`. The format of each file is documented in `testdata/README.md` (1 063 lines, English), so that no Go code needs to be read.
Generated by the reference implementation (`go run ./internal/testkit/genfixtures -out testdata`). The `.dkc` and `.dkk` fixtures, `security_cms.json` and `locator.json` hold randomness and are frozen. TypeScript and Dart copy `testdata/` from a Go commit and never generate fixtures. Every file says `"spec": "0.15"`. The format of each file is documented in `testdata/README.md` (1 152 lines, English), so that no Go code needs to be read. At `fe50885` there are 142 files; v0.15 adds `vectors/release.json`, the five files of `releases/` and the field `source` of `mutations.json`.
| File | Content | Spec |
|---|---|---|
@ -83,6 +91,9 @@ Generated by the reference implementation (`go run ./internal/testkit/genfixture
| `vectors/dk1.json` | canonical `dk1_` strings, and rejected encodings with their code | §18, §19, §66 |
| `vectors/cbor.json` | the CBOR profile, and one block of vectors per schema, CONTROL_CBOR in the three formats | §58, CDDL |
| `vectors/tlock_ibe.json` | H2 of the tlock IBE: the serialisation of a GT element | §63 step 11 |
| `vectors/release.json` | the release object: valid and invalid encodings, drand's JSON, each with its result at step 10 (`ERR_NON_CANONICAL_CBOR`, `ERR_UNSUPPORTED_VERSION`, `ERR_PROFILE_MISMATCH`, `ERR_ROUND_MISMATCH`, `ERR_RELEASE_INVALID`); and the lookups of a local release archive | §47.1, §50, §63 step 10 (v0.15) |
| `releases/<round>.cbor` | the release object of each published round the fixtures use: 1000, 1001, 1004 and 2000 (111 bytes each) | §47.1 (v0.15) |
| `releases/archive_1000_1004.bin` | a local release archive in the informative format of §50, rounds 1000 to 1004, with 1002 and 1003 missing (zero-filled) | §50 (v0.15) |
| `vectors/tlock_steps.json` | steps 10 and 11 for Quicknet value by value: round message, hash to G1, and the decryption of a tlock stanza with H2, H4, H3 and the file key | §63 steps 10 and 11 (v0.14) |
| `vectors/padding.json` | padding of formats 2 and 3: P for each L, and the PAYLOAD_AGE length | §29.1 |
| `vectors/paths.json` | the paths of a format 3 head: rules of one entry, and of the paths of a head | §29.5 |
@ -95,19 +106,21 @@ Generated by the reference implementation (`go run ./internal/testkit/genfixture
| `vectors/resolved_ip.json` | the IP a locator name resolves to, NAT64 included, and whether a reader may connect | §44.1 (v0.13) |
| `vectors/wordkey.json` | key of words: the words of a text, what a writer refuses, the derived identity | §38.1, §64 |
| `vectors/locator.json` | the `datekeys.capsule` extension, its envelope and locator, and what a reader rejects and uses | §44.1, §64 |
| `vectors/mutations.json` | the mutation corpus: the 178 mutations of §64 and further cases | §63, §64 |
| `vectors/mutations.json` | the mutation corpus: 222 cases, the 178 mutations of §64 and further cases. Since v0.15 each case names its release `source`: `supplied` (a release in hand, 220 cases) or `network` (2 cases); four cases are new (cases 219 to 222), and «round not reached yet» now opens with a release in hand | §63, §64 |
| `vectors/inspect_differential.json` | 5 110 mutations of fourteen fixtures with the verdict of steps 1 to 8 | §63 |
| `fixtures/<name>.dkc`, `<name>.json` | official capsules and every intermediate value | §67 |
| `fixtures/<name>.dkk`, `<name>.dkk.json` | official access keys | §68 |
| `fixtures/<name>.plaintext` | the content of each capsule (formats 1 and 2: the content; format 3: BODY) | §67 |
| `fixtures/<name>.inspect.json` | the exact output of `datekeys inspect -json` | §63 |
Twenty-six official capsules (`testdata/README.md`): five of format 1 (v0.8.2, compatibility), seven of format 2 (v0.9, compatibility) and fourteen of format 3, among them `format3_signed` (`alg` 1, F4), `format3_signed_cms` (`alg` 2, two signers, ECDSA P-256 and RSA 2048, CAdES-T each, F6), `format3_sealed` (`alg` 1 and an RFC 3161 seal, S4) and `format3_note`. Each record embeds the published Quicknet signature that opens it, so every fixture decrypts offline. Test secrets (`payload_identity`, `access_material`, the seed of the test author key) are in the records on purpose.
Twenty-six official capsules (`testdata/README.md`): five of format 1 (v0.8.2, compatibility), seven of format 2 (v0.9, compatibility) and fourteen of format 3, among them `format3_signed` (`alg` 1, F4), `format3_signed_cms` (`alg` 2, two signers, ECDSA P-256 and RSA 2048, CAdES-T each, F6), `format3_sealed` (`alg` 1 and an RFC 3161 seal, S4) and `format3_note`. Each record embeds the published Quicknet signature that opens it, so every fixture decrypts offline; since v0.15 the same signatures are also in `releases/` as release objects. Test secrets (`payload_identity`, `access_material`, the seed of the test author key) are in the records on purpose.
## 4. Dependencies
### Go (`datekeys-go/go.mod`, Go 1.26.8)
No dependency changed in v0.15: `go.mod` and `go.sum` are identical at `39b2033` and `fe50885`; the TypeScript `package.json` and lock file change only the package version from 0.3.0 to 0.4.0; the Dart `pubspec.yaml` and `pubspec.lock` are identical at `013b069` and `faa2c4c`. The recovery program `scripts/recovery` uses only modules already in `go.mod`.
Direct:
| Module | Version | Role (`SECURITY.md`) |
@ -123,7 +136,7 @@ Indirect: `filippo.io/hpke` v0.4.0, `github.com/BurntSushi/toml` v1.6.0, `github
The Go standard library provides Ed25519 (with strict checks in `internal/ed25519strict`), RSA, ECDSA, SHA-2 and PBKDF2. CBOR (`codec`), DER (`internal/der`) and the CMS/X.509/RFC 3161 reader (`internal/cms`) are the module's own code.
### TypeScript (`datekeys-ts/package.json` at `v0.3.0`, exact versions)
### TypeScript (`datekeys-ts/package.json` at `v0.4.0`, exact versions)
Runtime:
@ -136,7 +149,7 @@ Runtime:
`age-encryption` brings `@scure/base` 2.4.0 and `@noble/post-quantum` 0.5.4, which carries its own `@noble/curves` and `@noble/hashes` 2.0.1. The IBE core (`ibe.ts`) is derived from `tlock-js` (MIT); `tlock-js` itself is not a dependency. Development: TypeScript 5.9.3, Vitest 5.0.1, Vite 8.3.0, Svelte 5.57.1, SvelteKit 2.70.3, svelte-check 4.7.6, adapter-static 3.0.10, `@types/node` 24.13.6.
### Dart (`datekeys-dart/pubspec.yaml` and `pubspec.lock` at `013b069`)
### Dart (`datekeys-dart/pubspec.yaml` and `pubspec.lock` at `faa2c4c`)
- Runtime: `crypto` 3.0.7 (SHA-1, SHA-2, HMAC), with `typed_data` 1.4.0 transitive. Everything else is own code: HKDF, PBKDF2, scrypt, ChaCha20-Poly1305, X25519, Ed25519, BLS12-381, ECDSA, RSA, DER, CMS and CBOR.
- Development: `test` 1.31.1 or later (`^1.31.1`).
@ -144,9 +157,9 @@ Runtime:
## 5. Traceability
`datekeys-go/docs/traceability.md` (258 lines) maps every normative section of the specification to the Go code that implements it and the tests that exercise it, row by row from §3 to §76, and marks cases of §64 not yet in the repository as *pending*. It is intended for the external reviewer.
`datekeys-go/docs/traceability.md` (261 lines) maps every normative section of the specification to the Go code that implements it and the tests that exercise it, row by row from §3 to §76, with a row for the informative annex §79, and marks cases of §64 not yet in the repository as *pending*. It is intended for the external reviewer.
Brought up to v0.14 at `22f184c` (branch `v0.14`): the title and the row §12.1, which lists the one scheme of v0.14 (§76 v0.14 change 7). The same commit fixed `datekeys-go/README.md` (one drand scheme, 19 normative errors), `SECURITY.md` (no release exists yet) and the header comment of `spec/datekeys.cddl`.
At v0.15 in the frozen commit `fe50885`, with the rows of v0.15: §45 (the Release API answers with the release object), §47.1 (the release object, `provider/release.go`, `FuzzDecodeRelease`), §49 (a release in hand), §50 (archives and cache services) and §79 (`scripts/recovery`). The documentation fixes of v0.14 (`22f184c`: one drand scheme, 19 normative errors, no signed release of the module yet) are included in that commit.
## 6. Other documents a reviewer may want
@ -155,4 +168,6 @@ All in the private `docs` repository; in Spanish:
- `REVISION_completitud_protocolo.md`: completeness review against v0.8.2 (29 September 2026), AI-assisted.
- `REVISION_completitud_v0.13.md`: completeness review against v0.13 (6 October 2026), AI-assisted.
- `spec_v0.14/decisiones.md`: the ten decisions of the v0.14 draft.
- `diseno_recuperacion.md`: the design of the long-term recovery (6 October 2026), with the options and the author's decisions, AI-assisted.
- `spec_v0.15/decisiones.md`: the decisions of the v0.15 draft (7 October 2026). It describes the `.dkr` release file, which the author removed before approval; a note at its top says so (spec §76, v0.15 change 4).
- `spec_v0.10/revision_fable.md`, `spec_v0.11/revision_fable_astra.md`: reviews by the AI systems Fable and Astra.

@ -1,6 +1,6 @@
# DateKeys v0.14: design overview for a cryptographic reviewer
# DateKeys v0.15: design overview for a cryptographic reviewer
*Informative. Every statement here summarises the Spanish specification `DateKeys_Protocol_Specification_v0.14.md` (tag `spec-v0.14`); the section sign (§) refers to it. Where this summary and the specification disagree, the specification wins. Reading time: about an hour.*
*Informative. Every statement here summarises the Spanish specification `DateKeys_Protocol_Specification_v0.15.md` (tag `spec-v0.15`); the section sign (§) refers to it. Where this summary and the specification disagree, the specification wins. Reading time: about an hour.*
Notation: `||` is concatenation; `uint32_be`, `uint64_be` are big-endian integers; SHA-256 is FIPS 180-4; "age" is the C2SP age v1 format; Quicknet is the drand network of §12.
@ -11,6 +11,7 @@ Notation: `||` is concatenation; `uint32_be`, `uint64_be` are big-endian integer
- Guiding principle (§3): never trust the server for a property the client can verify. The provider profile is pinned locally, date → round is computed locally, releases are verified locally, and `.dkc`, `.dkk`, APIs and relays are untrusted inputs.
- No new cryptography (§28, §30, §37): DateKeys composes three standard age files and the tlock IBE of drand. It defines framing, CBOR, bindings, stanza rules, padding, the format 3 content, the author signature profile and the verification flow.
- The protocol does not define storage, discovery, distribution or delivery of `.dkk` (§6).
- Since v0.15 the release of a round has a data format, the release object (§47.1), and long-term recovery rests on archives and cache services of all rounds, with an annex to open a capsule without DateKeys software (§50, §79). See section 8.
## 2. Provider Profile and root of trust
@ -50,7 +51,7 @@ The SDK chooses the first round with `round_time ≥ requested_unlock_at`, compa
### 2.4 Release verification: message and hash to G1 (§51, §63 step 10, paragraph «Mensaje de ronda y hash a G1»)
For round n of Quicknet:
Step 10 first validates a release object in hand (its size, type and version, and schema; §47.1, section 8.1) and compares its `chain_hash` with the pinned profile's (`ERR_PROFILE_MISMATCH`, v0.15); then the round (`ERR_ROUND_MISMATCH`); then the signature (`ERR_RELEASE_INVALID`). For round n of Quicknet:
```text
M = SHA-256(uint64_be(n)) ; 32 bytes; no previous signature
@ -214,7 +215,7 @@ BODY = AREA_LEN (uint32 BE) || SECURITY_LEN (uint32 BE) || HEAD_LEN (uint32 BE)
AREA_LEN = 512·k, 1 ≤ k ≤ 128; 1 ≤ SECURITY_LEN ≤ AREA_LEN; 1 ≤ HEAD_LEN ≤ 16 MiB
```
- A v0.14 writer MUST write AREA_LEN = 32768, signed or not, or 65536 only if the creator expressly widens it because signatures do not fit. So P does not depend on whether the capsule is signed, except with a widened area (§29.2, §55.2). v0.10 writers wrote 512. A reader accepts any valid AREA_LEN.
- A writer of v0.14 or later MUST write AREA_LEN = 32768, signed or not, or 65536 only if the creator expressly widens it because signatures do not fit. So P does not depend on whether the capsule is signed, except with a widened area (§29.2, §55.2). v0.10 writers wrote 512. A reader accepts any valid AREA_LEN.
- The 32 KiB size is provisional until measured with real signatures (§74, §75 item 13).
### 4.2 Head (§29.4 to §29.6)
@ -364,9 +365,14 @@ plaintext length: exactly 4096, or the smallest multiple of 4096 that fits
7 resolve the time condition locally, round_time bound
8 SHOULD check the tlock stanza arguments (round, chain hash) as exact strings
9 no network: (a) a .dkk as an object, then its link to this capsule; (b) time_and_key
without a credential → ERR_ACCESS_REQUIRED; (c) now < round_time → ERR_RELEASE_UNAVAILABLE;
then fetch; a network source verifies each response with step 10 and discards bad ones
10 release: round first (ERR_ROUND_MISMATCH), then canonical signature and BLS (ERR_RELEASE_INVALID)
without a credential → ERR_ACCESS_REQUIRED; (c) only before a network request:
now < round_time → ERR_RELEASE_UNAVAILABLE (a release in hand is not compared
with the clock, v0.15); then fetch; a network source verifies each response with
step 10 and discards bad ones; no release → ERR_RELEASE_UNAVAILABLE
10 release in hand: release object layers (ERR_NON_CANONICAL_CBOR, ERR_UNSUPPORTED_VERSION)
or unreadable drand JSON (ERR_RELEASE_INVALID); chain_hash vs pinned profile
(ERR_PROFILE_MISMATCH, v0.15); round (ERR_ROUND_MISMATCH); canonical signature
and BLS (ERR_RELEASE_INVALID)
11 open OUTER: exactly one tlock stanza; IBE decryption; r·G == U; age MAC
12 structure vs access_policy; 16 stanzas in formats 2 and 3
13 time_and_key: every identity against every stanza; an identity unwrapping two stanzas →
@ -384,18 +390,63 @@ plaintext length: exactly 4096, or the smallest multiple of 4096 that fits
- In format 3, a failure of age after its header or a plaintext length other than P prevails; a reader may stop early only with `ERR_INTEGRITY` when that is already the final code; any other code of step 17 is reported only after reading PAYLOAD_AGE to EOF (§63 step 17).
- 19 normative error codes (§69).
## 8. Canonical CBOR and limits (§57, §58, §58.1)
## 8. The release object and long-term recovery (v0.15: §45 to §50, §53, §62.1, §63 steps 9 and 10, §79)
### 8.1 The release object (§47.1)
The release of a round as data: the answer of the Release API (§45), the `release_material` of a Release Cache (§47), and a release the caller gives from a file or from a release archive. It has no file extension of its own; its type tag identifies it.
```text
Deterministic CBOR (profile of §58), no frame, 1 to 1024 bytes:
0 → "datekeys-release" 1 → 1 2 → chain_hash (32 bytes)
3 → round (1 .. 2^53 − 1) 4 → signature (1..96 bytes; 48 in Quicknet)
round 1000 of Quicknet: 111 bytes (testdata/releases/1000.cbor)
```
- All five keys are required. The chain is named by its `chain_hash`, drand's identifier, the same as in the tlock stanza; the object carries neither `profile_hash` nor `profile_id`.
- Validation, all at step 10, with the layers of §69.1: an empty input or one over 1024 bytes → `ERR_NON_CANONICAL_CBOR`, before decoding (no valid encoding exceeds 165 bytes); another type tag → `ERR_NON_CANONICAL_CBOR`; a version other than 1 → `ERR_UNSUPPORTED_VERSION`; CBOR profile and schema → `ERR_NON_CANONICAL_CBOR`. There are no layer-4 fields: `chain_hash`, round and signature are compared in that order at step 10 (`ERR_PROFILE_MISMATCH`, `ERR_ROUND_MISMATCH`, `ERR_RELEASE_INVALID`). A signature of the wrong length for the scheme passes the schema and is `ERR_RELEASE_INVALID`.
- A reader MAY decode it on receipt, but MUST report its errors only at step 10, after steps 1 to 9: a capsule without credentials still gives `ERR_ACCESS_REQUIRED` (§69.1).
- Trust: the object is not signed and has no "verified" field. For one round and one public key there is a single valid BLS signature, so any copy that verifies at step 10 is the release, whatever its source.
- drand's JSON, `{"round": …, "signature": "…"}`, SHOULD also be accepted as caller input (an input whose first non-whitespace byte is `{`). It names no chain, so step 10 compares no `chain_hash`; `randomness`, if present, MUST be the SHA-256 of the signature; an input over 8192 bytes or unreadable → `ERR_RELEASE_INVALID` at step 10, before the round. A Release Cache and the Release API MUST store and serve the release object, never this JSON.
- Vectors: `release.json`, `releases/<round>.cbor`.
### 8.2 Two kinds of source, and step 9.c (§49, §63 step 9)
- **Network source:** a drand relay, the Release API, a cache service or a remote archive. Each request is observable and reveals the round. The source verifies every response with the rules of step 10 and discards bad ones; if none delivers, `ERR_RELEASE_UNAVAILABLE` at step 9. It is not asked before `round_time` (step 9.c), unless the person expressly asks (MAY), because the clock may be wrong.
- **Release in hand:** given by the caller without network: a release object or drand's JSON from a file, or the entry of a local archive. **It is not compared with the local clock** (v0.15). If its `round_time` is after the local time, the reader MAY warn that the clock may be behind. A release in hand that fails step 10 gets the codes of step 10.
- The reasoning recorded in §76 (v0.15 change 3): the reasons for 9.c are network reasons (no useless or observable requests; fail early). A valid signature of a future round is only possible if drand is compromised (§7.6), and then the clock no longer protects confidentiality; the clock had been vetoing a verifiable release on a local value nobody can verify (for example a dead CMOS battery or a virtual machine).
- This is the one verdict v0.15 changes: a valid release in hand opens a capsule with a clock behind its round time, where v0.14 gave `ERR_RELEASE_UNAVAILABLE` at step 9 (§70). With a network source nothing changes. A v0.14 reader does not read a release object but does read drand's JSON for the same round.
### 8.3 Long-term recovery: archives and cache services (§50, §53)
- A capsule decades ahead needs three things kept: the `.dkc` (the protocol does not store it, §6), the rest of an envelope stored outside, if any (§44.1), and the release of its round. The release is the only one that does not exist at sealing time; and once it exists the capsule can already be opened, so a release saved next to one capsule only helps to reopen it.
- So long-term recovery rests on **release archives** with all rounds of the chain, local or remote, and on **cache services**, from DateKeys or others, that keep the releases of all rounds continuously and serve them; not on the release of one capsule. Keeping only the rounds of known capsules would reveal their dates and is not recommended.
- The reader asks for its round and verifies it with the pinned key at step 10, without trusting who serves it. A remote archive or cache service is a network source and learns the round; a local archive does not.
- The specification promises no published archive or service and does not say where they are hosted; a project archive or cache service and its hosting are future work (§74).
- **Archive format (informative, no error codes of its own):** a Deterministic CBOR header `{0: "datekeys-release-archive", 1: 1, 2: chain_hash, 3: first round, 4: number of rounds}`, followed by the signatures of consecutive rounds, n bytes each (48 in Quicknet); the signature of round r starts at |header| + (r − first round)·n; the file is exactly |header| + number·n bytes; a missing round is n zero bytes. An entry becomes a release object with the header's `chain_hash` and is verified at step 10. An archive of another chain, of another length, or without the round delivers nothing: `ERR_RELEASE_UNAVAILABLE` at step 9. Size for Quicknet: 10 512 000 rounds a year, about 505 MB of signatures a year, which do not compress, about 42 MB a month. Vector: `releases/archive_1000_1004.bin` (rounds 1002 and 1003 zero).
- The rejected alternative (§76, v0.15 change 4): a `.dkr` release file kept next to the capsule, and next to a `.dkk` with a locator, with a writer rule to fetch and store it after the date. The author removed it on 7 October 2026 for the reasons above; the `.dkk` extension `datekeys.release` went with it (change 6).
### 8.4 Annex: opening a capsule without DateKeys software (§79, informative)
- It says how to open a Quicknet capsule if no DateKeys software exists: the Quicknet parameters (chain hash, public key, genesis time, period, q, DST), the `.dkc` frame and header, the release (object, archive entry or drand JSON) and its BLS check, the tlock stanza and FK_TIME (H2, H3, H4 as in §63), opening an age file from its file key (HKDF, the header HMAC, STREAM with ChaCha20-Poly1305), the inner layers (`age -d` with the identity of a `.dkk`, a recipient or a key of words; the Bech32 encoding of an X25519 identity), and the content of each format.
- Needed: the `.dkc`, the release, a credential in `time_and_key`, a BLS12-381 library with pairing and the RFC 9380 hash to G1, SHA-256, HMAC-SHA256, HKDF-SHA256, ChaCha20-Poly1305, a CBOR decoder, and `age`. drand's tools do not serve: `tle` fetches the release from the network and accepts no given release, and `age` accepts no file key, which is why the annex describes those two steps in full.
- What it does not check (§79.8): it checks what decides that the result is correct (the release signature, r·G2 == U, every age MAC and every file's SHA-256), but not canonical encodings, `header_binding`, the 16 stanzas, the zero padding or the path rules. A capsule a conforming reader would reject may open by the annex; its content is what the age MACs sealed, without the guarantees of a conforming reader.
- The official SDK SHOULD keep the annex text next to each `.dkc` (§62.1 rule 27); it contains no data of any capsule.
- Proof: `scripts/recovery_check.sh` (part of `scripts/check.sh`) opens `format3_single` (`time_only`) and `format3_time_and_key_portable` (`time_and_key`) with `scripts/recovery`, which imports no DateKeys package, nor `drand/tlock` or `drand/drand` (it uses `drand/kyber` and `drand/kyber-bls12381` for BLS, `filippo.io/age` and `golang.org/x/crypto`), and compares the recovered BODY with the fixtures (`artifacts.md` section 2).
## 9. Canonical CBOR and limits (§57, §58, §58.1)
- Deterministic CBOR (RFC 8949 §4.2.1) restricted to major types 0, 2, 3, 4, 5; unsigned integer keys in strictly ascending order; shortest forms; definite lengths; closed maps; valid UTF-8. Negative integers, tags, floats and simple values are rejected. Decoders re-encode and compare. Every integer ≤ 2⁵³ − 1.
- Absent optional fields MUST be omitted; `{}`, `[]`, `""`, `h''` never mean absence (§58.1).
- Extensions: one mechanism for PUBLIC_HEADER, CONTROL_CBOR, `.dkk` and head; `data` is a non-empty opaque `bstr`; 1 to 64 per array, strictly ascending by UTF-8 bytes; unknown critical → reject; an extension outside the objects and arrays it is registered for is treated as unknown (§54, §72). A security-relevant extension MUST be in CONTROL_CBOR or covered by a signature extension (§72).
- Frame limits are MUST for encoders and decoders (§57). Some field limits are implementation limits of the reference only, listed in §74.
## 9. Writer rules (§61, §62, §62.1)
## 10. Writer rules (§61, §62, §62.1)
Selected MUST rules: write format 3 only; reject an unlock instant not after the writer's clock (the specification notes that a clock running late can still seal to an already published round, rule 2); 1 to 16 credentials, canonical and not low order; 16 slots with decoys in random order; all randomness from a CSPRNG, fresh per capsule (`capsule_id`, I_PAYLOAD, I_ACCESS, `credential_id`, decoys, permutation); know L before sealing; write the exact SEALED_CONTROL_LEN (resolved by sealing a provisional control of the same length, rule 7); the 32 KiB area; a fresh head salt; self-decoding of CONTROL_CBOR, HEAD_CBOR and SECURITY_CBOR with reader rules (rule 17); verify every signature and seal before writing (rule 19); deliver AUTHOR_MESSAGE as text with its code before each signature (rule 20); never store I_PAYLOAD, CONTROL_CBOR or content on disk while waiting for signatures (rule 25). SHOULD: self-check after sealing (rule 11) and erase secrets (rule 12).
Selected MUST rules: write format 3 only; reject an unlock instant not after the writer's clock (the specification notes that a clock running late can still seal to an already published round, rule 2); 1 to 16 credentials, canonical and not low order; 16 slots with decoys in random order; all randomness from a CSPRNG, fresh per capsule (`capsule_id`, I_PAYLOAD, I_ACCESS, `credential_id`, decoys, permutation); know L before sealing; write the exact SEALED_CONTROL_LEN (resolved by sealing a provisional control of the same length, rule 7); the 32 KiB area; a fresh head salt; self-decoding of CONTROL_CBOR, HEAD_CBOR and SECURITY_CBOR with reader rules (rule 17); verify every signature and seal before writing (rule 19); deliver AUTHOR_MESSAGE as text with its code before each signature (rule 20); never store I_PAYLOAD, CONTROL_CBOR or content on disk while waiting for signatures (rule 25). SHOULD: self-check after sealing (rule 11) and erase secrets (rule 12); since v0.15, warn when sealing that opening years later needs the `.dkc`, the `.dkk` in `time_and_key`, and the release of the round, which exists only after the date (rule 26), and keep the text of the recovery annex next to the `.dkc` (rule 27).
## 10. What the reader should check against the code
## 11. What the reader should check against the code
- The reference implementation implements no cryptography itself: age is `filippo.io/age`, tlock is `drand/tlock` (exported core), BLS is drand/kyber on `kilic/bls12-381`, signatures use the Go standard library; CBOR, DER and the CMS/X.509/RFC 3161 reader are the module's own code (`datekeys-go/SECURITY.md`).
- The TypeScript and Dart implementations implement the tlock IBE themselves: TypeScript in `ibe.ts`, derived from `tlock-js`, on `@noble/curves` 2.4.0; Dart in pure Dart on `BigInt`, not constant-time, a choice the author accepted (`datekeys-dart/README.md`).
- The release object is the module's own code (`provider/release.go`, on its CBOR codec); a release in hand reaches `capsule.Open` through `provider.Supplier`, and `datekeys decrypt -release` reads a release object, drand's JSON or a local archive (`docs/traceability.md`, rows §47.1 and §49). `scripts/recovery`, the program behind the annex of §79, deliberately uses none of the module's code.

@ -6,8 +6,8 @@ The completeness review of v0.13 (step 3) asks, before an external review, to de
## 1. What the sources say today
- **Specification text** (`DateKeys_Protocol_Specification_v0.14.md`, Spanish). It uses RFC 2119 keywords in English with Spanish equivalents (§2). It does not say which language is normative or what wins when sources disagree.
- **CDDL** (`spec/datekeys.cddl`). Its header calls itself the «Normative companion» of the specification. The text delegates to it: «cualquier violación de una regla normativa de `datekeys.cddl` … → `ERR_NON_CANONICAL_CBOR`» (§57), and layer 3 of §69.1 checks «toda regla normativa de `datekeys.cddl`». Some CDDL rules are marked as non-normative implementation limits of the reference (§74). Its header comment is stale: it names v0.11 and says the reference implements v0.9.
- **Specification text** (`DateKeys_Protocol_Specification_v0.15.md`, Spanish). It uses RFC 2119 keywords in English with Spanish equivalents (§2). It does not say which language is normative or what wins when sources disagree.
- **CDDL** (`spec/datekeys.cddl`). Its header calls itself the «Normative companion» of the specification. The text delegates to it: «cualquier violación de una regla normativa de `datekeys.cddl` … → `ERR_NON_CANONICAL_CBOR`» (§57), and layer 3 of §69.1 checks «toda regla normativa de `datekeys.cddl`». Some CDDL rules are marked as non-normative implementation limits of the reference (§74). Its header comment names the current version, v0.15, and does not mention precedence.
- **Test data** (`testdata/`, `testdata/README.md`). The README says: «The rules that decide each verdict are in the specification; this file points to them». §16 says the definitive vectors MUST be generated from the reference implementation and frozen before v1.0. §76 lists a fixture, a mutation test and the CDDL among the sources of a reproducible case.
- **Reference implementation** (Go). §16 and §67 make it the generator of the vectors. The v0.8.2 refinements of §76 record cases where the reference and `testdata/README.md` held rules that the text did not, and the text was then changed to match.
@ -25,9 +25,9 @@ So in practice, until now, a gap between sources was closed by writing the rule
4. **A disagreement is a defect.** Any disagreement found between the sources is a defect: the text decides. It is recorded in the project's working notes (`docs/HANDOFF.md`) and fixed in the next version, with its reproducible case in §76. Until then the vectors and fixtures are not touched: the gates regenerate `testdata/` from the reference and fail on any change, and the TypeScript guard fails on a file that no test runs.
5. **Reviews are labelled by who did them.** §76 names each review with its kind: internal and AI-assisted, or external and human, with the reviewer's name, scope and date for an external one (§75 item 10).
## 3. Spec text changes this would need (next version, v0.15 or later)
## 3. Spec text changes this would need (next version, v0.16 or later)
The v0.14 text is tagged and does not change. These changes would go into the next version, each recorded in its §76 block:
The v0.15 text is tagged and does not change; none of the passages below changed in v0.15, which was the long-term recovery. These changes would go into the next version, each recorded in its §76 block:
1. **A new paragraph on language and precedence, at the end of §1** (decided by the author on 6 October 2026: not a §0, which would shift the numbering every document cites). Draft wording in Spanish (the normative language), for the author to edit:
@ -50,14 +50,14 @@ The v0.14 text is tagged and does not change. These changes would go into the ne
Not normative; they can be done in the repositories at any time, and the external reviewer will see them first:
- `spec/datekeys.cddl`, header comment: the current version, and a line pointing to the precedence rule.
- `spec/datekeys.cddl`, header comment: a line pointing to the precedence rule (it already names the current version, v0.15).
- `testdata/README.md`: one line stating the precedence rule.
- `spec/README.md`: one line stating that the Spanish text is normative.
- `docs/traceability.md` and `README.md` of `datekeys-go`: brought up to v0.14 at `22f184c` (`artifacts.md` section 5).
- `docs/traceability.md` and `README.md` of `datekeys-go`: at v0.15 in the frozen commit `fe50885` (`artifacts.md` section 5).
## 5. Decided by the author (6 October 2026)
- The proposal is approved, with a paragraph at the end of §1 and rule 4 as written above.
- Among implementations, the reference first.
- Whether English becomes normative is left for v1.0.
- These text changes do not open a version now: they go into the version that records the findings of the external review, together with the labels of §76 and the record of the review (§75 item 10). The cover letter already states that every prior review was by AI.
- These text changes do not open a version now: they go into the version that records the findings of the external review, together with the labels of §76 and the record of the review (§75 item 10). The cover letter already states that every prior review was by AI. (v0.15, approved on 7 October 2026, is the long-term recovery and does not carry them.)

@ -1,6 +1,6 @@
# Scope and questions
*Section numbers (§) refer to `DateKeys_Protocol_Specification_v0.14.md`, tag `spec-v0.14`. "Known" marks a problem the project already knows about, with its source, so that you do not spend time rediscovering it; your opinion on it is still welcome.*
*Section numbers (§) refer to `DateKeys_Protocol_Specification_v0.15.md`, tag `spec-v0.15`. "Known" marks a problem the project already knows about, with its source, so that you do not spend time rediscovering it; your opinion on it is still welcome.*
## 0. Levels of scope
@ -20,7 +20,7 @@
- **`.dkk`, locator and envelope:** §40 to §44.1, including the address rules.
- **Error precedence** as a possible oracle (§63, §69.1).
- **Writer rules** that affect security: randomness, decoy disposal, self-checks (§62.1).
- **Long-term recovery and the provider** as written in §7.6, §50, §71.
- **Long-term recovery and the provider** (v0.15): the provider model (§7.6, §71), the release object (§47.1), network sources and a release in hand (§49), archives and cache services (§50), step 9.c and the release checks of step 10 (§63), the writer rules 26 and 27 (§62.1), and the informative recovery annex (§79).
The reference implementation (Go), and the TypeScript and Dart implementations, are in scope as aids and as evidence: please report where an implementation disagrees with the text.
@ -30,7 +30,7 @@ The reference implementation (Go), and the TypeScript and Dart implementations,
- The drand network's operation, its threshold and its key management; the protocol states the dependency (§7.6).
- Storage, discovery, distribution and delivery of `.dkc` and `.dkk` (§6).
- Legal validity of signatures and seals, and the trust in certificate chains and TSAs (§5, §29.10, §29.11).
- The Release API, Release Queue and Release Cache beyond what §45 to §47 sketch; they are not implemented (`datekeys-go/README.md`).
- The Release API server, the Release Queue and a Release Cache service: §45 to §47 fix only what they serve (the release object of §47.1, which is in scope) and the HTTP form of §45 is informative; none is implemented (`datekeys-go/README.md`). Where and how a release archive or cache service would be hosted (§50, §74).
- The landing site and the product application.
- The web pages `/inspect` and `/create` of `datekeys-ts` as a deployed service. Their threat is in §7.10; a review of the page code is welcome but optional.
- Side channels in the TypeScript and Dart code. Both state that they are not constant-time (see section 4).
@ -97,7 +97,7 @@ The order is our estimate of impact. Each question gives the sections to read.
### Q10. The H3 shift and the rest of the root of trust (§12.2, §63 steps 10 and 11)
- Is the byte-level text of steps 10 and 11 complete and correct, so that an implementer needs no drand, kyber or kilic code? In particular: the DST and suite, M = SHA-256(uint64_be(round)), the GT serialisation order, the H3 loop (counter from 1, uint16 little-endian, at most 65534 attempts, shift of the first byte only) and its failure path.
- Is the byte-level text of steps 10 and 11 complete and correct, so that an implementer needs no drand, kyber or kilic code? Since v0.15 the informative annex §79 repeats it for someone opening a capsule without DateKeys software (79.3 and 79.4); please also say whether the annex is correct and enough. In particular: the DST and suite, M = SHA-256(uint64_be(round)), the GT serialisation order, the H3 loop (counter from 1, uint16 little-endian, at most 65534 attempts, shift of the first byte only) and its failure path.
- Does the specification's H3 match drand/kyber `encrypt/ibe` `h3` exactly? The text says the shift is the mask of 256 − 255 = 1 bit applied to the first byte; please confirm against kyber.
- **Known:** `tlock_steps.json` gives M, H(M) and the full step-11 trace, but not the intermediate values of RFC 9380 hash_to_curve; the author decided not to add them (v0.14 decision 10). Dart checks its hash to G1 against the RFC 9380 vectors.
@ -105,11 +105,18 @@ The order is our estimate of impact. Each question gives the sections to read.
- The codes and their order are fixed so that all implementations report the same code. Does this create an oracle that helps an attacker: for example, before step 13 versus after, or `ERR_ACCESS_INVALID` versus `ERR_POLICY_STRUCTURE_MISMATCH` for an identity, or the rule that a format 3 reader reads to EOF before reporting a non-integrity code?
- Steps 1 to 8 use no secret and no network. Is anything secret-dependent reported before the age MAC is verified?
- (v0.15) A release in hand may be decoded on receipt, but its errors are reported only at step 10, after steps 1 to 9 (§47.1, §69.1). Does the order layers → `chain_hash` (`ERR_PROFILE_MISMATCH`) → round → signature leak anything, or let a release source learn something about a capsule?
### Q12. Long-term recovery and the provider (§7.6, §50, §71, §4 goal 6)
### Q12. Long-term recovery: the release object, the archives and step 9.c (§7.6, §47.1, §49, §50, §53, §62.1 rules 26 and 27, §63 steps 9 and 10, §79; v0.15)
- Is the written provider model (§7.6, v0.14) accurate and complete?
- **Known:** there is no defined release object or archive source (§74 future work); step 9.c lets the local clock refuse a release that step 10 would verify (§74 future work: "el uso del reloj local en el paso 9.c"); there is no recovery annex without DateKeys software; a capsule years ahead depends on someone keeping the release, the `.dkc` and, with a locator, the envelope rest (§50).
v0.15 gives long-term recovery a design (§76, «Cambios normativos de la v0.15»; `design_overview.md` section 8):
- **Release object (§47.1).** Is the record `{0: "datekeys-release", 1: 1, 2: chain_hash, 3: round, 4: signature}`, unsigned and without a "verified" flag, sound as the single form a cache, the Release API and an archive entry use? Is naming the chain by drand's `chain_hash`, checked against the pinned profile first at step 10 (`ERR_PROFILE_MISMATCH`), enough, given that drand's JSON, also accepted as input, names no chain? Any issue in the size limit (1 to 1024 bytes, `ERR_NON_CANONICAL_CBOR`) or in reporting its errors only at step 10?
- **Release in hand and step 9.c (§49, §63 step 9.c).** Since v0.15 a release in hand (a release object or drand's JSON from a file, or the entry of a local archive) is not compared with the local clock; 9.c applies only before a network request, and the person MAY ask a network source before `round_time`. The specification argues that a valid signature of a future round exists only if drand is compromised (§7.6), when the clock no longer protects confidentiality. Is that argument complete? Is there any risk in accepting a release in hand without the clock: for example a product that presents "opened before its date" in a misleading way, a test or debugging path that could be abused, or a future scheme where a signature for a future round could exist without a compromise?
- **Archives and cache services (§50).** Is it sound to rest long-term recovery on archives of all rounds and on cache services, local or remote, from DateKeys or others, verified with the pinned key and never trusted, rather than on a release kept next to each capsule (the rejected `.dkr`, §76 v0.15 change 4)? Is the informative archive format (a CBOR header, then fixed-size signatures, missing rounds as zeros) adequate, and is treating a zero-filled, short, other-chain or out-of-range entry as `ERR_RELEASE_UNAVAILABLE` at step 9 right? Is the privacy statement complete (a remote archive or cache service learns the round; a local one does not; keeping only the rounds of known capsules reveals their dates)?
- **The annex (§79).** Is the annex correct and sufficient to open a capsule decades later without DateKeys software, and is its list of what it does not check (§79.8) honest about the weaker guarantee?
- Is the written provider model (§7.6, v0.14) still accurate and complete with this design?
- **Known:** the specification promises no hosted archive or cache service; a project archive or service and its hosting are future work (§74), and none exists today. A capsule years ahead still depends on someone keeping the release of its round, the `.dkc` and, with a locator, the envelope rest (§50). If the network stops signing before the round, nothing opens the capsule (§7.6). The SDK rules 26 and 27 (warn when sealing; keep the annex next to the `.dkc`) are SHOULD and are not implemented in the clients yet; the Go CLI does not implement them either, nor the MAY of asking a network source before `round_time` (`docs/spec_v0.15/decisiones.md`, decision 11).
## 4. Known open problems (summary)
@ -119,7 +126,7 @@ So that they are not rediscovered. Sources: §74, §75, `docs/REVISION_completit
|---|---|---|
| K1 | Byte-level schemas of PUBLIC_HEADER, CONTROL_CBOR and `.dkk`, and the final field limits, are still provisional | §74, §75 item 1 |
| K2 | The 32 KiB area and the CMS algorithm table and certificate profile are unmeasured against real signatures, seals and OCSP responses | §74, §75 item 13 |
| K3 | No release object format, no archive source; the local clock at step 9.c can veto a verifiable release | §74 future work; review v0.13, 2.6 |
| K3 | No release archive or cache service is hosted, and the specification promises none: long-term opening depends on someone keeping the releases. (v0.15 closed the rest of this item: the release object and the archive format exist, and the clock no longer vetoes a release in hand.) | §50, §74 future work; review v0.13, 2.6 |
| K4 | No post-quantum access type; X25519, Ed25519, ECDSA, RSA and TSA signatures are not post-quantum | §7.7, §74 |
| K5 | The `.dkk` is 32 raw bytes with no MAC, password protection or check value | §38, §55.1; review v0.13, 2.8 |
| K6 | Key of words: PBKDF2 is not memory-hard; entropy only a SHOULD | §38.1; review v0.13, 3.3 |
@ -133,7 +140,7 @@ So that they are not rediscovered. Sources: §74, §75, `docs/REVISION_completit
| K14 | `kilic/bls12-381` is archived; `drand/tlock` has had no tagged release since August 2024 | `datekeys-go/SECURITY.md` |
| K15 | The `datekeys.` prefix of `extension_id` is used but not reserved | review v0.13, 2.8 |
| K16 | Three formats must be read forever, which multiplies cases in §64 and §69.1 (decided: capsules of older formats exist) | §70; review v0.13, 3.4 |
| K17 | Editorial: header line 8 says «Implementación de referencia prevista»; §1 lists the Release API and Release Cache among what the document defines, while §45 to §47 only sketch them; the second list of §74 ends with a semicolon | review v0.13, 3.8 |
| K17 | Editorial, still in v0.15: header line 8 says «Implementación de referencia prevista»; §1 lists the Release API and Release Cache among what the document defines, while §45 to §47 fix only what they serve (the release object) and leave the HTTP form informative, and no service exists; the second list of §74 ends with a semicolon | review v0.13, 3.8 |
## 5. Not a question: stated non-goals

@ -1,6 +1,6 @@
# DateKeys v0.14: threat model, goals and non-goals
# DateKeys v0.15: threat model, goals and non-goals
*Informative English summary of spec §3, §4, §5, §7, §36.1, §55, §55.1 and §55.2 of `DateKeys_Protocol_Specification_v0.14.md`. The Spanish text is the reference. Additions of v0.14 are marked **(v0.14)**.*
*Informative English summary of spec §3, §4, §5, §7, §36.1, §55, §55.1 and §55.2 of `DateKeys_Protocol_Specification_v0.15.md`, with §45 to §50 and §79 where they concern recovery and the clock. The Spanish text is the reference. Additions of v0.14 are marked **(v0.14)**, those of v0.15 **(v0.15)**.*
## 1. Guiding principle (§3)
@ -8,7 +8,7 @@ Never trust the server when the same property can be verified cryptographically
- date → condition is computed locally;
- provider profiles are pinned locally;
- releases are verified locally;
- releases are verified locally, whatever their source: a relay, the Release API, a cache service, an archive or a copy in the caller's hand **(v0.15:** §47.1, §49, §50**)**;
- `.dkc`, `.dkk`, APIs and relays are untrusted inputs;
- DateKeys must not need the plaintext or final access secrets.
@ -19,7 +19,7 @@ Never trust the server when the same property can be verified cryptographically
3. **Local verifiability.** The SDK detects tampered conditions, profiles and releases.
4. **Integrity.** Changes to the framing, header, control or payload cause failure.
5. **Interoperability.** Independent implementations produce and consume compatible objects.
6. **Independent recovery.** If the provider keeps or can serve the release, the ciphertext is still available and the credentials exist, a mature object should open without the DateKeys API.
6. **Independent recovery.** If the provider keeps or can serve the release, **(v0.15)** or a release archive or a cache service keeps it (§50), the ciphertext is still available and the credentials exist, a mature object should open without the DateKeys API, **(v0.15)** and even without DateKeys software (§79).
7. **Extensibility.** New providers and extensions do not redefine old objects.
8. **Metadata privacy.** Before the date, a format 2 or 3 capsule does not reveal the exact content length or the number of credentials. Format 3 also hides paths, sizes, hashes, dates, comment, declared author and the number of files beyond the bound given by the padding (§55.2).
9. **Optional authenticity.** A format 3 capsule may carry signatures from one or more signers and a time seal. The opener can check that those signers signed this content for this control and, with a seal, that the signature existed before the capsule could be opened (§29.8 to §29.11). Without a signature, a capsule proves no authorship (§36.1).
@ -52,7 +52,7 @@ Out of scope (§6): where a `.dkc` is stored, how it is discovered or distribute
### 4.1 DateKeys server (§7.1)
May try to return a past round, a fake profile or invalid releases; correlate queries; serve stale data; keep copies of the ciphertext. Defences: local round resolution and the past-round check (§15, §17), the pinned profile (§12, §13), local BLS verification (§51), the Release API being keyed by round and not by capsule (§45).
May try to return a past round, a fake profile or invalid releases; correlate queries; serve stale data; keep copies of the ciphertext. Defences: local round resolution and the past-round check (§15, §17), the pinned profile (§12, §13), local BLS verification (§51), the Release API being keyed by round and not by capsule (§45). **(v0.15)** The Release API answers with the release object (§47.1), and its user is a network source that verifies every answer and discards a bad one (§45, §49); the object carries no "verified" flag, which would have no value (§51). No DateKeys service offers the Release API today; the implementations fetch releases from drand relays (§45).
### 4.2 Relay, MITM, DNS (§7.2, §52)
@ -70,7 +70,7 @@ Must be treated as holding a sensitive capability. The `.dkk` is 32 raw bytes wi
A compromised SDK or dependency can replace the root of trust, accept false conditions, exfiltrate secrets or weaken the cryptography. §59 lists SHOULD measures: pinned crypto dependencies, SBOM, signed releases, published hashes, signed profiles, reproducible builds, fuzzing, published vectors, and an external cryptographic review of v1.0.
### 4.6 Provider (§7.6) (v0.14)
### 4.6 Provider (§7.6, §50) (v0.14; recovery v0.15)
A `time_only` capsule depends on a single provider (Quicknet in V1) and has no other way to open: no DateKeys key, recovery or service opens it before or after the date. Two separate things depend on the provider:
@ -79,6 +79,16 @@ A `time_only` capsule depends on a single provider (Quicknet in V1) and has no o
A `time_and_key` capsule adds a credential the provider does not have: an early signature of the round is not enough, but a missing round leaves it just as closed (§36.1). The official SDK SHOULD recommend it for long horizons or valuable content. A pinned profile is identified by its `profile_hash`; a provider that changes key, period or chain is another profile, and existing capsules still depend on the old one.
**(v0.15) Long-term recovery.** The release is the only thing a capsule needs that does not exist when it is sealed: it is published at `round_time`. Once the round is signed, opening years later depends on someone keeping that release. v0.15 places long-term recovery on release archives with all rounds of the chain and on cache services, from DateKeys or others, that keep and serve the releases of all rounds continuously (§50). Whoever serves a release need not be trusted: for one round and one public key there is a single valid BLS signature, checked against the pinned profile at step 10 (§47.1). What v0.15 does not change:
- if the network stops signing before a capsule's round, nothing opens it; archives keep only rounds that were signed;
- the specification promises no published archive or cache service and says nothing about hosting; a project archive or service is future work (§74). Today a capsule whose round is signed depends on drand relays keeping it, or on whoever keeps an archive;
- the release archive format is informative (§50), with no error codes of its own;
- an archive that keeps only the rounds of known capsules would reveal their dates, and is not recommended (§50);
- the official SDK SHOULD warn when sealing that opening years later needs the `.dkc`, the `.dkk` in `time_and_key`, and the release, and SHOULD keep the recovery annex next to the `.dkc` (§53, §62.1 rules 26 and 27).
The rejected alternative, a `.dkr` release file kept next to each capsule, did not cover the case that matters, someone opening decades after the date when nobody kept anything for that capsule (§76, v0.15 change 4).
Profile registry states (§71, v0.14): `activo` (write and open); `solo lectura` (no new capsules; existing ones still open); `comprometido` (evidence that confidentiality failed; existing capsules still open; the SDK SHOULD warn that the content may have been read before the date). A published entry is never removed.
### 4.7 Future quantum adversary (§7.7, §53) (v0.14 extended)
@ -109,6 +119,16 @@ With a signature or seal in format 3:
A client the browser downloads on each visit, such as a page that encrypts or opens capsules, can be replaced by whoever serves the page, controls its domain or compromises its build. A replaced client can copy the content, the credentials and the words of a key before encrypting or after opening, or write a capsule that will not open. No format rule detects it: the capsule it writes is valid. §59 asks (SHOULD) for reproducible builds with published hashes, Subresource Integrity on every script, a content policy that loads no code from another origin, and the same client usable offline.
### 4.11 The reader's local clock (§17, §49, §63 step 9.c) (v0.15)
Not an adversary section of §7, but a change of v0.15 in what the clock decides:
- Before v0.15, step 9.c refused to open when the local time was before the DateKey's `round_time`, even with a release that step 10 would verify.
- Since v0.15, 9.c applies only before a network request: a network source is not asked before `round_time` (the reasons are network ones: no useless or observable requests, fail early). The person MAY expressly ask for the request anyway, because the clock may be wrong.
- A **release in hand** (a release object or drand's JSON from a file, or the entry of a local archive) is not compared with the clock; the reader MAY warn that its clock may be behind. A valid signature of a future round exists only if the provider is compromised (§7.6), and then the clock no longer protects confidentiality. The clock had been vetoing a verifiable release on a local value nobody can verify (§3), for example on a machine with a dead CMOS battery or a virtual machine (§76, v0.15 change 3).
- Whatever the clock says, opening still needs the signature of the round, verified at step 10 against the pinned key (§51).
- The writer's clock is unchanged: a writer with a clock running late can still seal to an already published round (§62.1 rule 2, section 8).
## 5. Authenticity semantics (§36.1)
- `time_only` provides **no creator authenticity**, before or after maturity, unless an author signature (§29.8) or a signature extension adds it.
@ -143,7 +163,7 @@ Formats 2 and 3 (format 1 reveals more):
- **After the date:** `time_only`: anyone reads everything. `time_and_key`: anyone sees the INNER header with 16 stanzas; CONTROL_CBOR and the content stay hidden from those without a credential; a credential holder learns which stanza is theirs but not which of the other 15 are decoys; several credential holders together learn only a lower bound on the number of credentials.
- **Never visible** (under Diffie–Hellman in X25519): the recipients; whether a stanza is a decoy; whether a portable `.dkk` exists; the number of credentials beyond the lower bound above.
- **Signature and seal:** before the date, whether a capsule is signed is hidden while it uses the common 32 KiB area; a 64 KiB area reveals it; a v0.10 capsule with a 512-byte area reveals it carries no seal when P is small. Signers and TSA names are visible after the date (to anyone in `time_only`), including a signer's national identifier in the certificate. OCSP requests, often over unencrypted HTTP, reveal the certificate serial number; a writer that uses an intermediary for OCSP or the seal MUST declare it.
- **Outside the `.dkc`:** a `.dkk` carries the credential in clear, plus `capsule_id`, `credential_id`, the optional `capsule_digest` and extension data; `datekeys.capsule` carries the note and the date in clear and the locator encrypted to the date; the host of an envelope rest sees random bytes and their size; fetching a release reveals the profile, round and requester address to the API and relays, not `capsule_id`.
- **Outside the `.dkc`:** a `.dkk` carries the credential in clear, plus `capsule_id`, `credential_id`, the optional `capsule_digest` and extension data; `datekeys.capsule` carries the note and the date in clear and the locator encrypted to the date; the host of an envelope rest sees random bytes and their size; fetching a release reveals the profile, round and requester address to the API and relays, not `capsule_id`; **(v0.15)** the same holds for a cache service and a remote archive (read, for example, with an HTTP range), which are network sources, while a local archive or a release in hand reveals nothing (§49, §50).
- **Format 1:** SEALED_CONTROL_LEN grows 98 bytes per INNER stanza, and the PAYLOAD_AGE length gives L exactly.
## 8. Things the specification already says are not checked
@ -156,3 +176,6 @@ These are stated limits, not findings:
- A writer with a clock running late can seal to an already published round; comparing with the last published round is only a MAY (§62.1 rule 2).
- The `.dkk` has no integrity check of its own (§55.1).
- DateKeys never checks who issued a certificate or a seal (§29.10, §29.11).
- **(v0.15)** No release archive or cache service is promised or hosted; long-term opening depends on someone keeping the releases (§50, §74).
- **(v0.15)** A release in hand is not compared with the reader's clock (§63 step 9.c).
- **(v0.15)** The recovery annex does not check canonical encodings, `header_binding`, the 16 stanzas, the zero padding or the path rules; a capsule a conforming reader would reject may open by the annex (§79.8).

@ -2,6 +2,8 @@
*7 de octubre de 2026. El borrador está en la rama `v0.15` de `datekeys-go` (`b7402bd`), en `spec/DateKeys_Protocol_Specification_v0.15.md`. Es la recuperación a largo plazo del [diseño](../diseno_recuperacion.md), con la opción A y las ocho recomendaciones que aprobaste el 6-10. Lo hizo un agente Opus; la sesión revisó el paso 9.c en el código. `scripts/check.sh` pasa entero, con un script nuevo que abre dos fixtures siguiendo solo el anexo.*
> **Nota del 7-10.** El autor rechazó el fichero `.dkr` antes de aprobar: la decisión 1 quedó sin el fichero ni su extensión, y la recomendación de la decisión 4 de guardarlo junto al `.dkc` o la `.dkk` se retiró, con la orden `datekeys release` y `decrypt -save-release`. El objeto release se queda y sale de archivos y servicios de caché (§50). La v0.15 aprobada (`spec-v0.15`, `fe50885`) lo registra en el §76, cambio 4. Lo que sigue es el borrador tal como se presentó.
Si apruebas lo que sigue tal como está, basta con decir «apruebo el borrador». Al aprobarlo se cierra como la v0.14 y se lleva a TypeScript, a Dart y al paquete de la revisión externa.
## Lo que hace el borrador

Loading…
Cancel
Save

Powered by TurnKey Linux.