Repository navigation
Conversation
…t checker; Details: TC-2223
…tor documents; Details: TC-2223
…rtificate checks; Details: TC-2223
…ficate SPEC rulings to the checker; Details: TC-2223
…ertificates in the checker; Details: TC-2223
…2223-s05-transcript-checker; Details: TC-2223
Merged
This branch has not been deployed
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.
Independent checker for threshold DKG and resharing transcripts (S0.5). Stacked on #493 (TC-2221), which sits on #492 (TC-2220); retarget to
mainafter those merge.tinycloud-threshold/vectors/checknow recomputes a whole genesis DKG and a whole reshare/refresh outcome from the raw signed records, using only the published SPEC. It covers the H0 start link and transcript chain, every closure and member signature and binding, the complaint and answer rules, QUAL/D selection, mpk and public shares, identity rejections, the 4 MiB bound and the malformed-message rules. It reuses lane A's primitives (TH, BLS12-381 decoders,@noble/curves2.4.0) and Ed25519 from the same package withzip215: false(strict RFC 8032). No new dependency;bun.lockis unchanged.SPEC changes (owner rulings, 2026-10-30)
The independent review approved this PR at
ee0d4d3d. A follow-up commit applies the owner's SPEC rulings toSPEC.mdand enforces them in the checker:MalformedDeal. This supersedes proposal 7.genesis_t = tandn ≥ 2t−1. Every successor requiresepoch ≥ 1andrekey ≤ epoch. A re-key must change mpk (previous mpk ≠ mpk), haverekey ≥ 1, and, like genesis, satisfygenesis_t = tandn ≥ 2t−1(UnsupportedFaultBudget). The re-key clauses were added in a second rulings commit after the delta review; they matchverify_successor's "genesis t = new t" and S0.2's "re-key uses the genesis budget".InvalidCeremony(authorized against the pinned certificate). This settles proposal 9. Rust's resharing reports a different code for this input, but it also rejects it, and codes are informative, so no Rust change is needed (Naomi, 2026-10-30).Clean-room statement
Files read for this checker (verbatim list). No Rust source under
tinycloud-threshold/src/, no Rust git history and no Rust diffs were opened.tinycloud-threshold/SPEC.md(whole file, including the S0.2, S0.3 DKG and S0.4 redistribution appendices)tinycloud-threshold/vectors/v1/dkg-genesis.json,reshare.json,cert-core.json(layouts, and the published Ed25519 fixture seeds for tests),primitives.jsontinycloud-threshold/vectors/check/*(lane A's checker:README.md,package.json,bun.lock,bunfig.toml,tsconfig.json,.gitignore,isolate.ts,cli.ts,schema.ts,vectors.ts,protocol.tsand the four existing*.test.ts)/var/tmp/tc2092-plan.J13a/plan-r2.md(sha256f701d2be…4d14verified): §0, §§3.0–3.11, §5 (allowed by Naomi for error names; it names none), §6@noble/curves2.4.0README.mdand theed25519.d.ts/abstract/edwards.d.tsdeclarations (API only).github/workflows/rust.yml(only to confirm the CI lane)/var/tmp/naomi-brief-lines.txt,host-hygiene.mdVector coverage
Every committed case agrees byte for byte (
bun run vectors: primitives 18/18, DKG 6/6, reshare 5/5).genesis_2of3genesis_2of3_selective_extractiongenesis_3of5_two_faultygenesis_3of5_answers_and_disqualificationEquivocated{round:1}(dealer 4);MissingAnswer(dealer 5)insufficient_reconstruction_valuesInsufficientRecoverywith R6 as last recordinsufficient_qualified_dealersInsufficientQualifiedwith R3 as last recordreshare_2of3_to_3of4refresh_2of3_answered_complaintreshare_wrong_constantMalformedDeal; D = [2,3]reshare_t_prime_complaintsComplaints; D in R1 order skips dealer 3reshare_insufficient_dealersInsufficientQualifiedSynthetic transcripts (
testkit.ts, signed with the published fixture seeds) cover each rule the vectors do not. In DKG: every disqualification reason, the order of rules 5–8 pairwise, self-complaints, R2/R3 index bounds, unrequired valid and invalid answers, missing/conflicting/malformed/wrong-count R4, R5 entries that are upheld, self-directed against a Feldman-invalid dealer, Pedersen-invalid, or against a Feldman-valid dealer, R6 shortfall and conflicts, and 3-of-5 with two silent members. Genesis ceremony rules: anchor, kind, current digest, counters, budget, directory contiguity and duplicate DIDs, option marker, signature cap. In reshare: every exclusion reason, the order of rules 4–7, R1 owner-order selection, other-cohort envelopes ignored, no self-exclusion, and entry checks. In both: identity mpk, top coefficient and public share; byte-identical and alternate-signature retransmissions; envelope, closure and certificate signature caps; record count; closure binding; list reordering. Strict RFC 8032: a ZIP-215-only signature (non-canonical R), S + L and a small-order public key are rejected.s02.test.tsruns everycert-core.jsoncertificate (genesis, reshare successor, re-key), ceremony, decode refusal and closed-round record through the same S0.2 layer; all agree. It also covers the §3.9 decoded-certificate rules: constant = mpk, top coefficient, evaluated shares, predecessor combinations, genesis t, option markers, anchor and signer.Checker-order reason codes (corruption probe)
Each probe flips one byte of one committed signed record, in every field class, for all 11 cases (first and last message of each round). 1309/1309 are rejected, each with the reason code this checker's order produces. Rejection is normative; the reason codes are informative (SPEC "Verifier conformance").
Re-signed one-byte payload flips reach the rule-level reason. Dealer commitment byte →
MalformedDeal(QUAL [2,3]). R2 version byte → malformed R2 contributes nothing (mpk unchanged). R4 byte → extraction fault, so a 5-record transcript isInvalidRound. Corrupted upheld R5 pair → nothing to reconstruct, so R6 is an extra record (InvalidRound). Reshare B_0 byte →MalformedDeal, D [2,3]. R3 value byte →InvalidAnswer. Complaint version byte →MissingAnswer. One byte over 4 MiB →LimitExceededbefore any signature.Error names chosen as defaults (not from SPEC, plan §5 or vector reason fields)
Plan §5 names the error types but no variants. The defaults below follow Naomi's 2026-10-30 rulings and sit in one table (
DEFAULT_ERROR,ceremony.ts):InvalidSignature: owner or member signature fails strict RFC 8032, or the DID has no key.InvalidRound: closure non-canonical, ordered-list mismatch, envelope names another ceremony/round. (SPEC namesInvalidRoundfor the closure's ceremony/round/previous-hash binding and for record counts; the rest is a default.)InvalidIndex: envelope cohort/index does not resolve in its signed cohort (including any cohort-2 envelope in genesis, and unknown cohort bytes).InvalidCeremony: ceremony owner/network differs from the anchor; genesis with a current digest or non-zero counters; successor epoch ≠ checked current + 1 or re-key counter changed. (Stale or absent current digest is now SPEC-namedInvalidCeremony.)InvalidCertificate: current certificate owner/network differs from the anchor.ContextMismatch: reshare B′_0 ≠ current mpk.InvalidEncoding: envelope over 64 KiB, any signature over 512 bytes; certificate commitment[0] ≠ mpk, genesis t outside 2..=16, and the §3.9 field-combination rules (including the new genesis_t = t, successor epoch/rekey and re-key mpk/rekey rules). A genesis certificate over budget reports the SPEC-namedUnsupportedFaultBudget.SPEC clarifications proposed
Fix the check order inside a closed round.Settled: codes and their precedence are informative (SPEC "Verifier conformance"). This checker's order, for reference: closure ceremony/round/previous → owner closure signature → each envelope (decode, ceremony/round, signer resolution, signature) → ordered-list commitment.InsufficientQualified,InsufficientRecovery) must be the last record; extra records areInvalidRound(Naomi ruling).zip215: false, which rejects non-canonical A/R encodings, S ≥ L and (observed) small-order public keys.Sealed dealing decoded by layout only.Superseded: SPEC now requires a ciphertext of at least 16 bytes.A stale current digest has two names.Settled:InvalidCeremony(SPEC S0.4 now says so; the checker follows).dkg_verify_transcripthere returnsInvalidCeremonyfor it.Verification
bun install --frozen-lockfile && bun run check: all tests,tsc --noEmit, and the real CLI over the three committed documents pass.≥ t→> t; R3 index bound removed; R6 record-count rule removed; R5i ≠ jremoved; DKG rules 5–8 and reshare rules 4–7 reordered pairwise; reshare B_0 check removed; R1-order selection removed. Checks:>→≥on the 4 MiB bound; ZIP-215 enabled; certificate constant/top/public-share/combination/genesis-t/option-marker checks removed; envelope, closure and certificate signature caps removed; directory contiguity removed; genesis re-key-counter check removed. The "lowest t R6 senders" mutation survives because it is unobservable (see 8).genesis_t = tremoved; genesis budget removed; successorepoch ≥ 1removed;rekey ≤ epochremoved; re-keympkchange removed; re-keyrekey ≥ 1removed; re-keygenesis_t = tremoved; re-key budget removed; stale/absent digest back toContextMismatch. New tests: 0- and 15-byte ciphertexts exclude the dealer and change QUAL (DKG) or D (reshare); a 16-byte tag-only ciphertext is accepted; a re-key with t=2, n=3, genesis_t=3 is rejected; a 3-of-4 re-key isUnsupportedFaultBudget.ContextMismatchtoInvalidCeremonyper ruling 4.Internal review (builder's subagent)
This is an internal check, not the independent review; Naomi has seated a separate independent Opus reviewer for this PR. A fresh-context Opus subagent read SPEC and the checker line by line. It found no P0. Its four P1 findings were all test gaps: rule precedence, the R5
i ≠ jrule, untested §3.9 certificate rules and caps, and genesis counter rules. All four are fixed in the follow-up commit, with each reported surviving mutant now killed. Its P2 items are applied: every default is inDEFAULT_ERROR, the README wording is corrected, and clarifications 4 and 9–10 are added.Subagent clean-room disclosure (accepted by Naomi, 2026-10-30): one subagent grep over
tinycloud-thresholdfor error names also printed about 40 lines of Rust error-variant snippets fromsrc/*.rs. The subagent opened no Rust file, history or diff, made no finding that relies on those lines, and declined to rule on directory-rule error names because of them. The builder (author of this PR) did not see those lines; no code here depends on them.The independent reviewer (
abf01a5d) approvedee0d4d3d, requested one P2 change at3e61e74c(re-key certificate rules), and approved6d1883aewith no remaining P1/P2/P3 findings. The head is frozen at6d1883ae; retarget tomainonly after #492 and #493 merge.Provenance log
dkg-genesis.json,reshare.json,cert-core.jsonseeds)zip215: falseAPIDetails: TC-2223