lib/datekeys.dart exports the formats, as index.ts of datekeys-ts: the
frames, PUBLIC_HEADER, CONTROL_CBOR, the .dkk, the extensions and their
registries, the Provider Profile, the DateKey with its rounds and times,
and the padding; the frame of BODY, the digest and the helpers of the
schemas stay internal for stage 4c. The README describes the modules, the
enums and the errors without a code, the Standard registry and the checks
it is given, the one difference of the formats between Go at c531e93 and
the tag spec-v0.11, and the generator of the vectors; the changelog the
stage, its tests and the faults injected. cbor_vectors_test.dart drops the
test it kept skipped until the decoders of the schemas, which
formats_vectors_test.dart now runs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A fault that ignored the top bit of FLAGS of a .dkc passed the tests: the
cases had FLAGS of 1, or random bytes with other bits set. The generator
now writes each bit of FLAGS and of RESERVED alone, in the PRELUDE of a
.dkc and in the frame of a .dkk, with the text of Go, and the tests on the
VM and on Node.js try every bit of both frames.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A fault injected in the order of the layers of PUBLIC_HEADER, parsing the
DateKey before the rule across the extension arrays, passed the tests: no
random case had a DateKey of layer 4 and a fault of layer 3 together. The
generator now builds, for PUBLIC_HEADER, CONTROL_CBOR of the three
formats, the Provider Profile and the .dkk, each fault of a list alone and
each pair of them on a valid object, with Go's code and text: 153, 360,
153 and 181 cases, the .dkk sometimes with FLAGS 1 too. The cases use no
random value, so the other sections are the same as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tool/formats_go_vectors.go runs in the module of datekeys-go at c531e93,
without changing anything there, and writes test/vectors/formats_*.json:
the result, the normative code and the text of Go on inputs of a fixed
seed, valid and broken in every layer of spec §69.1, and on the fixtures
of testdata/, edited:
- the PRELUDE (229 cases), the steps 1 to 3 of capsule.Inspect on cut and
edited fixtures (492) and whole .dkk files (268);
- PUBLIC_HEADER (660) and CONTROL_CBOR of the three formats (618);
- Provider Profiles decoded (163) and validated as values (60);
- extension arrays (260), Canonical (80), CheckDisjoint (50), the
registries with places (120) and CheckWrite with Standard (60);
- dk1_ strings (466);
- RFC 3339 parsed (434) and formatted (80), Resolve (320), RoundTime (64),
Validate (128) and MaxRound (8), on profiles of other genesis times and
periods;
- PaddedLength and PayloadAgeLength at the boundaries up to L_MAX (474),
and the check of the padding of capsule.Open at step 17 on fixtures whose
PAYLOAD_AGE is encrypted again with an edited plaintext (56);
- the encoders on values and the decoders at the limits of spec §57 (90);
- the frame of BODY (260) and the zeros of the area (60).
The output is the same on every run. formats_vectors.g.dart holds every
eighth case as Dart constants, so that the differential runs compiled to
JavaScript too, on Node.js; a test on the VM checks that they are those of
the files. Every file is under 310 KB.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/src/header.dart, control.dart and accesskey.dart port DecodeHeader,
EncodeHeader, DecodeControl and EncodeControl of package capsule and
package accesskey of datekeys-go at c531e93, in the layers of spec §69.1
and with the texts of Go: the limit of the frame, the type tag and the
schema version, the CBOR profile with the re-encoding and the CDDL, keys 6
and 7 of CONTROL_CBOR versions 2 and 3, and only then the DateKey of the
header and access_type and access_material of the .dkk. The .dkk is
written with the rule of spec §72 for the extensions of the specification
and read back before it is returned, as MarshalBody. I_PAYLOAD and
access_material are copied once and wiped on every path; their objects
print without them. The access policy is the enum AccessPolicy.
The tests read every fixture of testdata/: the PRELUDE, the sections and
header_binding of the 24 capsules, their header and control decoded and
written back, the round time of their DateKey, P, and in format 3 the frame
of BODY, the area, the head and the files; the six .dkk with their
capsule_digest. And the shared vectors dk1.json, quicknet_rounds.json,
profile_quicknet.json, padding.json and the 172 schemas of cbor.json,
which stage 1 left aside, each decoded by its schema and written back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/src/profile.dart ports package profile of datekeys-go at c531e93: the
Deterministic CBOR of a Provider Profile and its profile_hash, Decode and
Validate with rules 1 to 3 of spec §12.1 in their order and the texts of
Go (a period printed as Go prints a time.Duration), the drand schemes that
tlock supports and the group of their key, checked with
checkCompressedPoint, the chain hash of drand's chain.Info, MaxRound, the
pinned Quicknet profile and the registry with Default. Profile implements
PinnedProfile, which the verification of releases of stage 3 reads.
lib/src/datekey.dart ports package datekey: dk1_ strings, parsed with the
four Base64 decoders of Go and a JSON reader with the acceptance of
encoding/json with UseNumber, and numbers read by their exact decimal
value, with the texts of Go and its %v of the values; Resolve, RoundTime,
Validate and UnlockAt; and Instant, seconds and nanoseconds, with the RFC
3339 of Go's time.Parse(time.RFC3339Nano) and of Format, as datekey.ts of
datekeys-ts. A round is an int up to 2^53-1, exact on the web.
The tests, on the VM and compiled to JavaScript, check properties on
values of a fixed seed: dk1_ strings that read back, instants that format
and parse back to the nanosecond, and rounds whose time is the first at or
after the instant, at the end of the range of several profiles.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/src/extension.dart ports package extension of datekeys-go at c531e93:
the structural rules of an array (1 to 64 entries in the order of the
UTF-8 bytes of extension_id, never of the UTF-16 code units of a String;
an extension_id of 1 to 256 bytes; data absent or non-empty) checked while
it is decoded and before it is written; Canonical, CheckDisjoint; the
registries with the optional data check and places of Go (an abstract
ExtensionRegistry whose defaults are those of a Go registry that is not a
DataValidator nor a Placement), ExtensionSet and KnownIn; CheckCritical
and CheckNoncritical, with and without the object; and CheckWrite with the
Standard registry of the extensions of spec §72, whose checks of the data
of a note and of a locator are given to it, since the rules of a note need
the tables of the rules of paths of stage 4a.
lib/src/schema.dart holds the helpers of the decoders of the objects, as
schema.ts of datekeys-ts: the key of a failing read, the required keys and
the extension arrays at their keys.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/src/framing.dart ports ParsePrelude, Prelude.Bytes, PayloadOffset and
HeaderBinding of package capsule and the frame of Decode of package
accesskey of datekeys-go at c531e93, with their checks in the order of
spec §23 and §40 and their texts, and splitCapsule and FramingException,
the steps 1 to 3 of capsule.Inspect, as framing.ts of datekeys-ts. The
format of a capsule is the enum CapsuleFormat.
lib/src/padding.dart is padding.go: PaddedLength and PayloadAgeLength for
the codes of PaddingRule, exact up to L_MAX on the web too, where an int is
a double: bitlen doubles a power of two and the roundings divide and
multiply by powers of two, with no shift or mask of more than 31 bits. And
PaddingCheck, the checkPadding of capsule.Open at step 17, fed the
plaintext piece by piece.
lib/src/body.dart is the frame of BODY of format3.go (ParseBodyFrame,
CheckArea, ContentLength), and lib/src/digest.dart the incremental SHA-256
of a capsule_digest, with the comparison of checkCapsuleDigest. The errors
that Go returns without a normative code are ArgumentErrors with its text.
The tests run on the VM and compiled to JavaScript: the order of the
checks on capsules built in memory, P against a statement of spec §29.1 in
BigInt, next to 2^53 and at the boundaries of 32 bits, and the digest
against package:crypto however the file is cut.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/src/pathrule_tables.dart is the output of internal/pathrule/gen -dart
of datekeys-go at c531e93, from Unicode 18.0.0 and WindowsBestFit, with
TablesDigest 07cf5d54…; the rules of paths and texts that use it come
with stage 4.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/datekeys.dart exports the verification of releases (PinnedProfile,
Release, ReleaseSource, verifyRelease, suppliedRelease, fetchRelease and
quicknetScheme) and checkCompressedPoint with BlsGroup and PointVerdict, as
datekeys-ts does; the curve arithmetic, the IBE and the tlock stanza stay
internal, and encryption waits for the writer of stage 6. The README
describes the modules, the deliberate differences with Go, the caveat
that BigInt is not constant time, the timings on the VM and on Node.js,
and the generators of test/vectors/.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Like those of stage 2, the four generators of stage 3 run in the module
of the datekeys-go next to this repository, which they import, without
changing anything there: cd ../datekeys-go && go run ../datekeys-dart/tool/
… The tag spec-v0.11 and the draft v0.12, whose packages provider, agewrap,
profile and capsule.ParsePrelude are the same, give the same output as the
committed vectors, byte for byte.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reduction modulo p of a BigInt costs several times a product, and the
formulas of kilic reduce every product. The field layer gains FpWide, a sum
of products not yet reduced, and the product and the square of Fp6, its
product by the sparse element of a line and the square in Fp4 of the
cyclotomic square add their products in that form and reduce each
coefficient once. The values are the same, which the vectors of Go check;
a pairing takes about 15 % less on the VM and 13 % less on Node.js.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The faults injected at the end of the stage were all caught on the VM, but
three of them only there: the point at infinity taken for a signature, the
code of a failing source kept at step 9, and the length of the stanza body
left unchecked. Three tests that read no file now catch them compiled to
JavaScript as well, the stanza being the one of the encryption of Go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tool/bls12381_bench.dart times, on the VM or compiled to JavaScript, the
decoding of a point of G1 and of G2, a pairing, the verification of a
Quicknet round signature, the IBE decryption and encryption, and steps 10
and 11 of the opening together, as the plan asks in «Rendimiento». It
reads no file, so that a phone can run it too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ibe.dart is DecryptCCAonG2 and EncryptCCAonG2 of drand/kyber for Quicknet,
as ibe.ts of datekeys-ts: H2 over GT in the order of kilic, H3 with its
rejection of candidates, H4, the identity of a round, the gates of the
signature and of U, and fixed texts that carry no value of the
computation. Encryption takes an injectable sigma, so that the vectors of
Go reproduce byte for byte; sigma and r are secret and BigInt is not
constant time.
release.dart is provider.Verify, in its order and with its texts, for the
scheme of Quicknet only, as release.ts; the supplied release; and the rule
of step 9, under which whatever a source throws is
ERR_RELEASE_UNAVAILABLE. tlock.dart is NewTimeIdentity with its Unwrap and
NewTimeRecipient of agewrap on the arguments and the body of the stanza.
tool/ibe_go_vectors.go, tool/tlock_go_vectors.go and
tool/release_go_vectors.go, ports of the generators of datekeys-ts where
they exist, write the vectors from kyber, tlock, age, provider and agewrap
on the fixtures of testdata/. The ciphertexts with a random sigma are the
frozen ones of datekeys-ts at 289fe71, decrypted again by Go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The field layer, an extension type over BigInt that a later implementation
with fixed limbs can replace alone; the tower Fp2, Fp6 and Fp12 with the
formulas of kilic; G1 and G2 with their compressed encodings and the
verdicts of FromCompressed (flags, the point at infinity, coordinates below
p, the curve and the subgroup, checked in G2 by psi(P) = [x]P); the optimal
ate pairing with the final exponentiation of kilic, GT serialized c1 before
c0 at every level; and the hash to G1 of RFC 9380 with the DST of Quicknet.
tool/bls12381_go_vectors.go writes test/vectors/bls12381_vectors.json with
kilic and kyber-bls12381: the frozen edge cases of datekeys-ts with their Go
verdicts recomputed, and decodings, sums, multiples, pairings, hashes, maps
and BLS signatures drawn from a fixed seed. BigInt is not constant time:
the README says where that matters.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The modules of the primitives and of age, the integer bounds of each, the
note that BigInt is not constant time and where it is used, the vectors of
test/vectors/ and how Go writes them, and the timings on the VM and on
Node.js.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The unmasked rotations of the previous commit were exact, but on the VM
they left values of up to 62 bits in the sums, against the rule of the
package: every value in 32 bits on the VM as on the web. Masked again, the
unrolled rounds are as fast: PBKDF2 at 600 000 iterations takes about 1 s
on the VM.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The working variables rotate by name instead of by assignment, and the
left halves of the rotations are no longer masked: on the VM their bits
above 32 only reach sums that are masked before any other use, and on the
web `<<` keeps 32 bits itself. PBKDF2 at 600 000 iterations goes from 1.27
to 1.11 s on the VM; HMAC of package:crypto takes about 3.5 s for the same
work.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On the web a shift truncates to 32 bits, so the carries of Poly1305 are
taken with a division. A fault injected in the carry of limb 0 passed every
test, on the VM, where the shift is exact, and on Node, because no vector
took that sum past 2^32. The generator now simulates the 13-bit limbs with
the largest r that clamping allows and finds two messages that do; Go's
poly1305 gives their tags, and the fault fails on Node. The sums of the
other limbs stay below 2^32 (at most 4.14e9 with that r).
The strict Ed25519 verification is also checked against
testdata/vectors/ed25519_strict.json directly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The product of Poly1305 and that of the field of curve25519 are unrolled
over locals, as TweetNaCl-js does, and ChaCha20 XORs whole blocks: on the
VM, X25519 goes from 2.4 to 1.3 ms, Ed25519 verification from 8.6 to
4.7 ms and ChaCha20-Poly1305 from 40 to 19 ms per MiB. The bounds of the
arithmetic do not change.
tool/bench.dart times the primitives on the VM or compiled to JavaScript.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
age: the header and its limits (internal/format), with the texts of Go's
errors; the header MAC; the X25519 and scrypt stanzas, the scrypt work
factor bounded at 16 by default, as authorkey bounds it; the payload key
and the STREAM of internal/stream, decrypted as the ciphertext arrives,
with the same end-of-file cases as Go's DecryptReader. Each failure is an
AgeException with Go's text and its phase, the header or the payload.
agewrap: the stanza rules of OUTER_TIME_AGE, PAYLOAD_AGE and
INNER_ACCESS_AGE, the probe of the stanzas, and the payload and access
identities, with the fixed texts and the codes of datekeys-go.
tool/gen_age_vectors.go writes, with filippo.io/age and agewrap:
- test/vectors/age.json: X25519 and scrypt files, their truncations and
manipulations, a corpus of headers against the grammar of spec §28.1
and the 2 MiB limit, the rules and identities of agewrap, and Go's text
for each. A file of more than one chunk is its header, nonce and file
key; the tests encrypt the plaintext again and check the SHA-256 of the
whole file;
- test/vectors/age_fixtures.json: the PAYLOAD_AGE of every fixture with its
payload_identity, and the INNER_ACCESS_AGE of the time_and_key ones,
taken from OUTER_TIME_AGE with the release of the fixture.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The generator checks its copy of the strict profile against the
testdata/ of datekeys-dart, the copy synced at spec-v0.11, rather than
the working tree of datekeys-go. The vectors do not change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SHA-256 with its own compression, and on it HMAC-SHA256 with the inner and
outer states of the key computed once, HKDF-SHA256 and PBKDF2-HMAC-SHA256,
whose iterations are two compressions over words; scrypt with Salsa20/8;
ChaCha20, Poly1305 in 13-bit limbs and ChaCha20-Poly1305 with the tag
compared in constant time; X25519 on the field of TweetNaCl in doubles,
with the all-zero secret refused; the strict Ed25519 verification of
internal/ed25519strict; Go's Base64 with the offsets of its errors, and
age's Bech32.
tool/gen_primitive_vectors.go computes every expected value with Go and
x/crypto, from the inputs of RFC 5869, 7748, 7914, 8032 and 8439, edge
cases and seeded random ones. The tests also run compiled to JavaScript,
from a Dart copy of the JSON, without the cases that would take too long.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tool/check.sh runs dart test -p node after dart test: the tests that read
no file check on every commit that the integers of the library are exact
on the web, where an int is a double and the bit operators work on 32 bits.
The gate needs Node.js, as datekeys-ts does. The author decided it on 5
October.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- README: the state, with the modules of stage 1 and how its integers
are exact on the VM and on the web, and how to run the tests compiled
to JavaScript, which the gate does not run.
- CHANGELOG: stage 1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/src/der.dart is the port of internal/der/der.go at 601e6d2, the
draft of v0.12, whose DER already differs from spec-v0.11: check, split,
content, setOfSorted and parseTime, with the texts of the reference. It
is internal, as in Go, and keeps the names of the Go package for an
import with a prefix.
parseTime reads UTCTime and GeneralizedTime in their forms of X.690
and refuses a date or a time that does not exist. It returns a DerTime,
exact to the nanosecond as Go's time.Time and unlike Dart's DateTime:
its fields and its seconds since the epoch, below 2^53.
The tests port der_test.go, with the texts that Go prints. The fuzz
target is a property over seeded mutations of its seeds and of the
signatures and tokens of security_cms.json.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/src/cbor.dart is the port of codec/codec.go: CborEncoder,
CborDecoder, unmarshalCbor, peekSchema, checkSchema and walkCbor, with
the same reads, the same checks in the same order and the same error
texts, such as "codec: offset 0: 23 is not in its shortest form
(initial byte 0x18): ERR_NON_CANONICAL_CBOR".
Integers are exact on the VM and on the web, where an int is a double
and the bit operators work on 32 bits. An argument of eight bytes is
read as two halves of 32 bits, and is an int up to 2^53-1 and a BigInt
above, map keys and the numbers of the error texts included. uint
returns an int, since every schema bounds its integers at 2^53-1, and
uint64 a BigInt. The map that peekSchema reads is bounded at 2^63-1,
Go's math.MaxInt, on the web too.
Two kinds of text are of Dart only. CborEncoder.uint refuses an int
outside 0..2^53-1 and uint64 a BigInt outside 0..2^64-1, with the text
of datekeys-ts, where Go's uint64 cannot hold such a value. And the only
invalid text that a Dart String holds is a lone surrogate: the error
quotes it as Go quotes its bytes in generalized UTF-8.
The tests port codec_test.go, internal_test.go and vectors_test.go,
with the texts that Go prints, and cbor.test.ts. The fuzz targets are
properties over seeded inputs, checked against a reference encoder and
decoder written apart, as internal/cbortest. cbor.json runs its 36
accept and 67 reject vectors with the walk limits and the values; its
172 schema vectors are read and wait for the schema decoders of stage 4.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- lib/src/errors.dart, the port of errors.go: ErrorCode, the 19 codes in
the order of section 69, and DateKeysException, which carries one of
them with the message of the reference, the context and then the code.
wrap and withContext are fmt.Errorf("prefix: %w"), errorCode is
datekeys.Code. test/errors_spec_test.dart reads section 69 from
../datekeys-go at the tag spec-v0.11 and compares its ERR_ lines with
the catalogue; it is skipped when that repository is missing.
- lib/src/bytes.dart, as bytes.ts of datekeys-ts: hexadecimal,
comparison and concatenation; strict UTF-8 that keeps a leading
U+FEFF, which the Utf8Decoder of dart:convert drops on the VM and on
the web; Go's utf8.DecodeRune; and Go's %q, with the table of
strconv.IsPrint of Go 1.26 copied from datekeys-ts and the SHA-256 of
the whole rune set pinned. A lone surrogate, which a Dart String may
hold, is written in generalized UTF-8, which is not UTF-8.
- lib/datekeys.dart exports the errors and the byte functions that a
user needs.
- The tests that read files are marked @TestOn('vm'), those of stage 0
included, so that the others also run compiled to JavaScript with
dart test -p node.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pure Dart package, without Flutter, for the app that the author will
write in Flutter (docs/PLAN_dart.md, stage 0):
- pubspec.yaml: the package datekeys, unpublished, for Dart 3.13; at run
time only package:crypto, and in development only package:test, which
the author approved on 5 October.
- testdata/ vendored from datekeys-go at the tag spec-v0.11 (ae33434),
124 files, with the same testdata/SOURCE.json that datekeys-ts writes for
that commit.
- tool/sync_testdata.dart, the port of scripts/sync-testdata.mjs, and
test/testdata_test.dart, which checks the copy and that every file names
specVersion; test/version_test.dart keeps pubspec.yaml and
lib/src/version.dart in step.
- tool/check.sh, the local gate: format, analysis with every info fatal,
tests, and the copy against ../datekeys-go.
- The licence, Apache-2.0, as the other two implementations.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>