Repository navigation
A language-neutral test-vector pack that both readers are held to - #276
Merged
Merged
Conversation
docs/vectors/ holds the expected bytes for the text and binary forms of KEYM v2, v3 and v4 as plain JSON, for anyone writing a third reader. There are 94 vectors in seven families. - primitives.json has HKDF-SHA-256 (RFC 5869 A.1 to A.3, prk and okm), ChaCha20-Poly1305 (RFC 8439 §2.8.2 and A.5), AES-256-GCM (NIST CAVP) and Argon2id, transcribed from pyca's cryptography_vectors 50.0.2 and checked against the libraries each reader loads. - containers.json has whole containers from pinned inputs with kdf_input, slot_key, core_header, k_table and slot_table_mac, including v3 §8's and v4 §8's vectors, all three ciphers, a key file and an NFD password. - shares.json, parts.json and text.json have a 3-of-5 split from pinned coefficients with both share texts and the set code, the KMPART1 and KMPART2 strings, armor in both widths, the IGNORABLE set and padded_len. - reject.json has 50 inputs a reader must refuse with v2 §6's one generic failure, each tagged with its rule. The container rows that test a rule are sealed correctly around one violation, so a reader that skips the rule opens them. - accept.json has 21 inputs a reader must open although it may be tempted to refuse: a bad slot beside a good one, a stripped slot table (which must also be reported), armor full of ignorable characters, shares out of order or repeated, and parts out of order. reference/vectors.py generates the pack from keym2.py and checks it, including the inputs and outputs printed in v3 §8 and v4 §8 and the files' exact text. scripts/vectors-test.mts reproduces every vector with the app's code. The pack is append-only, a wrong vector is superseded by an erratum that both suites skip, and its count is asserted in both. v2 §7 now states how armor is wrapped. keym-v2.ts exports the three intermediate derivations for the suite. npm run test:vectors, a conformance workflow step and the README list run it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
Bet 4 of the review report's plan.
docs/vectors/is a language-neutral test-vector pack for KEYM v2, v3 and v4, as plain JSON that a third implementer can read with no Node, no Python and no code from this repository. Both readers here are held to it on every pull request.Stacked on #275 (Bet 5), because both change
package.json,README.mdand the conformance workflow. GitHub retargets it as the stack merges.The pack
94 vectors in seven families.
docs/vectors/README.mddescribes every field.primitives.jsonprkandokm), ChaCha20-Poly1305 (RFC 8439 §2.8.2 and A.5), AES-256-GCM (NIST CAVP) and Argon2id, including RFC 9106 §5.3containers.jsonkdf_input,slot_key,core_header,k_tableandslot_table_mac. v3 §8's and v4 §8's vectors, all three ciphers, a key file, a decomposed password, and the base the reject rows changeshares.jsonparts.jsonKMPART1andKMPART2stringstext.jsonpadded_lenacross v4 §4.2's branchesreject.jsonaccept.jsonAuthentic reject rows. The container rows that test a rule are sealed correctly around one violation. Every AAD, wrap, tag and the slot-table MAC is computed over the bytes as written, so a reader that skips the rule opens the row. There are 17 of them:
final_flag0;The sealer must reproduce the base container byte for byte before it writes any of them.
Accept rows. These catch the reader that refuses too much:
memory_kibbelow 8 ×parallelism, which §6 admits and no library can derive;How it is held
reference/vectors.pygenerates the pack fromkeym2.py. It requires each file to equal what it renders, byte for byte. It also checks:keym2.py's own libraries;keym2.pyopens every container and accept row, and refuses every reject row with its exact generic message;scripts/vectors-test.mtsreproduces every vector with the app's code:--writevalidates every family before it writes anything and refuses to change a committed vector. A wrong vector is superseded by anerratumnaming its replacement. Both suites skip it, and the README tells a third reader to do the same.npm run test:vectorsruns both suites, and so do a step in the conformance workflow and the README's test list.VECTOR_COUNTis asserted in both.keym-v2.tsexports its three intermediate derivations for the suite. The app does not call them through that export.Sources
rfc-editor.orgis blocked from the build environment. The published values were therefore taken from pyca'scryptography_vectors50.0.2, which carries these RFCs' and NIST's values as data files. Each vector names the exact file and entry, and both suites check every one against the libraries the readers load.RFC 9106 §5.3's Argon2id vector uses a secret and associated data.
keym2.py's library checks it through its low-level interface, and the TypeScript skips it, because hash-wasm takes no associated data.Review
Two independent reviews ran before anything was pushed, one on the vectors' correctness against the spec and one on the suites' strength. Because the pack is append-only, a vector that encodes a misreading would be a permanent erratum. The reviews found 22 distinct problems once their overlap is merged, all fixed here. The ones that changed the design were these.
accept.jsonholds the same bad slots beside good ones.slot_countor header checks in either reader still passed, because the mutated byte also broke authentication. Those rows are now sealed around the violation.Negative controls
Each was applied to a copy, confirmed to compile, and shown to fail the vector that names it.
Every rule an authentic row tests, removed from each reader in turn. 25 of 26 fail their own row and no other. The exception is the reserved header byte in
keym2.py. Its AAD is rebuilt from the parsed header, which packs that byte as zero, so the slot's tag refuses the row as well as the explicit check.Reader defects.
Each fails both suites, or the suite for the reader changed.
Pack and documents. These all fail by vector id: a flipped byte in a container, an HKDF answer, an Argon2id answer and a set id; a dropped vector; a misprinted master key and container byte in v3 §8, and a misprinted MAC in v4 §8.
The machinery.
--writeleaves every file untouched.Not in this PR
scripts/*.mts).vectors-test.mtsis not typechecked bynpm run typecheck, like the other suites there.Verification on this tree
npm run typecheck,npm run build, and everytest:*script inpackage.jsonexcepttest:browser(45 scripts,test:vectorsamong them) pass on the head commit.--workers=2on the full suite, after a plainnpm run build, gives 360 passed, 5 skipped and 0 failed. An earlier run, made while the review agents were running suites on the same machine, failedasync-guard.spec.ts"switching tabs mid-derivation" andcalibration.spec.ts"calibrating twice agrees with itself". The first is one of CLAUDE.md's two named timing flakes, and the second is the calibration test CLAUDE.md says fails under CPU contention. Both passed on the quiet re-run above. Firefox and WebKit are left to CI.Generated by Claude Code