nist_curves.dart reads an uncompressed point as Go's
ecdsa.ParseUncompressedPublicKey does, and computes u1 G + u2 Q in
Jacobian coordinates with Shamir's trick, the infinity included.
ecdsa.dart is VerifyASN1: the encoding as cryptobyte reads it, r and s
in [1, n - 1] and never reduced, s above n/2 accepted, the hash cut to
the bits of the order. rsa.dart is VerifyPKCS1v15, which rebuilds the
encoding and compares it whole, and VerifyPSS with a salt of the length
of the hash, with the bytes before emLen that must be zero; and the
hashes of the table, SHA-256, SHA-384 and SHA-512 of package:crypto.
All on BigInt, exact on the VM and compiled to JavaScript, and not
constant-time: a verification sees public values only. The curve
constants are those that the vectors record from Go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/datekeys.dart exports author.dart and security.dart, as package
capsule of Go exports the commitments and the evaluation, and the tests
that imported them from lib/src import them from the library.
The README and the changelog give the testdata of the branch v0.12 of
datekeys-go, the modules of part 5b with their notes, the boundary with
the reader of CMS of part 5c, the vectors of the security area, and the
tests and the faults injected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OpenOptions.evaluator is now evaluateSecurityInput, so that opening a
capsule of format 3 gives the verdicts of Go at step 17: the signature of
alg 1 and every verdict of the form, with the author keys of the options,
and the signature of alg 2 and the seal of seal_type 2 not evaluated
until a reader of CMS is given. notEvaluated stays for a caller that
shows no verdict.
tool/open_go_vectors.go records the verdicts of each capsule of format 3
that opens, with their lines, the key and the label of alg 1 and the
earliest valid seal, and opens the fixtures signed with alg 1 also with
their author key saved, F3, and with another, F4. Every case of
open_cases.json and every case of the mutation corpus that opens gives
those verdicts and lines: format3_signed, format3_unsigned,
format3_signature_unsupported, format3_seal_unsupported,
format3_security_v2 and format3_note all of them, and format3_signed_cms
and format3_sealed the part that needs no reader of CMS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
author.dart ports what an author signs and a seal seals from
signature.go of datekeys-go: payload_commit, control_commit over
CONTROL_SIG in each format, head_digest, signers_digest, AUTHOR_MESSAGE
with its prefix and its 99 bytes, its code taken byte by byte as Go
takes it, SIG_PART and SEAL_SUBJECT.
security.dart ports SECURITY_CBOR and EvaluateSecurityIn: the outer
map, author-signature and seal with the schema and the limits of Go,
their encoders, and an evaluation that never throws. X for an outer map
that fails its layer 2 or 3, version 2 among them; F0 to F4 for the
signature, with verifyStrict for alg 1 and the key matched against the
saved ones by its dkauthor1 string; S0 to S2 for the seal; and a failure
inside one part fails that part only, as Go recovers a panic. Without a
context it reads as a reader of v0.10. securityContext is
newSecurityContext with the head digest, control_commit at zero when
CONTROL_SIG cannot be encoded, and holderText the rule of a name of a
certificate.
The signature of alg 2 and the seal of seal_type 2 belong to the reader
of CMS of stage 5c, behind the interface CmsEvaluator: without one their
verdict is null, not evaluated, never guessed.
verdicts.dart gains the texts of Go at the draft v0.12, Verdicts.lines
and sealedAt, Detail, SignerLine and SignerResult, and verdicts that may
be evaluated in part.
The tests check every case of security_vectors.json, security.json in its
context, the commitments, the signature and the seal of each fixture of
format 3, and the boundary with a reader of CMS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The README describes the modules of part 4c and their notes: the input in
memory or from a ByteSource and what is read of it before the release;
the output and the sinks, required for their format, closed or committed
only at step 18 and aborted after any failure; the result, which never
throws for an invalid capsule; the credentials, the key of words among
them; the evaluator of stage 5 and accept; StandardExtensions with the
rules of the note; the differences of form with Go; and a bug of dart2js
of Dart 3.13 that an application for the web should know. It adds the
times of the opening, the generators of the vectors of stage 4c and their
files. The changelog has the part, its tests and the 15 faults injected,
all of them found on the VM and 13 on Node.js. The comment of
lib/datekeys.dart says what the library reads now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/src/open.dart and open3.dart port Open and openBody of package capsule
of datekeys-go at c531e93, with the checks, codes, steps and texts of the
reference and the detail of each check: the .dkk of step 9.a, decoded or
still encoded, with its material, its critical extensions, its capsule_id
and its capsule_digest; at least one credential; the clock and the release,
with the rule of step 9 for the failures of its source (sourceFailure);
its verification at step 10; OUTER_TIME_AGE with the tlock stanza;
INNER_ACCESS_AGE with the X25519 identities, those of the .dkk and the key
of words, and the rules of the slots; CONTROL_CBOR, header_binding,
I_PAYLOAD and P; PAYLOAD_AGE streamed, with the padding of format 2
checked and never delivered, and in format 3 the frame of BODY, the area,
the head, each file to the sink with its SHA-256 and the padding, with the
precedence of spec §63; and the commit. A failure of age keeps the code of
the identity that reports it, or is ERR_INTEGRITY with the reason of its
phase, as classify of Go.
openCapsule opens a capsule in memory and openCapsuleSource one that a
ByteSource reads: the prefix of the inspection and the nonce of
PAYLOAD_AGE before the release, then pieces of 1 MiB. lib/src/sink.dart
has ByteSink, for the content of formats 1 and 2 and for each file, and
FileSink, for the files of format 3, as the dst and the Sink of Go, with
MemoryByteSink and MemoryFileSink. Nothing is presented as valid before
step 17 ends: the output is closed only then and aborted after any
failure, and the sink aborted after any failure that follows its begin
(spec §56).
The signature and the seal are stage 5: lib/src/verdicts.dart has the
verdicts and the SecurityEvaluator, given what newSecurityContext and
EvaluateSecurityIn of Go take, which never fails the opening; the default
evaluates nothing. OpenOptions.accept is Accept of Go. And
AgePayloadDecryptor.wipe clears the key of a STREAM left unread.
The tests run open_cases.json and the mutation corpus with the texts and
the checks of Go, in memory and from a source read in pieces; capsules of
several MiB made from the fixtures, for the streaming; a capsule with a
stanza for a key of words; and the caller, the sinks and the evaluator.
open_test.dart runs on Node.js too, with open_vectors.g.dart.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/src/inspect.dart ports Inspect of package capsule of datekeys-go at
c531e93: the steps 1 to 8 of spec §63, without network and without
secrets, with the check of each step as Go records it, its name and its
detail, and Inspection with the fields of the steps that passed. The
opening runs them with a hook right after step 2, as the afterPrelude of
Go. inspectedLength, from prefix.ts of datekeys-ts, names the first bytes
that give the inspection of a whole file, so that a large capsule is read
up to one byte after the largest age header of PAYLOAD_AGE, and
maxAccessKeyRead the most bytes of a .dkk that its decoder needs. And
inspectView and inspectJson, the exact output of datekeys inspect -json
of internal/inspectview, with the public note.
lib/src/source.dart has ByteSource, the bytes of a capsule read by ranges,
which the application adapts from a file or a Blob, and BytesSource, over
bytes in memory; inspectCapsuleSource reads only the prefix.
The tests compare, byte for byte, the 24 fixtures/*.inspect.json and the
views of open_inspect.json, and each of the 5110 mutations of
inspect_differential.json with its code, its step and the text of Go,
also from a source read in pieces; and the prefix at the limits of age.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/src/note.dart ports CheckNote, NewNote and Note of package extension
of datekeys-go at c531e93: checkNote and checkNoteData check the length,
the UTF-8 and the rules of text of the declared author, in that order and
with the texts of Go, on the bytes of the note as Go reads its string;
newNote, publicNote and unusableNote, and Header.publicNote and
Header.unusableNote. StandardExtensions checks the data of a note as the
Standard of Go does, and its parameter validateNote, which could replace
those rules, is gone.
lib/src/head.dart ports DecodeHead, EncodeHead and CheckHeadEnd of
format3.go: the limit of HEAD_LEN, the type tag and the version, the CDDL
with R1 and R8 on the UTF-8 bytes of the paths, never on the UTF-16 code
units of a String, and then the comment, the declared author and the files
with the rules of pathrule and their layout, by subtraction, and R7 and R9,
as ERR_HEAD_INVALID with the text of Go, and the critical extensions of the
head. decodeWrittenHead is the decoder without the critical extensions, for
the self-check of the writer of stage 6.
The tests read open_heads.json, open_notes.json, head_schema.json with the
detail of each ERR_HEAD_INVALID, the trees of paths.json as heads of files
of 0 bytes, and the head of each fixture of format 3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/datekeys.dart exports the key of words, as Go exports its package
wordkey: normalizeWords, checkWords, wordKey, WordKeyException, minWords,
minLetters and wordKeyRounds. wordIdentity stays internal, since it
returns an identity of age.dart, and so do the rules of paths and texts,
as internal/pathrule does in Go: the head and the public note of stage 4c
will use them.
The README says what stage 4a ports and how: the bytes of Go, the
platform's Unicode left aside, the errors, the round of 53 bits, the one
difference with datekeys-ts and what is exported; the integer rule of the
tables; the timings; and how the vectors are written, the generator of
the paths in an export of datekeys-go. The changelog has the entry of the
stage.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Faults injected one at a time found four that the vectors let through:
R2 at 32 segments, R3 counting code points instead of UTF-16 code units
in an astral NFD, U+036F kept by normalizeWords, and DEL let through by
checkWords. The generators now write both sides of each limit: 32 and 33
segments, 255 and 256 bytes in letters of two and four bytes, 255 and 256
UTF-16 code units of NFD and 252 and 258 from astral decompositions,
bases of 8 and 9 runes, extensions of 3 and 4 also astral, the first and
the last mark of U+0300 to U+036F and their neighbours, and U+001F,
U+007E, U+007F, U+0080 and U+00A0 in a word. All four faults are caught
now.
wordKeyPassword is the password P of spec §38.1, as wordKeySalt is S, and
wordKey uses both: the tests compiled to JavaScript check P against the
one of Go, so that a wrong separator of the words is caught there too,
not only by the keys of 600 000 iterations on the VM.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/src/wordkey.dart ports package wordkey of datekeys-go at c531e93:
normalizeWords is wordkey.Normalize (the NFD of pathrule.dart, without
U+0300 to U+036F, the simple lowercase of Unicode 18.0.0, split at the
white space of §38.1), checkWords is wordkey.Check with its texts,
wordKey is wordkey.Key (PBKDF2-HMAC-SHA256 of sha256.dart, 600 000
iterations, with the salt of §38.1) and wordIdentity is wordkey.Identity,
an X25519Identity of age.dart. As in pathrule.dart, the functions whose
name ends in Utf8 take the bytes of a Go string, and a String is taken as
utf8Bytes writes it.
tool/wordkey_go_vectors.go runs in the module context of datekeys-go and
writes test/vectors/wordkey_vectors.json and its Dart copy: 400 texts and
their words, 513 lists of words and the result of Check, and four keys
with their salt, the PBKDF2 of 1000 iterations for Node.js and the
recipient, the vector of §38.1 first. The keys of 600 000 iterations run
on the VM only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/src/pathrule.dart ports internal/pathrule of datekeys-go at c531e93
(spec §29.5, §29.5.1, §29.6): NFD with the canonical ordering and Hangul,
the case folding, the simple lowercase, Default_Ignorable with the
whitelist of R4, the best-fit projections of R6c, every rule of a path
(R2 to R6c and R10), the tree (R7 with its key and the two paths it names,
and R9), and the texts of the comment and the declared author, with the
texts of Go. canonicalTables is pathrule.Canonical, and a test recomputes
tablesDigest from the lists.
Go reads a string as bytes, and so does this port: the functions whose
name ends in Utf8 take the bytes of a Go string, where a byte that is not
valid UTF-8 is the rune U+FFFD, and the limits count bytes; the others
take a String as utf8Bytes writes it. Each rule returns its violation, as
in Go, and only the public functions throw.
tool/pathrule_go_vectors.go runs in an export of datekeys-go, since
internal/pathrule cannot be imported from outside its tree, and writes
test/vectors/pathrule_vectors.json and its Dart copy: the cases of the
tests of Go and of datekeys-ts, 1300 strings and 350 trees drawn from a
fixed seed (marks, Hangul, ignorables, emoji, best-fit look-alikes,
device names, 8.3 aliases, limits, texts and invalid UTF-8), the cases of
R9, code points, and for each plane the SHA-256 of one line per code
point of each function. Every code point of every plane gives the results
of Go: planes 0, 1 and 14 also on Node.js.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>