The final review of the draft found 22 problems, and none had been applied
yet. All of them are applied now, together with four places that repeated
them (§62.1 rules 1 and 4, §76 changes 4 and 10).
- §29.1, §76 change 4: 32-bit arithmetic first gives a wrong P at
L = 2 113 929 217 with signed operators and at L = 4 227 858 433 with
>>> 0, not at 2^32 + 1. The vector table gains a row for each, checked
against a BigInt Padme. Above 2^32, Padme exceeds bloque256 except at
L_MAX. The Node log2 error changes E and lastBits, not P or S.
- §56, §76 change 4: a reader MUST NOT present the content as valid before
step 17 ends; a streaming reader MUST NOT write the padding and MUST
signal the step 17 error so that what it wrote is discarded. The author
chose this over the stricter rule, which forbade delivering any byte
before step 17 and so the streaming Open(dst) of the reference.
- §64: the 15 and 17 stanza mutations recalculate the PRELUDE and
header_binding; every time_and_key mutation offers the identity, because
any change breaks the capsule_digest of a .dkk; the duplicate recipient
mutation names its identity. Three new mutations cover the shape of
payload_length (7 or 9 bytes, a CBOR integer); the format 2 cbor.json
vectors of §76 list them too.
- §39, §62.1 rule 4: the official test vectors may show which slots are
dummies. §70, §62.1 rule 1: the format 2 rule binds implementations that
write capsules, and a test vector generator MAY write format 1.
- §62 step 8 gets the 64 MiB limit of §61 step 6.
- Accuracy: §22 (an older reader detects a new padding code only after the
network request; the .dkk schema is §41), §37 and §76 change 10 (the §63
rules do not detect those recipients), §55.2 (the writer knows the number
of parties; relays are §48), §76 changes 1 and 8.
- Wording: §62.1 rules 7 and 11, §63 step 4, §76 change 11, the field names
in the CDDL comments, and a v0.9 entry in spec/README.md.
go test ./... passes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Draft decided by the author on 29-09-2026: format 2 with exactly 16
X25519 stanzas in INNER_ACCESS_AGE (dummies, shuffled), payload padding
(code 1 bloque256, code 2 reforzado = max(bloque256, Padme)) with L and
the code in CONTROL_CBOR v2, VERSION 2 so v0.8.2 readers reject early,
a privacy section (§55.2) and writer rules (§62.1). The CDDL holds the
draft schemas. The fixes from the final review were being applied when
work stopped: they may be partial. See App/docs/HANDOFF.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Amendment of the unreleased v0.8.2, recorded in §76 with its case: the
second implementation's phase-2 research found that tlock-js over
@noble/curves 1.9.7 accepts U re-encoded as c0 + p and a signature
x + p and returns the same file key, while the reference rejects both
(noble 1.9.7 differed from kilic on 5,615 of 41,686 encodings), and the
spec did not say which encodings are valid.
- §12.2 defines the canonical encoding of a BLS12-381 point (drand's
compressed ZCash form) and requires decoders to reject every other
byte string; §12.1 applies it to public_key.
- §63 step 10 applies it to the release signature (ERR_RELEASE_INVALID)
and step 11 defines the tlock stanza body U || V || W (96 + 16 + 16
bytes for Quicknet) with a canonical, non-infinity U (ERR_INTEGRITY).
- §64 gains ten mutations, exported to mutations.json (65 cases). The
signature x + p case uses published Quicknet round 1004, the first
after 1000 whose x allows x + p < 2^381. The reference already gave
every stated code and step.
Errors no longer copy text from tlock, kyber, age, drand or
kyber-bls12381. kyber's IBE error carried the candidate plaintext and r,
and with one bit of W flipped the message disclosed the real tlock file
key with that bit flipped. Every such place now uses a fixed reason with
its normative sentinel; TestTlockFailureDiagnosticsCarryNoSecrets fails
with the old wrapping.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Approved refinements, each recorded with its reproducible case in the
§76 v0.8.2 subsection:
- §69.1: layered error model with normative precedence (frame, type tag
and version, CBOR profile and CDDL, then fields with their own code in
ascending key order; across steps the §63 order decides), with a scope
paragraph for the optional steps 5, 6 and 8.
- §55.1: normative trust table per section (who can write it, from which
step it is bound, what it never proves); §72: security-relevant claims
go in CONTROL_CBOR or under a signature, .dkk data is advisory.
- §31/§54: extension arrays in strictly ascending unsigned byte order of
extension_id (one rule for order and uniqueness).
- Gaps a second implementation needed: §28.1 malformed age headers,
§15/§19 latest unlock time and dk1_ reading rules, §22/§23/§57 length
lower bounds, §63 step 8 tlock argument comparison and step 9 order,
§12.1 profile validation with the drand chain-hash formula, §74 table
of implementation limits.
Reference alignment: .dkk errors only at step 9.a (new
OpenOptions.AccessKeyFile, used by the CLI), CR/LF in dk1_ is
ERR_DATEKEY_INVALID, BODY_LEN 0 is ERR_INTEGRITY, nil identities are not
credentials, and AccessIdentity tries every identity on every stanza so
its verdict does not depend on their order. dk1.json gains three
vectors; every other testdata file is byte-identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Step 2b: package codec is rewritten without reflection or struct tags. A
strict Decoder accepts only the spec §58 profile, Unmarshal decodes,
re-encodes and compares, Peek reads the type tag and version, and Walk is a
bounded iterative helper for vectors and fuzzing. Every schema has its own
hand-written encoder and decoder that checks all CDDL rules before the
fields with their own error codes. github.com/fxamacker/cbor/v2 and
github.com/x448/float16 are gone; nothing replaces them. Valid objects
encode and decode exactly as before (1.34 million differential verdicts);
the invalid-input differences are documented in CHANGELOG and
traceability decision 12. A review found and fixed an access_policy check
that truncated to uint8.
Step 3: testdata gains vectors/cbor.json (generic and per-schema CBOR
vectors), vectors/mutations.json (the 55-case mutation corpus, replayable
offline), vectors/inspect_differential.json (1,825 fixed-seed mutations
with the Go verdict) and one inspect -json golden per fixture, all
regenerated byte-identically by genfixtures and documented in
testdata/README.md for second implementations.
Gate green with 90 s of fuzzing per target on all 15 targets; codec at
100 % coverage; pre-existing testdata byte-identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Extension data becomes a non-empty opaque bstr bounded by the frame of its
container; the base protocol never decodes or validates it. Arrays hold at
most 64 extensions, extension_version is bounded to 2^32-1 and the profile's
period and genesis_time to 2^53-1. The multiplicity exception is removed,
ERR_EXTENSION_DATA_INVALID is added, the §57 limits become MUST with an
explicit error mapping, §58 names the protocol's CBOR profile and §72 sets
the registration rules. §76 records the six reproducible cases behind the
change. The implementation follows in the next commit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The module is imported as g.activething.com/go/DateKeys, the path the
project's Gitea advertises. The .github directory is gone: workflows
now live in .gitea/workflows, use the gitea.com action mirrors and
install every tool from its Go module; releases go to this Gitea with
goreleaser and a key-based cosign signature; Dependabot is replaced by
a nightly report of available updates. scripts/check.sh runs the same
checks on any machine and is the gate while the server has no runner.
SECURITY.md, README and CONTRIBUTING no longer refer to GitHub.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Reference implementation in Go, built from the implementation plan
(milestones M0 to M5): datekey, profile, provider, codec, agewrap,
extension, capsule, accesskey, the datekeys CLI, official vectors and
fixtures, the mutation corpus, fuzz targets, interop and live tests,
CI workflows, traceability and policy documents.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>