|
|
# datekeys-go
|
|
|
|
|
|
Implementación de referencia en Go de la **DateKeys Protocol Specification
|
|
|
v0.16** ([`spec/`](spec/DateKeys_Protocol_Specification_v0.16.md)), etiquetada
|
|
|
`spec-v0.16`: un sello sin precisión no acredita nada antes de la fecha de
|
|
|
apertura, el JSON de drand se lee de forma estricta y el anexo para abrir una
|
|
|
cápsula sin software de DateKeys deriva también una llave de palabras. La
|
|
|
v0.15 trajo la recuperación de cápsulas a largo plazo: el objeto release, un
|
|
|
release en la mano que el reloj no detiene, y archivos y servicios de caché
|
|
|
que guardan los releases de todas las rondas.
|
|
|
[English version](README.md).
|
|
|
|
|
|
DateKeys cifra datos de forma que solo puedan abrirse a partir de un instante
|
|
|
elegido. La condición temporal procede del beacon de aleatoriedad **Quicknet**
|
|
|
de drand: los datos se sellan con cifrado timelock hacia una ronda futura, y la
|
|
|
firma BLS de esa ronda, que drand publica cuando llega, es la llave. Todo lo que
|
|
|
se puede verificar localmente se verifica localmente; relays, cachés y APIs son
|
|
|
transportes no confiables.
|
|
|
|
|
|
> **Estado: v0.x, pre-estándar.** La especificación es un borrador y la API
|
|
|
> puede cambiar antes de v1.0.0. El código aún no ha pasado una revisión
|
|
|
> criptográfica externa (spec §75). No lo uses para secretos de alto valor.
|
|
|
|
|
|
## Qué implementa
|
|
|
|
|
|
| Objeto | Spec | Paquete |
|
|
|
|---|---|---|
|
|
|
| DateKey: fecha → ronda, cadena canónica `dk1_…` | §14–§19 | [`datekey`](datekey) |
|
|
|
| Provider Profile, perfil Quicknet pinneado, `profile_hash` | §10–§13 | [`profile`](profile) |
|
|
|
| Fuentes de releases, verificación BLS local, relays drand | §45–§52 | [`provider`](provider), [`provider/drand`](provider/drand) |
|
|
|
| DateKeyCap `.dkc`: `time_only` y `time_and_key`, los ficheros del formato 3, el área de seguridad y sus veredictos | §20–§39, §61–§63 | [`capsule`](capsule) |
|
|
|
| Rutas y textos del head, con las tablas de Unicode 18.0.0 y best-fit | §29.5, §29.6 | [`internal/pathrule`](internal/pathrule) |
|
|
|
| Firma de autor: qué se firma, `alg` 1 y 2, el sello de `seal_type` 2 | §29.8–§29.11 | [`capsule`](capsule) |
|
|
|
| Claves de autor `dkauthor1…` y el Ed25519 estricto de `alg` 1 | §29.9, §29.12 | [`authorkey`](authorkey), [`internal/ed25519strict`](internal/ed25519strict) |
|
|
|
| Firma con certificados (`alg` 2, CMS) y sello de tiempo (RFC 3161): DER, el perfil del certificado, la tabla cerrada de algoritmos | §29.10, §29.11 | [`internal/cms`](internal/cms), [`internal/der`](internal/der) |
|
|
|
| La nota pública `datekeys.note` | §24.1 | [`extension`](extension), [`capsule`](capsule) |
|
|
|
| Llave de palabras | §38.1 | [`wordkey`](wordkey) |
|
|
|
| DateKeys Access Key `.dkk` | §40–§44 | [`accesskey`](accesskey) |
|
|
|
| La extensión `datekeys.capsule`: localizador, sobre y direcciones | §44.1 | [`locator`](locator) |
|
|
|
| Extensiones y su registro | §54, §72 | [`extension`](extension) |
|
|
|
| CBOR determinista | §58 | [`codec`](codec) |
|
|
|
| Errores normativos | §69 | [`errors.go`](errors.go) |
|
|
|
| CLI | — | [`cmd/datekeys`](cmd/datekeys) |
|
|
|
|
|
|
Aquí no se implementa criptografía. El cifrado es [age](https://age-encryption.org)
|
|
|
(`filippo.io/age`); el timelock es [tlock](https://github.com/drand/tlock)
|
|
|
(solo su núcleo exportado); la verificación BLS es la de drand; las firmas de
|
|
|
autor y los sellos se verifican con la biblioteca estándar de Go, con el perfil
|
|
|
estricto de Ed25519 comprobado alrededor de `crypto/ed25519`. Este módulo
|
|
|
aporta framing, CBOR, DER, bindings, reglas de verificación y flujo, y aplica
|
|
|
las reglas de stanzas del protocolo dentro de las identities de age, para que
|
|
|
un fichero nunca se acepte solo porque age haya podido desenvolver una clave.
|
|
|
|
|
|
No implementa, a propósito: el servidor y la cola de la Release API, el
|
|
|
almacenamiento y la entrega, la descarga del resto de un sobre ni el cliente
|
|
|
TypeScript (plan §2). El paquete `locator` comprueba las direcciones de un
|
|
|
localizador y lo que un lector trae de ellas, y no descarga nada (spec §44.1).
|
|
|
La firma con certificados y el sello comprueban la criptografía, nunca quién
|
|
|
emitió un certificado o un sello ni si se revocó: eso lo hace un validador
|
|
|
oficial (spec §29.10). Las curvas brainpool y los algoritmos nacionales como
|
|
|
GOST o SM2 quedan fuera de la tabla.
|
|
|
|
|
|
## Versiones
|
|
|
|
|
|
Hay tres números de versión, cada uno con su significado:
|
|
|
|
|
|
| Versión | Dónde | Cambia cuando |
|
|
|
|---|---|---|
|
|
|
| Formato | Dentro de los objetos: el formato de la cápsula, el `VERSION` del prelude de DKC1, 3 al escribir y de 1 a 3 al leer, que es también la versión de schema de CONTROL_CBOR; y 1 en la trama de DKK1 y en el schema de los demás objetos, incluidos el head y `security` del formato 3 | Cambia el formato. Un lector rechaza una versión que no conoce (spec §22, §70) |
|
|
|
| Especificación | `datekeys.SpecVersion`, hoy `0.16`, y el tag `spec-v0.16`. Un borrador, como lo fue la v0.16, no tiene tag ni la cambia | Cambia el texto normativo. §76 del spec recoge cada cambio con su caso |
|
|
|
| Módulo | Los tags de este módulo Go, `vX.Y.Z`, y `datekeys.Version()` | Cambia la API o el comportamiento. Versionado semántico, sin promesa de estabilidad antes de v1.0.0 |
|
|
|
|
|
|
`datekeys version` imprime la versión del módulo, la del spec y la del toolchain de Go. Un binario compilado en un checkout muestra la pseudo-versión de su commit, por ejemplo `v0.0.0-20260928105528-9ac9cd952f04`.
|
|
|
|
|
|
Cada release dice qué cubre, aquí y en el [CHANGELOG](CHANGELOG.md). El código de esta rama, aún sin publicar, cubre:
|
|
|
- la especificación 0.16: escribe el formato 3 de cápsula y lee los formatos 1, 2 y 3;
|
|
|
- el perfil Quicknet pinneado, y cualquier perfil del scheme `bls-unchained-g1-rfc9380`, el único que admite la v0.14 del spec;
|
|
|
- cifrado, inspección y apertura, firmas de autor y sellos, la nota pública, la llave de palabras y el localizador, y la CLI;
|
|
|
- todos los vectores y fixtures compartidos de [`testdata/`](testdata).
|
|
|
|
|
|
El primer tag, v0.1.0, llegará cuando `go get` funcione desde una máquina limpia.
|
|
|
|
|
|
## Una cápsula, en un dibujo
|
|
|
|
|
|
```text
|
|
|
.dkc = PRELUDE (16 B) || PUBLIC_HEADER (CBOR) || SEALED_CONTROL (age) || PAYLOAD_AGE (age, hasta EOF)
|
|
|
|
|
|
time_only: SEALED_CONTROL = age(tlock ronda R → CONTROL_CBOR)
|
|
|
time_and_key: SEALED_CONTROL = age(tlock ronda R → age(16 stanzas X25519 → CONTROL_CBOR))
|
|
|
CONTROL_CBOR = { header_binding = SHA-256(PRELUDE || PUBLIC_HEADER), I_PAYLOAD, extensiones, L, regla de relleno }
|
|
|
PAYLOAD_AGE = age(X25519 R_PAYLOAD → BODY || ceros hasta P = regla(L)), en streaming
|
|
|
|
|
|
BODY = AREA_LEN || SECURITY_LEN || HEAD_LEN (3 × uint32)
|
|
|
|| SECURITY_CBOR, ceros hasta AREA_LEN (32 KiB) firma de autor y sello, o vacío
|
|
|
|| HEAD_CBOR sal, comentario, autor declarado, los ficheros
|
|
|
|| los ficheros, uno tras otro
|
|
|
```
|
|
|
|
|
|
Es el formato 3, el que escribe `encrypt` (spec §22, §29.2). Sus 16 stanzas
|
|
|
llevan de 1 a 16 credenciales y un señuelo en cada hueco libre, en orden
|
|
|
aleatorio, y su payload se rellena hasta P: hasta la fecha nadie sabe cuántas
|
|
|
credenciales hay, ni la longitud exacta L, ni los nombres de los ficheros ni
|
|
|
cuántos son, más allá de lo que acota P (spec §29.1, §39, §55.2). El área de
|
|
|
seguridad mide 32 KiB, lleve o no firma, para que P no diga si la cápsula va
|
|
|
firmada, y 64 KiB solo cuando quien la crea lo pide porque una firma no cabe
|
|
|
(spec §29.2). Los escritores de la v0.10 escribían 512 bytes, que un lector
|
|
|
sigue aceptando. Ya abierta, da ficheros con sus rutas, tamaños, SHA-256 y
|
|
|
fechas de modificación, un comentario y un autor declarado, y los veredictos
|
|
|
de su área de seguridad. El formato 2, el de la v0.9, lleva un solo contenido;
|
|
|
el formato 1, el de la v0.8.2, lleva un stanza por credencial y no rellena.
|
|
|
Los lectores siguen abriendo los dos.
|
|
|
|
|
|
## CLI
|
|
|
|
|
|
```bash
|
|
|
go install g.activething.com/go/DateKeys/cmd/datekeys@latest
|
|
|
```
|
|
|
|
|
|
El módulo se sirve desde el Gitea del proyecto, cuyo certificado Go no
|
|
|
reconoce por defecto. Define `GOPRIVATE=g.activething.com` para que el proxy y
|
|
|
la base de datos de sumas de Go no intervengan, e instala el certificado del
|
|
|
servidor o, en una red de confianza, define `GOINSECURE=g.activething.com`.
|
|
|
|
|
|
```bash
|
|
|
datekeys datekey resolve -at 2030-01-01T00:00:00Z
|
|
|
datekeys encrypt -at 2030-01-01T00:00:00Z -in carta.txt -out carta.dkc
|
|
|
datekeys encrypt -at 2030-01-01T00:00:00Z -in fotos -in carta.txt -comment "Para Ana" -author "Juan" -out regalo.dkc
|
|
|
datekeys encrypt -at 2030-01-01T00:00:00Z -policy time_and_key -dkk regalo.dkk -in fotos -out regalo.dkc
|
|
|
datekeys encrypt -at 2030-01-01T00:00:00Z -policy time_and_key -words-file palabras.txt -in carta.txt -out carta.dkc
|
|
|
datekeys encrypt -at 2030-01-01T00:00:00Z -padding bloque256 -no-mtime -in carta.txt -out carta.dkc
|
|
|
datekeys author keygen -out autor.key -pass-file clave.txt
|
|
|
datekeys encrypt -at 2030-01-01T00:00:00Z -in carta.txt -note "Cartas de Lisboa" -sign autor.key -sign-pass-file clave.txt -out carta.dkc
|
|
|
datekeys decrypt -in carta.dkc -out carta -expect-author dkauthor1...
|
|
|
datekeys inspect -in regalo.dkc
|
|
|
datekeys decrypt -in regalo.dkc -out regalo -dkk regalo.dkk
|
|
|
datekeys decrypt -in regalo.dkc -out regalo -dkk regalo.dkk -release ronda.cbor
|
|
|
datekeys profile hash
|
|
|
datekeys version
|
|
|
```
|
|
|
|
|
|
`encrypt` escribe junto a la cápsula `FICHERO.dkc.recuperacion.txt`, el anexo de la especificación sobre cómo abrir una cápsula sin software de DateKeys (spec §79), salvo con `-no-recovery`; y dice qué hará falta para abrirla años después: el `.dkc`, una credencial si es `time_and_key` y el release de su ronda, que tendrá que conservar un archivo de releases o un servicio de caché si drand ya no lo sirve (spec §50). A más de un año, recomienda `time_and_key` a una cápsula `time_only` (spec §7.6). Con un perfil que no esté activo en el registro de §71 no escribe ninguna cápsula, y `decrypt` e `inspect` avisan si el perfil de una cápsula está comprometido.
|
|
|
|
|
|
`encrypt` nunca usa la red. Cada `-in` es un fichero o una carpeta; una
|
|
|
carpeta da su nombre como primer segmento de sus rutas, como hace un
|
|
|
navegador, y se recorre sin seguir enlaces, tomando solo ficheros regulares y
|
|
|
dejando fuera `.DS_Store`, `Thumbs.db`, `desktop.ini`, `._*` y `__MACOSX`. Una
|
|
|
ruta o un texto que incumple una regla de spec §29.5 o §29.6 se rechaza,
|
|
|
nombrando la regla y el carácter. Los ficheros conservan su fecha de
|
|
|
modificación salvo con `-no-mtime`. El contenido se rellena con la regla
|
|
|
reforzado, o con bloque256 si se pide (spec §29.1).
|
|
|
`inspect` ejecuta solo las comprobaciones previas al desbloqueo (spec §63,
|
|
|
pasos 1 a 8): nunca pide un release ni usa secretos.
|
|
|
`decrypt` obtiene el release de relays públicos de drand y lo verifica
|
|
|
localmente, nunca antes de la hora de la ronda; con `-release` toma en su
|
|
|
lugar el release en la mano, un objeto release, el JSON de drand o un
|
|
|
archivo local de releases, venga de donde venga, sin ninguna petición y diga
|
|
|
lo que diga el reloj (spec v0.15, §47.1, §63 paso 9.c). Los ficheros de una cápsula de formato 3 van a la carpeta nueva
|
|
|
`-out`, preparados dentro de ella y movidos a su sitio solo cuando todas las
|
|
|
comprobaciones han pasado (spec §56); una cápsula con solo un comentario no
|
|
|
crea la carpeta. Muestra los veredictos al principio y al final, y el autor
|
|
|
declarado, el comentario y las rutas como texto del creador que nadie ha
|
|
|
comprobado, cada línea tras el prefijo `│ ` y nunca más ancha que el terminal
|
|
|
(spec §29.7). Una línea de los veredictos se parte por el último espacio que
|
|
|
cabe, y cada fila tras la primera empieza por ` ↳ ` (dos espacios, U+21B3 y
|
|
|
un espacio): el terminal nunca parte una, y ningún nombre de un certificado
|
|
|
puede empezar una fila y pasar por un veredicto. Los formatos 1 y 2 siguen
|
|
|
dando un fichero. Nunca se sobrescriben ficheros de salida.
|
|
|
|
|
|
`author keygen` crea una clave de autor Ed25519 (spec §29.12) en un fichero
|
|
|
cifrado con una contraseña, o en texto con `-plain`, e imprime su clave
|
|
|
pública, `dkauthor1…`; `author public` la vuelve a imprimir. La contraseña
|
|
|
llega de un fichero, o de la entrada estándar con `-`, nunca de la línea de
|
|
|
órdenes ni del entorno. `encrypt -sign` firma la cápsula con ella (`alg` 1):
|
|
|
antes de firmar muestra la clave y el código de `AUTHOR_MESSAGE` (spec §62.1,
|
|
|
regla 20), y comprueba la firma antes de escribir nada. `decrypt` muestra la
|
|
|
firma; con `-expect-author` falla, sin escribir nada, salvo que la cápsula
|
|
|
lleve una firma válida de esa clave pública, el veredicto F4: compara la clave
|
|
|
antes del paso 18, cuando aún no se ha publicado ningún fichero.
|
|
|
|
|
|
`encrypt -note` pone una nota pública en claro en la cápsula (spec §24.1), y
|
|
|
avisa de que es pública. `inspect` y `decrypt` la muestran como texto del
|
|
|
creador que nadie ha comprobado; una nota que incumple las reglas de texto no
|
|
|
se muestra, y los dos lo dicen (`public_note_unusable` en `inspect -json`).
|
|
|
`-words` y `-words-file` dan a una cápsula `time_and_key` una llave de
|
|
|
palabras: al menos seis palabras distintas de tres letras o más, que la abren
|
|
|
con `decrypt -words-file` en lugar de una `.dkk` (spec §38.1). `-new-words
|
|
|
FICHERO` las sortea en su lugar, 7 por defecto, de una lista incluida
|
|
|
(`-dic en`, la de la EFF, por defecto, o `-dic es`; `-word-count N`), las
|
|
|
escribe en un fichero nuevo y dice su fuerza en bits: las palabras que elige
|
|
|
una persona son más débiles. `-dice` y `-dice-file` las sacan de unos dados,
|
|
|
para quien no se fíe del azar de un ordenador: cinco dados por palabra dan un
|
|
|
número del 11111 al 66666, su posición en la lista, y `datekeys wordlist`
|
|
|
escribe la lista numerada para los dados, para imprimirla, con su SHA-256;
|
|
|
la de `en` es el fichero de la EFF, byte a byte. `encrypt` muestra las
|
|
|
palabras de los dados: la cápsula la abren ellas, no los números. Una lista solo se usa si cada palabra es del alfabeto de su idioma.
|
|
|
Las listas y su licencia están en [`wordkey/lists`](wordkey/lists/README.md).
|
|
|
|
|
|
## Librería
|
|
|
|
|
|
```go
|
|
|
reg, err := profile.Default() // perfil Quicknet pinneado, comprobado contra su profile_hash
|
|
|
|
|
|
// EncryptFiles: sin red, la ronda se resuelve localmente. Lee cada fichero
|
|
|
// dos veces, y falla si un fichero cambia entre las dos lecturas.
|
|
|
res, err := capsule.EncryptFiles(dst, []capsule.Source{{
|
|
|
Path: "fotos/playa.jpg",
|
|
|
Size: info.Size(),
|
|
|
ModTime: info.ModTime(),
|
|
|
Open: func() (io.ReadCloser, error) { return os.Open(nombre) },
|
|
|
}}, capsule.EncryptOptions{
|
|
|
Profile: profile.Quicknet(),
|
|
|
UnlockAt: time.Date(2030, 1, 1, 0, 0, 0, 0, time.UTC),
|
|
|
Policy: capsule.TimeAndKey,
|
|
|
NewPortableKey: true, // res.PortableKey es la .dkk; se codifica con accesskey.Encode
|
|
|
Comment: "Para Ana",
|
|
|
Now: time.Now,
|
|
|
})
|
|
|
|
|
|
// Inspeccionar: pasos 1 a 8, sin red ni secretos.
|
|
|
in, err := capsule.Inspect(f, capsule.InspectOptions{Registry: reg})
|
|
|
|
|
|
// Abrir: pasos 1 a 18; el release se verifica localmente. Una cápsula de
|
|
|
// formato 3 entrega sus ficheros a un Sink, que los publica en Commit, en el
|
|
|
// paso 18.
|
|
|
opened, err := capsule.Open(ctx, nil, f, capsule.OpenOptions{
|
|
|
Registry: reg,
|
|
|
Source: drand.New(),
|
|
|
AccessKey: key, // o Identities: []age.Identity{...}
|
|
|
Sink: sink,
|
|
|
Now: time.Now,
|
|
|
})
|
|
|
if errors.Is(err, datekeys.ErrReleaseUnavailable) { /* todavía no */ }
|
|
|
```
|
|
|
|
|
|
Un `Sink` recibe `Begin` con el head, `Create` para cada fichero y `Commit`
|
|
|
solo cuando el paso 17 ha pasado; tras cualquier fallo recibe `Abort`, y nada
|
|
|
de lo que recibió puede presentarse como válido (spec §56). `opened.Head`
|
|
|
lleva las rutas, los tamaños, los SHA-256 y las fechas de modificación, el
|
|
|
comentario y el autor declarado, y `opened.Verdicts.Lines()` los veredictos
|
|
|
que se muestran antes (spec §29.7). `EncryptOptions.AuthorKey` o `CMSSigner`
|
|
|
firman la cápsula, y `Sealer` la sella (spec §29.9 a §29.11);
|
|
|
`OpenOptions.AuthorKeys` son las claves que la persona guardó, que dan F3, y
|
|
|
`OpenOptions.Accept` ve los veredictos antes del paso 18 y puede negarse a
|
|
|
publicar los ficheros. `Open` sin `Sink` se detiene justo tras el paso 2 con
|
|
|
`capsule.ErrSinkRequired`, un error del llamador sin código. Las cápsulas de
|
|
|
los formatos 1 y 2 siguen escribiendo su contenido en streaming en `dst`,
|
|
|
nunca el relleno. `opened.Format` es el formato de la cápsula: el formato 1 no
|
|
|
oculta el número de credenciales ni la longitud exacta del contenido, así que
|
|
|
muéstralo (spec §70). Todo fallo del protocolo envuelve uno de los 19 errores
|
|
|
normativos del §69, así que `errors.Is` y `datekeys.Code(err)` lo identifican.
|
|
|
|
|
|
## Propiedades de seguridad y límites
|
|
|
|
|
|
- **Confidencialidad temporal** bajo el supuesto de umbral de drand. El
|
|
|
timelock de Quicknet **no es post-cuántico**: los ciphertexts guardados
|
|
|
durante años quedan expuestos a *harvest now, decrypt later* (spec §7.7, §53).
|
|
|
- **Sin confianza en servidores**: el perfil va pinneado en el binario, la ronda
|
|
|
se calcula localmente, los releases se verifican con BLS localmente y una
|
|
|
firma válida de otra ronda se rechaza (spec §13, §17, §51).
|
|
|
- **Integridad**: framing, cabecera, control y payload están autenticados
|
|
|
frente a quien no conoce las file keys: un cambio de un tercero hace fallar
|
|
|
la apertura (fixtures y corpus de mutaciones). Publicada la ronda,
|
|
|
cualquiera puede calcular la file key temporal, y cualquiera puede sellar
|
|
|
un control nuevo para una cabecera pública; quién puede escribir cada parte
|
|
|
y desde qué paso queda vinculada es el modelo de confianza de spec §27 y
|
|
|
§55.1.
|
|
|
- **Privacidad de metadatos**: hasta la fecha quedan ocultos la longitud
|
|
|
exacta del contenido, el número de credenciales, y los nombres, tamaños y
|
|
|
número de los ficheros, más allá de lo que acota el tamaño con relleno P, y
|
|
|
también si la cápsula va firmada, salvo que se haya ampliado su área; no la
|
|
|
fecha, la política de acceso, `capsule_id` ni las extensiones de la
|
|
|
cabecera, entre ellas la nota pública (spec §55.2).
|
|
|
- **Extracción segura**: las rutas del head no pueden salir de la carpeta,
|
|
|
colisionar en Windows, macOS o Linux, esconder caracteres ni cambiar la
|
|
|
dirección del texto; las reglas usan tablas fijas de Unicode 18.0.0, nunca
|
|
|
las de la plataforma (spec §29.5, §29.6).
|
|
|
- **Autoría solo por una firma**: el autor declarado, el comentario, la nota
|
|
|
pública y las fechas de modificación son texto del creador que no prueba
|
|
|
nada (spec §24.1, §29.7, §36.1). Una firma de `alg` 1 prueba que firmó quien
|
|
|
tenía la clave secreta, no quién la tiene; de una firma con certificados y de
|
|
|
un sello, DateKeys comprueba la criptografía y las fechas, nunca quién los
|
|
|
emitió ni si se revocaron (spec §29.9 a §29.11). Los veredictos nunca
|
|
|
deciden la apertura (spec §29.3). `time_and_key` añade una barrera de
|
|
|
acceso, no una firma.
|
|
|
- **Recuperar años después** exige el release histórico: de un relay drand que
|
|
|
aún lo sirva o de cualquier caché, verificado de nuevo localmente (spec §50).
|
|
|
La v0.15 la basa en archivos y servicios de caché, de DateKeys o
|
|
|
de otros, que guardan los releases de todas las rondas, sin prometer
|
|
|
ningún alojamiento, y su §79 dice cómo abrir una cápsula sin software de
|
|
|
DateKeys, lo que comprueba `scripts/recovery_check.sh`.
|
|
|
|
|
|
Ver [SECURITY.md](SECURITY.md).
|
|
|
|
|
|
## Conformidad y tests
|
|
|
|
|
|
```bash
|
|
|
go test ./... # unitarios, vectores golden, fixtures, mutaciones
|
|
|
go test -race -cover ./...
|
|
|
go test -fuzz=FuzzInspect ./capsule # un objetivo de fuzzing cada vez
|
|
|
go test -tags interop ./capsule # las CLI oficiales age y tle abren nuestros ficheros
|
|
|
go test -tags integration ./capsule ./provider/drand # Quicknet en vivo
|
|
|
```
|
|
|
|
|
|
- `testdata/vectors`: vectores de `profile_hash`, fecha→ronda y `dk1_` (spec
|
|
|
§65, §66), vectores del perfil CBOR y de cada schema, vectores del relleno
|
|
|
(spec §29.1), las rutas, las claves de R7, los heads y las áreas de
|
|
|
seguridad del formato 3 (spec §67), el Ed25519 estricto de `alg` 1, las
|
|
|
firmas con certificados y los sellos, la nota pública y la extensión
|
|
|
`datekeys.capsule`, el corpus de mutaciones exportado y un corpus
|
|
|
diferencial de las comprobaciones previas al desbloqueo; formatos en
|
|
|
[`testdata/README.md`](testdata/README.md).
|
|
|
- `testdata/fixtures`: fixtures oficiales `.dkc`/`.dkk` sobre rondas ya
|
|
|
publicadas, con la firma BLS embebida y todos los valores intermedios (spec
|
|
|
§67, §68); se descifran sin red. Catorce son de formato 3, cinco de ellas
|
|
|
con el área de 32 KiB de la v0.11: sin firma, firmada con `alg` 1, sellada,
|
|
|
firmada con certificados y con una nota pública. Las siete de formato 2, de
|
|
|
la v0.9, y las cinco de formato 1, de la v0.8.2, se conservan por
|
|
|
compatibilidad. Cada `.dkc` tiene congelada su salida de
|
|
|
`datekeys inspect -json`.
|
|
|
- `internal/testkit.Mutations`: las mutaciones del §64, las 33 de sus dos
|
|
|
primeras listas en cada formato, las 23 de la lista del formato 2, las 48
|
|
|
de la del formato 3 y 8 de la de la v0.11, y 40 más, cada una con su error
|
|
|
y su paso exactos, o sus veredictos cuando se abre, comprobando además que
|
|
|
los fallos previos al desbloqueo nunca provocan una petición de release;
|
|
|
exportadas a `testdata/vectors/mutations.json`.
|
|
|
- [`docs/traceability.md`](docs/traceability.md): sección del spec → código → test.
|
|
|
- [`spec/datekeys.cddl`](spec/datekeys.cddl): schemas CBOR.
|
|
|
|
|
|
## Licencia
|
|
|
|
|
|
Código: Apache-2.0 ([LICENSE](LICENSE)). Especificación: CC-BY-ND-4.0
|
|
|
([spec/README.md](spec/README.md)). `codec/bech32` se copia de age bajo su
|
|
|
propia licencia. "DateKeys" es un nombre reservado: ver [TRADEMARKS.md](TRADEMARKS.md).
|