testdata and wordlists at datekeys-go e671032, with the same testdata:
wordlists/en.txt is the large wordlist of the EFF, 7776 words, CC BY 4.0,
in its order and without the dice numbers. wordListSha256 pins it, and
the alphabet of en is a to z and the hyphen of its four compound words,
as Go has them. The vectors are generated again by Go at e671032: only
their source and the list of lists change. The tests read the English
list too, and check the hyphen and the accent in each alphabet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ -19,6 +19,7 @@ Cambios notables de la librería Dart. El proyecto usa versionado semántico; mi
- **Vectores de Go:**`test/vectors/wordlist_vectors.json`, de `tool/wordlist_go_vectors.go` en una exportación de `datekeys-go` en `27a75ee`, con su copia en Dart para Node.js: el cuerpo de `List` sobre 19 textos; `CheckList` sobre 83 listas, y con cada punto de código de los planos 0, 1 y 14 en una lista; `Generate` en 51 casos, sobre la lista española y listas de 12 a 2^20 + 1 palabras, con el keystream de `SeededRandomSource`, bloques de SHA-256 y bytes que se acaban, entre ellos la semilla de `TestGenerate`, que solo saca dos índices y se queda sin bytes; y `Bits`, bit a bit, en 221 casos y cuatro resúmenes.
- **Pruebas.** 19 nuevas en la VM y 11 en Node.js: `test/wordlist_test.dart`, también compilado a JavaScript, con los vectores y los casos de `TestCheckList`, `TestGenerate` y `TestBits` de Go; `test/wordlist_vm_test.dart`, con cada punto de código y, sobre la lista española de `wordlists/`, los casos de `TestBuiltInLists`, `TestGenerate` y `TestGenerateUniform`; y `test/testdata_test.dart`, con la línea de `wordlists/`. En total, 2230 en la VM y 705 en Node.js.
- **Fallos inyectados** en `wordlist.dart`, uno a uno y revertidos: los 30 que cambian algún resultado, en el alfabeto, el orden de las comprobaciones, la cuenta de letras, los números de línea, el corte de las líneas, el SHA-256, el sorteo y los bits, los detectan pruebas que corren también en Node.js. Otros dos dan lo mismo con cualquier entero: quitar el atajo de las potencias de dos de `Log2`, porque `Log` da ahí lo mismo, y el borde de √2/2 en `Log`, al que no llega ningún entero.
- **La lista inglesa.**`datekeys-go` añade en `e671032` la lista grande de la EFF, `wordkey/lists/en.txt`, de 7776 palabras, CC BY 4.0, en su orden y sin los números de los dados, y `-dic` la toma por defecto. `testdata` y `wordlists` pasan a `e671032`, con el mismo `testdata`; `wordListSha256` fija la nueva lista, y el alfabeto de `en` es de la `a` a la `z` y el guion de sus cuatro palabras compuestas, como `t-shirt`. Los vectores se regeneran con Go en `e671032`: solo cambian su campo `source` y la lista de listas.
- **Diferencias con Go.** Una `RandomSource` no se acaba: lo que lance la fuente sale de `generateWords`, donde Go da `wordkey: EOF`. El fichero de una lista se lee como lee Go un string, como bytes, y sus palabras se decodifican después de la comprobación, que rechaza con el texto de Go un byte que no es UTF-8 válido.
### La recuperación a largo plazo: el objeto release y el release en la mano (07-10-2026)
`testdata/` es una copia de `datekeys-go/testdata` en un commit fijo. `testdata/SOURCE.json` registra el commit y el SHA-256 de cada fichero, igual que en `datekeys-ts`. La copia actual es la de `datekeys-go` en `27a75ee`, la rama `v0.15` después del tag `spec-v0.15`, cuyo `testdata/` es el del tag, `fe50885`, byte a byte: 142 ficheros, con `release.json` y `releases/`, el objeto release, el JSON de drand y el archivo de releases de la v0.15, con el campo `source` de `mutations.json`, con `tlock_steps.json`, los pasos 10 y 11 de Quicknet valor a valor, con `resolved_ip.json`, con `wordkey.json`, los vectores compartidos de la llave de palabras, y los veredictos y las líneas de la v0.12. Cada fichero dice `"spec": "0.15"`, como el `SpecVersion` de Go.
`testdata/` es una copia de `datekeys-go/testdata` en un commit fijo. `testdata/SOURCE.json` registra el commit y el SHA-256 de cada fichero, igual que en `datekeys-ts`. La copia actual es la de `datekeys-go` en `e671032`, la rama `v0.15` después del tag `spec-v0.15`, cuyo `testdata/` es el del tag, `fe50885`, byte a byte: 142 ficheros, con `release.json` y `releases/`, el objeto release, el JSON de drand y el archivo de releases de la v0.15, con el campo `source` de `mutations.json`, con `tlock_steps.json`, los pasos 10 y 11 de Quicknet valor a valor, con `resolved_ip.json`, con `wordkey.json`, los vectores compartidos de la llave de palabras, y los veredictos y las líneas de la v0.12. Cada fichero dice `"spec": "0.15"`, como el `SpecVersion` de Go.
`wordlists/` es la copia de `wordkey/lists` del mismo commit: las listas de palabras de `wordkey.Generate`, hoy `es.txt`, y su `README.md`, con la fuente, el método y la licencia de cada lista. `wordlists/SOURCE.json` tiene el formato de `testdata/SOURCE.json`, y `.gitattributes` guarda sus bytes exactos, como los de `testdata/`: `lib/src/wordlist.dart` fija el SHA-256 de cada lista.
`wordlists/` es la copia de `wordkey/lists` del mismo commit: las listas de palabras de `wordkey.Generate`, hoy `en.txt`, la de la EFF, y `es.txt`, y su `README.md`, con la fuente, el método y la licencia de cada lista. `wordlists/SOURCE.json` tiene el formato de `testdata/SOURCE.json`, y `.gitattributes` guarda sus bytes exactos, como los de `testdata/`: `lib/src/wordlist.dart` fija el SHA-256 de cada lista.
```bash
dart run tool/sync_testdata.dart sync --commit 27a75ee
dart run tool/sync_testdata.dart sync --commit e671032
```
```bash
@ -725,7 +725,7 @@ rm -rf "$tmp"
El de las listas de palabras corre en una exportación del commit de `wordlists/SOURCE.json`, para que sus vectores sean los de esas listas: `tool/wordlist_go_vectors.go` lee `wordkey/lists` y da a `Generate`, en lugar de `crypto/rand`, el keystream de `SeededRandomSource`, bloques de SHA-256 o bytes que se acaban. La salida es la misma en cada ejecución:
```bash
commit=$(git -C ../datekeys-go rev-parse 27a75ee)
commit=$(git -C ../datekeys-go rev-parse e671032)
out=$PWD/test/vectors
tmp=$(mktemp -d)
git -C ../datekeys-go archive "$commit" | tar -x -C "$tmp"
@ -816,7 +816,7 @@ rm -rf "$tmp"
| `pathrule_vectors.g.dart` | El mismo JSON como constante de Dart |
| `wordkey_vectors.json` | La llave de palabras de `wordkey`: 400 textos con sus palabras, 515 listas de palabras con el resultado de `Check`, y cuatro llaves con su contraseña P y su sal S, el PBKDF2 de 1000 iteraciones para Node.js y el recipient; la primera es el vector del §38.1 |
| `wordkey_vectors.g.dart` | El mismo JSON como constante de Dart |
| `wordlist_vectors.json` | Las listas de palabras de `wordkey` (`generate.go`), en `27a75ee`: el SHA-256, los bytes y las palabras de cada lista de Go; el cuerpo de `List` sobre 19 textos de una lista base, con y sin el LF final, con líneas CRLF, una línea vacía, una marca de orden de bytes y bytes que no son UTF-8 válido; `CheckList` sobre 83 listas editadas, con los casos de `TestCheckList`; `CheckList` con cada punto de código de los planos 0, 1 y 14 en la primera palabra, como el SHA-256 de sus resultados, y uno a uno hasta U+017F; `Generate` en 51 casos, sobre la lista española y listas de 12 a 2^20 + 1 palabras, con el keystream de `SeededRandomSource`, bloques de SHA-256 y bytes que se acaban, entre ellos la semilla de `TestGenerate`, que solo saca dos índices y se queda sin bytes; y `Bits`, el double de Go bit a bit, en 221 casos y cuatro resúmenes |
| `wordlist_vectors.json` | Las listas de palabras de `wordkey` (`generate.go`), en `e671032`: el SHA-256, los bytes y las palabras de cada lista de Go; el cuerpo de `List` sobre 19 textos de una lista base, con y sin el LF final, con líneas CRLF, una línea vacía, una marca de orden de bytes y bytes que no son UTF-8 válido; `CheckList` sobre 83 listas editadas, con los casos de `TestCheckList`; `CheckList` con cada punto de código de los planos 0, 1 y 14 en la primera palabra, como el SHA-256 de sus resultados, y uno a uno hasta U+017F; `Generate` en 51 casos, sobre la lista española y listas de 12 a 2^20 + 1 palabras, con el keystream de `SeededRandomSource`, bloques de SHA-256 y bytes que se acaban, entre ellos la semilla de `TestGenerate`, que solo saca dos índices y se queda sin bytes; y `Bits`, el double de Go bit a bit, en 221 casos y cuatro resúmenes |
| `wordlist_vectors.g.dart` | El mismo JSON como constante de Dart |
| `mutation_texts.json` | De `tool/mutation_go_texts.go`, port de `scripts/mutation-go-texts.go` de `datekeys-ts` sobre el `testdata/` de este repositorio: el texto del error de `capsule.Open` en cada caso del corpus de mutaciones, `ok` si se abre, y sus comprobaciones con el detalle de cada paso. Si Go y el corpus discreparan en el código o el paso de un caso, lo diría con `go_error` y `go_step`: en ninguno de los 222 casos del corpus de la v0.15 lo hacen con Go en `fe50885`, que abre cada caso con su `source`, como `testkit` |
| `open_cases.json` | `capsule.Open` sobre cada fixture con cada una de sus credenciales, y sobre fixtures editados o con otras opciones en cada paso que el corpus no alcanza: la trama, los campos, las extensiones y los vínculos de una `.dkk` en el paso 9.a, el reloj y los fallos de la fuente del release, las cabeceras `age` de los pasos 11 y 17, un stanza X25519 mal formado en `INNER_ACCESS_AGE`, `CONTROL_CBOR` sellado otra vez, `BODY` del formato 3 sellado otra vez, los sinks y la salida que fallan, el rechazo de `Accept` y las extensiones inutilizables de cada objeto. Cada caso tiene el resultado, el texto, el paso, las comprobaciones con su detalle, las peticiones del release, el estado del sink y el contenido o los ficheros, y los del formato 3 que se abren, sus veredictos con sus líneas, también con la clave de autor guardada |
"description":"The word lists of package wordkey of the Go reference (generate.go, spec \u00a738.1) for lib/src/wordlist.dart; see tool/wordlist_go_vectors.go. Binary values and words are lower-case hex. The base list is word i = pal and three letters, a + i/676, a + i/26%26 and a + i%26; a case of size n takes its first n words, replaces the word at each at of set, and adds those of append. lists: the SHA-256, bytes and words of each built-in list. parse: the body of List on the text prefix, the base list joined by sep, and suffix (sha256 is that of the text): the words read, and ok or the error. check_list: CheckList, ok or the error (sha256 is that of the words joined by LF). alphabet: CheckList of the base list of 2048 whose first word is pala, a code point and zz, for each code point of the planes but the surrogates: the SHA-256 of the lines U+XXXX result, the code points of the words it accepts, and alphabet_results, each result up to U+017F. generate: Generate on the list of the Spanish words (list es) or on a list of size words whose indices they are, reading a stream: seeded, the keystream of SeededRandomSource of the seed; counter, SHA-256 of the label and a 32-bit big-endian counter from 0, block after block; bytes, hex repeated repeat times, which end. The indices drawn, the bytes read and the next four of an endless stream, or the error. bits: Bits, its shortest decimal and the hex of its float64. bits_digests: the SHA-256 of the 8 big-endian bytes of each Bits of the sizes and counts, inclusive, sizes outer.",
"alphabet":{"word":"pala, the code point and zz, the first word of the base list of 2048","planes":[0,1,14],"count":194560,"sha256":"9119a1741586b087cc8fdcce99b00931d34c926f5dc54d7fa0ff250402a11ba9","ok":["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","\u00e1","\u00e9","\u00ed","\u00f1","\u00f3","\u00fa","\u00fc"]},
"description":"The word lists of package wordkey of the Go reference (generate.go, spec \u00a738.1) for lib/src/wordlist.dart; see tool/wordlist_go_vectors.go. Binary values and words are lower-case hex. The base list is word i = pal and three letters, a + i/676, a + i/26%26 and a + i%26; a case of size n takes its first n words, replaces the word at each at of set, and adds those of append. lists: the SHA-256, bytes and words of each built-in list. parse: the body of List on the text prefix, the base list joined by sep, and suffix (sha256 is that of the text): the words read, and ok or the error. check_list: CheckList, ok or the error (sha256 is that of the words joined by LF). alphabet: CheckList of the base list of 2048 whose first word is pala, a code point and zz, for each code point of the planes but the surrogates: the SHA-256 of the lines U+XXXX result, the code points of the words it accepts, and alphabet_results, each result up to U+017F. generate: Generate on the list of the Spanish words (list es) or on a list of size words whose indices they are, reading a stream: seeded, the keystream of SeededRandomSource of the seed; counter, SHA-256 of the label and a 32-bit big-endian counter from 0, block after block; bytes, hex repeated repeat times, which end. The indices drawn, the bytes read and the next four of an endless stream, or the error. bits: Bits, its shortest decimal and the hex of its float64. bits_digests: the SHA-256 of the 8 big-endian bytes of each Bits of the sizes and counts, inclusive, sizes outer.",
"alphabet":{"word":"pala, the code point and zz, the first word of the base list of 2048","planes":[0,1,14],"count":194560,"sha256":"9119a1741586b087cc8fdcce99b00931d34c926f5dc54d7fa0ff250402a11ba9","ok":["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","\u00e1","\u00e9","\u00ed","\u00f1","\u00f3","\u00fa","\u00fc"]},
@ -7,8 +7,14 @@ from the normalized text of the words, whatever list they came from.
| List | Words | SHA-256 | Status |
|---|---|---|---|
| `en.txt` | 7776 | `6d557f0693958fb5e650b68b5bee585eb82cf4da32965505c789e924743bc522` | The large wordlist of the EFF, as published |
| `es.txt` | 7776 | `ff77b487765c000da97cca58fe94a2cdb947303e7a07460614d7d95d800034fe` | Draft, not yet reviewed by a native speaker |
Each list has 7776 = 6^5 words, sorted, so that five dice give a word: each
die minus one is a digit of the position of the word in base 6, the first
die the most significant. The dice 11111 give the first word and 66666 the
last, as in the list of the EFF.
A list changes only with its hash in this file and in `generate_test.go`:
an application that downloads a list pins its SHA-256 and refuses any other.
`wordkey.CheckList` checks a list against the alphabet of its language,
@ -18,8 +24,26 @@ typed again with the letter of the keyboard, and the capsule would not open.
| Language | Alphabet |
|---|---|
| `en` | `a` to `z` and the ASCII hyphen of the four compound words of the list of the EFF (`drop-down`, `felt-tip`, `t-shirt` and `yo-yo`), in lower case |
| `es` | `a` to `z`, `á`, `é`, `í`, `ó`, `ú`, `ü` and `ñ`, in lower case and NFC |
## `en.txt`
- **Source:** the large wordlist for passphrases of the Electronic Frontier