You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
datekeys-doc/REVISION_completitud_protoc...

202 lines
19 KiB

# Revisión de completitud del protocolo DateKeys v0.8.2
29 de septiembre de 2026. Revisión interna asistida por IA, no una revisión externa. La hicieron cuatro revisores automáticos con enfoques distintos (criptografía y seguridad, longevidad, casos de uso, madurez del spec), y un verificador contrastó cada hueco con el texto del spec antes de esta síntesis. Los números de línea se refieren a `spec/DateKeys_Protocol_Specification_v0.8.2.md` de `datekeys-go`.
Lo que ya recoge el borrador v0.9 (rama `v0.9` de `datekeys-go`):
- el versionado, con la promesa de compatibilidad (punto 1);
- las reglas del escritor (punto 2);
- la privacidad, con los 16 huecos fijos y el relleno del contenido (punto 7b).
El resto queda como trabajo futuro, en §74 del borrador.
---
## 1. Veredicto
No, no lo resuelve todo, y el propio texto tampoco lo pretende. El núcleo criptográfico es sólido para lo que promete: una fecha mínima de apertura que el cliente comprueba por sí mismo y, si se quiere, una llave encima. Antes de la v1.0 no hace falta criptografía nueva. Hace falta decidir qué se congela, reglas para quien escribe cápsulas, un modelo de amenaza del proveedor bien escrito, una revisión externa humana y dos piezas que casi todos los casos reales necesitan: la firma y el archivo de releases.
## 2. Lo que hace especialmente bien
1. **No confía en el servidor para nada que el cliente pueda comprobar.** §3 l.54: «Nunca confiar en el servidor cuando la misma propiedad puede verificarse criptográficamente en el cliente». Y lo cumple:
- el perfil va pinneado (§13 l.401);
- la ronda se calcula en local (§17);
- el release se verifica en local;
- la ronda se comprueba antes que la firma (§63 paso 10, l.1811-1823).
Si la empresa desaparece, las cápsulas siguen abriéndose. §49 l.1352 dice que la API es «no una autoridad criptográfica obligatoria». Esa es la diferencia de fondo con SealedFor, donde la fecha la impone el servidor.
2. **No inventa criptografía.** Son tres ficheros age v1 completos, y OUTER es un fichero tlock estándar. El MAC de cabecera, el STREAM y la detección de truncado vienen de age (§28 l.768-788, §30 l.863-878). §37 l.1115: «No se define un KEM propio».
3. **time_and_key es un AND de verdad y está anidado en el orden correcto.** tlock va por fuera (§33 l.981-1031). Antes de la fecha nadie ve los stanzas de los recipients. Si drand cae, la capa X25519 sigue protegiendo frente a terceros.
4. **Las vinculaciones están bien pensadas.**
- Hay tres file keys independientes (§28 l.788, §62 l.1735).
- I_PAYLOAD ata el payload al control (§30.1).
- header_binding hashea los bytes exactos del PRELUDE y de PUBLIC_HEADER, sin volver a serializarlos (§26).
- Cada intercambio posible tiene su test de mutación (§64).
- El MAC de age compromete la file key, así que el creador no puede enseñar plaintexts distintos a recipients distintos (§63 pasos 11 y 13).
- La cardinalidad de stanzas hace visible un escrow en OUTER y en PAYLOAD (§32 l.967, §29 l.849). En INNER, en cambio, un recipient extra es legítimo (§39).
5. **La canonicidad llega a todas las capas:**
- CBOR que se vuelve a codificar y se compara (§58);
- dk1_ canónico (§19);
- una sola codificación por punto BLS12-381 (§12.2);
- el orden de GT en H2, con su vector (l.1918-1926).
Esto reduce mucho las divergencias entre implementaciones, aunque no las elimina (puntos 2 y 5 de la sección 4). Varias de estas reglas salieron de fallos reales encontrados por la segunda implementación (§76).
6. **El modelo de confianza es honesto y normativo.** §36.1 l.1093: «`time_only` **NO proporciona autenticidad del creador**». §55.1 l.1503 prohíbe con un MUST NOT presentar una sección como prueba de lo que no prueba. Además, todo lo que se puede comprobar en local se comprueba antes de cualquier petición de red (§27 l.758). La Release API pide por ronda, no por cápsula (§45).
## 3. Lo que deja fuera a propósito, y por qué es razonable
1. **Que Quicknet exista siempre y que su histórico se conserve (§5 l.97-98).** Nadie puede garantizar una red ajena. Esto excluye de paso cualquier vía de respaldo: OUTER lleva «exactamente un stanza, de tipo tlock» (§32 l.967). Es coherente, porque es lo que da sentido a la defensa estructural contra el escrow de §27 l.760. Lo que falta es escribir el coste (punto 3 de la sección 4).
2. **Resistencia post-cuántica del timelock (§5 l.99, §7.7, §53).** Hoy no hay ningún beacon de umbral post-cuántico en producción. Un matiz: la exclusión solo cubre el timelock. El texto fija además X25519 en la capa de acceso (§33 l.1002), y eso ninguna exclusión lo obliga (punto 1).
3. **Revocar copias, anonimato absoluto, dispositivo comprometido y control del plaintext tras abrir (§5 l.100-105, §7.8).** Es inherente a cualquier cifrado de ficheros. El anonimato está bien como no-objetivo, pero falta decir qué queda siempre visible (punto 7).
4. **Autoría legal y fecha probatoria de creación (§5 l.102-103, §36.1, §55.1).** Un timelock dice cuándo se puede abrir, no quién selló ni cuándo. Está bien fuera del núcleo.
- La autoría depende de una extensión de firma que aún no existe (punto 8).
- La fecha de creación se puede cubrir con un sello de tiempo (RFC 3161 u OpenTimestamps) sobre capsule_digest, en un fichero aparte.
5. **Almacenamiento, descubrimiento, distribución y entrega de la .dkk (§6 l.109-120).** Es una buena separación de capas. Por la misma razón, los umbrales N-de-M y el AND de varias llaves no deben ir al núcleo: se construyen anidando cápsulas o en la capa de credencial. Si algún día se hace Shamir para herencia, conviene revisar antes las patentes de SafeTech/Inheriti.
## 4. Lo que abordaría antes de la v1.0, por orden de importancia
### 1. Versionado: qué se congela y cómo evoluciona (núcleo)
- **Problema:** no está decidido si un lector v1.0 abrirá las cápsulas v0.8.2, y los lectores v1 verán los objetos futuros como corruptos.
- **Por qué importa:**
- La fase 3 va a sellar cápsulas con fecha a años vista.
- §74 l.2306-2308 sigue dando por provisional el «schema CBOR final byte-a-byte» de los tres objetos.
- La v0.8.2 ya invalidó objetos v0.8.1 sin cambiar de versión (§76 l.2390).
- Hacia delante, un `access_policy` 2 da `ERR_NON_CANONICAL_CBOR` (§69.1 l.2116).
- §70 l.2139 habla de «major versions», un concepto que el formato no tiene.
- **Propuesta:**
- Congelar el formato en bytes de la v0.8.2: la v1.0 solo añade reglas que ningún objeto válido incumpla. Los fixtures y el corpus de mutaciones pasan a ser una suite permanente.
- Añadir a §70: «toda implementación posterior MUST abrir todo objeto DKC1/DKK1 versión 1 válido».
- Regla de evolución: una política, un tipo de acceso o un proveedor nuevos implican schema N+1 o prefijo `dk2_`. Así un lector v1 responde `ERR_UNSUPPORTED_VERSION`.
- Decidir ahora si entra el access_type `mlkem768x25519`. Lo trae age v1.3.2, que ya usan las dos implementaciones. En INNER, los stanzas serían todos X25519 o todos híbridos, nunca mezclados. Después de congelar, añadirlo exige versión nueva.
- Sustituir §74/§75 por una tabla de estado (elemento, estado, evidencia, criterio de salida).
- Quitar «prevista» de l.8.
### 2. El lado del escritor (núcleo)
- **Problema:** la especificación dice con precisión cómo leer, pero no cómo escribir, y un escritor defectuoso produce cápsulas que solo fallan en la fecha.
- **Por qué importa:** en un timelock, el peor fallo es una cápsula que parece sana durante veinte años. El caso 5 de §76 (l.2387) ya produjo una que se sellaba y no se abría. Hoy:
- El orden de §61 l.1674-1686 es circular. El PRELUDE se hashea en el paso 7, pero SEALED_CONTROL_LEN no existe hasta el paso 9. Go lo resuelve con un sellado borrador y una suposición que no está escrita.
- Ningún escritor descifra lo que escribe.
- Los límites «No son normativos» (§74 l.2315). Un escritor puede sellar 1.025 recipients y la referencia rechaza la cápsula tras la apertura.
- I_PAYLOAD no tiene ningún MUST de frescura ni de no reutilización; solo lo tiene I_ACCESS (§38 l.1132). Si se reutiliza, al madurar la cápsula A se puede abrir la B años antes.
- Nada exige que la ronda objetivo siga sin publicarse. Con el reloj atrasado se crea una cápsula que cualquiera puede abrir ya (App/docs/PLAN_fase3_escritura.md l.479).
- **Propuesta:**
- Una sección normativa de escritura con el orden correcto y la regla de predicción de longitud.
- Los límites como MUST para lectores y escritores.
- «I_PAYLOAD MUST generarse con un CSPRNG para cada cápsula y MUST NOT reutilizarse ni derivarse de otro secreto». Pasar §28 l.788 a MUST NOT.
- MUST rechazar un instante que no sea futuro. SHOULD tomar now = max(reloj local, round_time del último release verificado); un relay que mienta no puede empeorarlo.
- SHOULD autoverificarse antes de emitir: abrir INNER con cada identidad generada, abrir la cabecera de PAYLOAD con I_PAYLOAD y hacer una prueba tlock con respuesta conocida sobre una ronda ya publicada.
- SHOULD borrar I_PAYLOAD, FK_* e I_ACCESS tras sellar.
- Publicar vectores de escritura por capa.
### 3. El riesgo del proveedor, bien escrito (núcleo en el texto y los estados de perfil; servicio para el re-sellado)
- **Problema:** el mayor riesgo real ocupa una sola frase: «Si deja de cumplirse el supuesto de seguridad del provider, puede fallar la confidencialidad temporal» (§7.6 l.176).
- **Por qué importa:**
- Si t miembros de la League of Entropy se ponen de acuerdo, o se les obliga, o se filtra la clave de grupo, se abren todas las cápsulas pendientes a la vez. Nadie lo nota y no tiene vuelta atrás.
- El resharing conserva la clave de grupo, así que la exposición crece con el horizonte.
- Si la red se para antes de la ronda, la cápsula se pierde. drand programó el borrado de la clave de fastnet para el 6 de noviembre de 2024, y §12.1 l.338 todavía admite su scheme.
- El único aviso obligatorio de horizonte largo (§53 l.1406-1412) habla solo del riesgo post-cuántico, y lo describe como harvest-now-decrypt-later. Para time_only el riesgo cuántico es otro: abrir antes de tiempo, porque la clave maestra de drand se puede sacar de la clave pública pinneada.
- **Propuesta:**
- Reescribir §7.6: el supuesto t-de-n con fuente y fecha, qué pasa si se rompe y qué pasa si la red se para.
- Escribir en §5 y §73: «un .dkc V1 no contiene ninguna vía alternativa de apertura; si un perfil deja de operar antes de la ronda, solo puede re-sellar quien conserve el plaintext».
- Unir §50 y §53 en un único aviso normativo. El riesgo cuántico va en dos casos: time_only (apertura anticipada) y time_and_key con recipients age1 públicos (descifrado posterior).
- Recomendar time_and_key para cápsulas largas o valiosas, porque sigue protegiendo frente a terceros tras una brecha de drand. Hoy §36.1 l.1099 lo presenta solo como «una barrera adicional de acceso».
- Dar valores al campo «estado» de §71:
- `active`;
- `deprecated`: no se sella nada nuevo;
- `halted_after_round N`: se rechazan las rondas posteriores y el lector las declara irrecuperables;
- `compromised_since T`: se muestra un aviso.
- Añadir: «un perfil publicado nunca se retira de los lectores conformes».
- En el servicio: ofrecer re-sellado cuando se anuncie un apagado.
### 4. Revisión externa y evidencia de independencia (proceso)
- **Problema:** el punto 10 de §75 sigue abierto, y la evidencia actual es más débil de lo que sugiere el texto.
- **Por qué importa:**
- §76 l.2429 atribuye correcciones a «la revisión formal e independiente». En realidad fue una revisión hecha por agentes en estas mismas sesiones.
- TypeScript sigue los textos de error de Go «byte a byte» (HANDOFF l.44), y §16 l.498 exige que los vectores salgan de la referencia.
- Las 407.196 entradas diferenciales prueban que TypeScript coincide con Go. No prueban que el texto baste para implementar.
- Los objetivos de §4 son informales.
- **Propuesta:**
- Una revisión criptográfica humana, con revisor, alcance y fecha anotados en §76.
- Etiquetar la revisión actual como interna y asistida por IA.
- Un anexo breve de modelo de seguridad: los adversarios de §7, qué se garantiza antes de la ronda, la confidencialidad del factor de acceso, la integridad frente a quien no tiene la llave y qué vale frente al creador.
- Una tercera implementación hecha por otra persona sin ver el código existente, solo con la spec y testdata, anotando cada pregunta que surja.
- Antes de la revisión: la versión inglesa y una regla de precedencia. El texto manda sobre el CDDL y testdata/README, y hay que declarar el idioma normativo.
### 5. Raíz de confianza y algoritmos de verificación (núcleo)
- **Problema:** para verificar un release hay que leer código ajeno, y la raíz de confianza tiene una puerta sin especificar.
- **Por qué importa:**
- El paso 10 verifica «según el scheme de drand» (l.1818).
- H3 y H4 son las de kyber (l.1843-1847).
- El mensaje de ronda y el DST no aparecen en el texto.
- §12.1 admite tres schemes, y las implementaciones ya divergen: Go acepta los tres y TypeScript solo el de Quicknet.
- §12 l.323 permite «una representación firmada equivalente» sin decir quién firma ni si puede introducir un profile_id nuevo. Quien tenga esa clave podría publicar una red falsa coherente.
- **Propuesta:**
- Limitar §12.1 a `bls-unchained-g1-rfc9380`.
- Junto a «Serialización de GT en H2», escribir msg = SHA-256(uint64_be(round)), el DST, Q_ID = hash_to_G1(msg, DST), H3 (con su iteración y su máscara) y H4.
- Poner valores intermedios en tlock_ibe.json y citar ePrint 2023/189 y RFC 9380.
- Para V1, pinnear Quicknet en el código y quitar «o una representación firmada equivalente». La alternativa es especificar esa clave, su distribución y su rotación.
### 6. Recuperación a largo plazo (núcleo para el objeto, el paso 9.c y el anexo; servicio para el archivo)
- **Problema:** el release, que es la pieza que abre la cápsula, no tiene formato definido, y el reloj local puede vetar uno válido.
- **Por qué importa:**
- §1 dice que el documento define la Release API y la Release Cache, pero §47 l.1313 deja `release_material` sin definir. Nadie puede guardar el release de su cápsula junto al .dkc en una forma que cualquier lector acepte.
- §49 solo nombra relays de drand, y fastnet demostró que los relays pueden dejar de servir una red entera.
- El paso 9.c (l.1800-1801) da `ERR_RELEASE_UNAVAILABLE` si el reloj va atrasado, aunque se aporte un release que el paso 10 verificaría. Así, un dato local que no se puede verificar pesa más que uno que sí: lo contrario de §3.
- La recuperación sin software DateKeys no está escrita. tle solo se prueba con time_only, y fuera de scripts/check.sh.
- **Propuesta:**
- Un objeto release canónico (profile_id, round, signature) en CBOR determinista y en JSON, con semántica HTTP: 200; 404 antes de round_time; 400 si el perfil es desconocido. La alternativa es pasar §45-§47 a un anexo informativo.
- Añadir «release desde fichero o archivo» como fuente en §49.
- SHOULD guardar el release verificado junto a la cápsula cuando madure.
- Aplicar 9.c solo a las fuentes de red y caché.
- Un anexo informativo «Recuperación sin software DateKeys»: offsets del PRELUDE, tle, la clave 3 de CONTROL_CBOR como AGE-SECRET-KEY-1 y age. Añadir un caso time_and_key a las pruebas locales.
- En el servicio: un archivo completo de Quicknet en instantáneas que cualquiera pueda replicar. Son 48 bytes por ronda, unos 505 MB al año, y cada release se verifica por sí solo.
### 7. Escribir lo que no garantiza (núcleo para el texto; extensión para el relleno; servicio para redondear horas)
- **Problema:** cuatro límites reales no están en el texto, y un texto de producto podría prometer lo contrario.
- **Por qué importa:**
- **(a)** Nadie puede comprobar antes de la fecha que una cápsula abrirá. La ronda del stanza tlock es una etiqueta que nada liga al cifrado IBE. Un creador puede cifrar a otra ronda, o romper el stanza de un solo recipient, y se descubre tras el release (pasos 11 y 13). En pujas o predicciones, eso le permite no revelar. §4 l.77 («El SDK debe detectar condiciones, perfiles y releases manipulados.») puede leerse como una promesa mayor.
- **(b)** Hay metadatos siempre visibles: la ronda, la política, el número de recipients y el tamaño exacto del plaintext. En los fixtures, SEALED_CONTROL_LEN vale 446, 646 y 842 bytes (98 por recipient). Un PAYLOAD_AGE de 78.216 bytes corresponde exactamente a 78.000 bytes de plaintext.
- **(c)** En el cliente web, el mismo origen del que §3 desconfía sirve el código que maneja el plaintext, I_PAYLOAD e I_ACCESS. §7.1 no lo menciona.
- **(d)** La caducidad, las condiciones por evento, varias fechas en un objeto y cancelar antes de la fecha no están en §5.
- **Propuesta:**
- Añadir a §5: «verificar antes de la madurez, frente a un creador malicioso, que la cápsula se abrirá o que su ronda es la declarada». Añadir también los no-objetivos de (d).
- Añadir a §4 un objetivo de unicidad de apertura, con sus supuestos.
- Una sección «Consideraciones de privacidad» con la lista de metadatos visibles y un relleno opcional:
- recipients X25519 ficticios hasta un tamaño fijo, lo que no cambia el protocolo;
- una extensión crítica de CONTROL_CBOR con la longitud real del payload.
- Añadir «servir un cliente web malicioso» a §7.1. En §59: hashes de build publicados, URLs versionadas inmutables, SRI y una build offline.
- En producto, redondear la hora de apertura al minuto.
### 8. Firma del creador y .dkk protegida (extensión)
- **Problema:** las dos piezas que casi todos los casos reales necesitan (herencia, pujas, embargos) son extensiones sin definir.
- **Por qué importa:**
- §27 l.764 dice: «Solo una extensión de firma puede aportar autenticidad del creador». No hay ninguna registrada.
- Colocar la firma tiene trampas. En PUBLIC_HEADER es circular con header_binding. Debe cubrir SHA-256(PAYLOAD_AGE), porque §55.1 l.1509 admite que, tras abrir, se puede cifrar otro payload. Eso obliga a escribir en dos pasadas. Y en time_only cualquiera puede quitarla y volver a sellar.
- La .dkk son «32 bytes crudos» (§38 l.1130) y «no lleva MAC ni firma» (§55.1 l.1510). Un bit cambiado se descubre en la fecha. Sin un formato estándar protegido con contraseña, cada aplicación inventará el suyo.
- **Propuesta:**
- Registrar `datekeys.signature` v1 en CONTROL_CBOR antes de la revisión externa, para que se revise junto al resto.
- La firma lleva una etiqueta de dominio y cubre header_binding, SHA-256(PAYLOAD_AGE) y los bytes exactos de las demás extensiones.
- Su ausencia no es un error. El firmante esperado se conoce por fuera de la cápsula.
- Mutaciones nuevas: firma quitada, payload recifrado y control trasplantado.
- Para la .dkk: una forma opcional dentro de un fichero age con scrypt, y un valor de comprobación de 4 bytes, SHA-256("datekeys-dkk-check" || I_ACCESS), en verification_metadata.
- De paso, reservar el prefijo `datekeys.` en extension_id y exigir a terceros nombres de dominio invertidos (§31 l.919).
## 5. Frase final
Es un núcleo bueno y honesto, pero no un sistema completo: antes de la v1.0, congela lo que después no podrás cambiar y escribe lo que no garantiza, antes de que lo prometa un texto comercial.

Powered by TurnKey Linux.