# Artifacts *State on 7 October 2026, specification v0.16. 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.16`, commit `b6ff17a5fa5f119aa8125356437a09c657b15d0b` (also the head of branch `v0.16` and of `main`) | English README (a Spanish one too); spec in Spanish | | `datekeys-ts` | TypeScript library and static pages `/inspect` and `/create` | tag `v0.5.0`, commit `2c305cf` (implements spec 0.16) | Spanish README | | `datekeys-dart` | Pure Dart library, for a future Flutter app | branch `v0.16`, commit `b53afdc`, no tag (implements spec 0.16) | 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.16 datekeys-ts/ at v0.5.0 (the author's machine names this folder App) datekeys-dart/ at b53afdc ``` Specification files at the tag: | File | SHA-256 | |---|---| | `spec/DateKeys_Protocol_Specification_v0.16.md` (4 810 lines, about 61 000 words, Spanish) | `807d4fe85ac09ad6f97abc75ab3e2156bb2f3fb0dc589777f4420627fad545e1` | | `spec/datekeys.cddl` (340 lines, English comments; v0.15 adds the rule `release`, v0.16 changes no schema) | `ba3ceb24203ef49f55d5da021b7e940ae6780ef83fccb10aa3d305e4dcfac3a3` | Both were checked on 7 October 2026 with `git show spec-v0.16: | sha256sum`. The documentation of the Go repository (README, SECURITY.md, `docs/traceability.md`, the header comment of the CDDL) is at v0.16 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.16. Earlier versions are in the same folder; §76 records each normative change with its reproducible case. The specification is CC-BY-ND-4.0 (since 7 October 2026; it was CC-BY-4.0); the code is Apache-2.0. ## 2. Build and gates ### datekeys-go (Go 1.26.8) ```bash cd datekeys-go scripts/check.sh # the local gate, without fuzzing scripts/check.sh 20s # and every fuzz target for 20 s each FUZZ_PARALLEL=4 scripts/fuzz.sh 60s # fuzzing only go test -tags interop ./capsule # the official age and tle CLIs open our files 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); `scripts/recovery_check.sh` (v0.15 and v0.16, 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`), `format3_time_and_key_portable` (`time_and_key`, with its `.dkk`), and, since v0.16, `format3_time_and_key_words` (with the text of the words of the annex vector) and `format3_full_chunk` (a PAYLOAD_AGE of one full STREAM chunk) 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 (PBKDF2 included), `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`). It takes the words with `-words` and, for text outside the recipe without tables of §79.7, `UnicodeData.txt` with `-unicodedata`, checked by its SHA-256. Its tests check the import rule, run over ten fixtures of the three formats, and compare both normalisations of §79.7 with every case of `vectors/wordkey.json` (spec §76, v0.15 change 4; v0.16 changes 2 and 3). `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`). Since v0.15, `decrypt -release ` 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. `encrypt` writes the recovery annex next to the capsule and says what opening will take (§62.1 rules 26 and 27), and draws random words with `-new-words` or takes them from dice with `-dice`. Gate and fuzzing record: - On 7 October 2026, `scripts/check.sh` (without fuzzing) passed on `b6ff17a`, the frozen commit, and before on `4f78854` and `3fd0e93` of the same branch. - On 7 October 2026, `FUZZ_PARALLEL=4 scripts/fuzz.sh 20s` ran the 27 targets on `b6ff17a`, with no failing input. - For v0.15: `scripts/check.sh` passed on `fe50885`. - For v0.15: `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) ```bash cd datekeys-ts npm ci npm run verify # svelte-check, typecheck, tests with coverage thresholds, build and its check 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 7 October 2026, `npm run verify` passed with 8 273 tests (1 skipped) on `2c305cf`, the release commit of 0.5.0, with `testdata/` at `b6ff17a` (`testdata/SOURCE.json`). ### datekeys-dart (Dart SDK 3.13 or later; Node.js for the JavaScript run) ```bash cd datekeys-dart dart pub get tool/check.sh # dart format, dart analyze --fatal-infos, dart test, dart test -p node, # and testdata/ against ../datekeys-go ``` On 7 October 2026 the gate passed on `b53afdc` with 2 286 tests on the VM and 720 on Node, with `testdata/` at `b6ff17a` (150 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.16"`. The format of each file is documented in `testdata/README.md` (1 186 lines, English), so that no Go code needs to be read. At `b6ff17a` there are 150 files; v0.15 adds `vectors/release.json`, the five files of `releases/` and the field `source` of `mutations.json`; v0.16 makes `security_cms.json` again, with `seal_reason`, adds 26 cases of drand's JSON to `release.json` and the annex vector to `wordkey.json`, and brings two fixtures, `format3_time_and_key_words` and `format3_full_chunk`. | File | Content | Spec | |---|---|---| | `vectors/profile_quicknet.json` | Quicknet Provider Profile: canonical CBOR and `profile_hash` | §11, §12 | | `vectors/quicknet_rounds.json` | date → round resolution | §15, §16, §65 | | `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. Since v0.16, 38 cases of drand's JSON, 26 of them for the strict reading: repeated names, escaped names, `ROUND`, rounds with a fraction, an exponent, a sign, 0 or 2^53, lone surrogates | §47.1, §50, §63 step 10 (v0.15, v0.16) | | `releases/.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 | | `vectors/path_fold.json` | the R7 key of segments, and their NFD | §29.5, §29.5.1 | | `vectors/head_schema.json` | format 3 heads and the result of decoding them | §29.4 to §29.6, §69.1 | | `vectors/security.json` | security areas in the context of a capsule, their verdicts and lines | §29.3, §29.7, §29.9 | | `vectors/security_cms.json` | security areas with an `alg` 2 signature or a `seal_type` 2 seal, with context, verdicts, results and lines; made again for v0.16 (143 cases), with the reason of S5, `seal_reason` | §29.7, §29.10, §29.11 | | `vectors/ed25519_strict.json` | Ed25519 signatures and the result of the strict profile | §29.9 | | `vectors/note.json` | public note data and the result of its rules | §24.1, §29.6 | | `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; since v0.16 the text of the annex vector, also with its marks apart | §38.1, §64, §79.7 | | `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: 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/.dkc`, `.json` | official capsules and every intermediate value | §67 | | `fixtures/.dkk`, `.dkk.json` | official access keys | §68 | | `fixtures/.plaintext` | the content of each capsule (formats 1 and 2: the content; format 3: BODY) | §67 | | `fixtures/.inspect.json` | the exact output of `datekeys inspect -json` | §63 | Twenty-eight official capsules (`testdata/README.md`): five of format 1 (v0.8.2, compatibility), seven of format 2 (v0.9, compatibility) and sixteen 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 with `accuracy`, S4), `format3_note`, and, since v0.16, `format3_time_and_key_words` (a key of words, its text in `words_text`) and `format3_full_chunk`. 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 or v0.16: `go.mod` and `go.sum` are identical at `39b2033`, `fe50885` and `b6ff17a`; the TypeScript `package.json` and lock file change only the package version, to 0.4.0 and then to 0.5.0; the Dart `pubspec.yaml` and `pubspec.lock` are identical at `013b069`, `faa2c4c` and `b53afdc`. The recovery program `scripts/recovery` uses only modules already in `go.mod`. Direct: | Module | Version | Role (`SECURITY.md`) | |---|---|---| | `filippo.io/age` | v1.3.2 | age files, X25519, STREAM, header MAC; scrypt for author key files | | `github.com/drand/tlock` | v1.2.0 | `TimeLock`, `TimeUnlock`, ciphertext encoding | | `github.com/drand/drand/v2` | v2.1.7 | BLS verification, chain-info hash | | `github.com/drand/kyber` | v1.3.2 | pairing, IBE | | `github.com/drand/kyber-bls12381` | v0.3.4 | BLS12-381 on kilic | | `golang.org/x/crypto` | v0.57.0 | required for GO-2026-6354 and GO-2026-6355 | Indirect: `filippo.io/hpke` v0.4.0, `github.com/BurntSushi/toml` v1.6.0, `github.com/kilic/bls12-381` v0.1.0 (archived), `github.com/nikkolasg/hexjson` v0.1.0, `go.dedis.ch/fixbuf` v1.0.3, `go.uber.org/multierr` v1.11.0, `go.uber.org/zap` v1.28.0, `golang.org/x/net` v0.58.0, `golang.org/x/sys` v0.48.0, `golang.org/x/text` v0.42.0, `google.golang.org/genproto/googleapis/rpc` (2026-07-06 pseudo-version), `google.golang.org/grpc` v1.84.0, `google.golang.org/protobuf` v1.36.11, `gopkg.in/yaml.v3` v3.0.1. gRPC and protobuf come in through `drand/v2` `common/chain` (`SECURITY.md`). 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.5.0`, exact versions) Runtime: | Package | Version | Role | |---|---|---| | `age-encryption` | 0.3.1 | the three age files, with own tlock `Identity` and `Recipient`; scrypt for author key files | | `@noble/curves` | 2.4.0 | BLS12-381 (IBE and release verification), X25519, Ed25519 arithmetic, ECDSA P-256/384/521 | | `@noble/hashes` | 2.4.0 | SHA-1, SHA-2, HKDF | | `@noble/ciphers` | 2.4.0 | ChaCha20-Poly1305 | `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 `b53afdc`) - 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`). - SDK: Dart `>=3.13.0 <4.0.0`. ## 5. Traceability `datekeys-go/docs/traceability.md` (262 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. At v0.16 in the frozen commit `b6ff17a`. The rows of v0.16: §29.7 and §29.11 (the reason of S5, `capsule.SealReason`, `Token.HasAccuracy` and `Token.BTSP`), §47.1 (`ParseDrandJSON` and `provider/drandjson.go`), §62.1 (`Result.Security` for rule 19; rules 21 and 22 *pending*, since no writer asks an authority yet), §67 (the two fixtures) and §79 (the key of words of `scripts/recovery`). 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 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.16/decisiones.md`: the eight decisions of the v0.16 draft (7 October 2026), the answer to Astra's review of v0.15, with a note on how they were approved. - `spec_v0.10/revision_fable.md`, `spec_v0.11/revision_fable_astra.md`: reviews by the AI systems Fable and Astra.