Skip to content

feat(threshold): add genesis DKG over owner-closed rounds; Details: TC-2220 - #492

Draft
samgbafa wants to merge 8 commits into
mainfrom
skgbafa/tc-2220-threshold-dkg
Draft

samgbafa wants to merge 8 commits into
mainfrom
skgbafa/tc-2220-threshold-dkg

Conversation

@samgbafa

@samgbafa samgbafa commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Adds the S0.3 genesis distributed key generation to tinycloud-threshold: GJKR New-DKG over owner-closed, member-signed rounds, with sealed dealings, complaints and answers, Feldman extraction, a common R5 round and R6 reconstruction, plus dkg_verify_transcript, which recomputes the outcome from the raw signed round records. The crate remains an unwired workspace member.

Base: main at d7f88e231179ea525462a8f1582729d55735d581. Head: a672197481f5ef9e1efd662411188cba8cbf6bdb.

What it does

  • dkg_start accepts only an owner-authorized genesis ceremony within the genesis parameter budget (3-of-4 is refused with UnsupportedFaultBudget). It checks the member index and that the supplied recipient key matches that member's directory key before drawing any randomness or producing coefficients or dealings.
  • Consume-self member states DkgDealt → DkgComplained → DkgAnswered → DkgExtracting → DkgAwaitingBarrier → AfterBarrier::{Finished, Reconstruct(DkgReconstructing, R6)}. Every transition first requires the closed round's ceremony digest, round number and previous transcript link to match the state. The initial link is TH("TC-THRESHOLD-V1-DKG-START", authorized_ceremony_digest) from dkg_initial_transcript.
  • QUAL is fixed after closed R3. A valid required answer replaces the receiver's private pair. Missing or malformed R3 disqualifies a dealer only when required answers are absent; an invalid answer disqualifies its dealer whether or not it was required; a valid unsolicited answer is ignored; a malformed R2 supplies no complaints. Faulted dealers are recovered from R6 and stay in QUAL. Typed errors cover too few qualified dealers, too few reconstruction values and a member without a private value from a qualified dealer.
  • dkg_verify_transcript takes the raw signed rounds (DkgTranscript), bounds the whole transcript to 4 MiB before checking signatures, and applies the same public rules as the members. It trusts no supplied outcome fields.
  • SPEC.md gains the S0.3 genesis DKG appendix (layouts, rule order and lifecycle); README.md is updated. vectors/v1/dkg-genesis.json holds six fixed-seed transcripts with recomputed outcomes or errors, regenerated and replayed byte for byte by a test.

Round equivocation compares conflicting authenticated message content from the same sender; a different signature encoding alone is not equivocation. No-abort liveness scenarios use a trusted relay that delivers every honest message. Dropped-message and equivocating-relay cases are separate failure/activation scenarios; this implementation does not provide reliable broadcast.

Commits and ownership

  • b8d52580 test: recipient public-key derivation (seal module owner).
  • 073412ba test: DKG module tests, signed owner relay scenarios, DKG checkpoint and module wiring (tests-only; no implementation).
  • 23849d71 feat: crate-private CeremonyHpkeSecretKey::public_key() (seal module owner).
  • fd9073b8 feat: DKG implementation; three typed error variants; removal of five #[cfg(test)] gates on existing crate-private helpers (Scalar::from_bytes, Scalar::to_bytes, Scalar::add, hash_g2, poly::evaluate) with no signature or body change; removal of the seal module's dead-code allowance.
  • 4f090b94 test: in this PR's own new test local_recipient_key_and_context_are_checked_before_any_randomness (src/dkg_relay.rs, added in 073412ba), the seed passed to the existing reshare-ceremony test helper changes from 12 to 11 so the reshare keeps the genesis master key and the ceremony builds; the test's assertions are unchanged. No test or fixture that existed before this PR is edited.
  • 705ff4d0 fix: clippy corrections (an AfterBarrier size allowance with reason; test type alias and slice).
  • a6721974 docs: SPEC appendix, README, DKG vectors.

Review notes

  • The five helpers listed above now run in non-test builds on secret values. Scalar::from_bytes refuses non-canonical encodings (curve.rs test scalar_canonical_boundaries_and_modular_arithmetic; DKG decoder tests assert InvalidScalar for non-canonical pair scalars). Scalar clears its storage on drop (curve.rs impl Zeroize/Drop for Scalar); DKG polynomial coefficients, received pairs and the candidate sum are held as Scalar values inside the consumed states.
  • The public_key() seam derives through the HPKE library's public API and is exercised by secret_public_key_matches_generated_recipient and local_recipient_key_and_context_are_checked_before_any_randomness.
  • HPKE library-internal key and context lifecycle remains as recorded in SPEC §3.11.

Checks

Run locally at 705ff4d0 with the pinned 1.97.1 toolchain, isolated homes and target, two jobs (a6721974 changes only SPEC, README and the generated vector file):

  • cargo test --locked -p tinycloud-threshold --release --no-run: ok.
  • TC_THRESHOLD_REGEN_VECTORS=1 cargo test --locked -p tinycloud-threshold --release dkg_vectors_regenerate_byte_for_byte_and_replay: ok.
  • PROPTEST_CASES=1024 cargo test --locked -p tinycloud-threshold --release: 118 passed, 0 failed.
    • Clarification: PROPTEST_CASES sets the default case count only. within_budget_fault_patterns_finish_with_identical_outcomes sets its own ProptestConfig::with_cases(12), so that property ran 12 fault-pattern ceremonies in this run, not 1024.
  • cargo test --locked -p tinycloud-threshold --release checkpoint_2of3 -- --nocapture: the existing nine outcomes and five DKG outcomes printed.
  • cargo clippy --locked -p tinycloud-threshold --all-targets -- -D warnings: ok.
  • cargo fmt -p tinycloud-threshold -- --check: ok.
  • A separate program built against the normal release library ran a signed 2-of-3 DKG with one reconstructed dealer, verified the transcript, bound the candidates to a verified certificate, and combined, derived and unwrapped a data key for all three pairs; it also showed ContextMismatch for a recipient key outside the directory and transcript rejection for an altered member signature.

Named DKG tests include: genuine_2of3_completes_with_every_member_and_the_verifier_agreeing, genesis_3of4_is_refused_before_any_dealing, three_of_five_with_two_faulty_members_recovers_the_committed_master_key, one_recipient_bad_private_value_is_replaced_by_a_valid_answer, malformed_r2_supplies_no_complaints, conflicting_r2_content_is_equivocation_even_when_malformed, different_signature_encoding_is_not_equivocation, missing_r3_disqualifies_only_with_required_answers, malformed_r3_disqualifies_only_with_required_answers, invalid_unsolicited_answer_disqualifies_its_dealer, valid_unsolicited_answer_is_ignored, selective_r4_reaches_the_common_barrier_and_is_reconstructed, bad_missing_and_malformed_r4_are_extraction_faults, r1_equivocation_disqualifies_but_r4_equivocation_reconstructs, every_member_sends_r5_and_an_empty_barrier_finishes, missing_or_malformed_r5_counts_as_an_empty_list, corrupt_dealer_withholding_its_r6_is_recovered_and_kept, insufficient_valid_r6_values_abort_with_a_typed_error, transitions_refuse_other_ceremonies_rounds_and_histories, closed_rounds_reject_wrong_signers_cohorts_and_signatures, transcript_bound_of_4_mib_precedes_verification, within_budget_fault_patterns_finish_with_identical_outcomes, dkg_start_label_is_distinct_from_and_not_a_prefix_of_every_frozen_tag, checkpoint_2of3_dkg.

Clean room

Clean-room statement. tinycloud-threshold is written from published papers and standards only: Shamir 1979; Feldman 1987; Pedersen 1991; Gennaro–Jarecki–Krawczyk–Rabin 1999/2007; Boneh–Franklin 2001/2003; Fujisaki–Okamoto 1999; Desmedt–Jajodia 1997; Wong–Wang–Wing 2002; Herzberg–Jarecki–Krawczyk–Yung 1995; CHURP (ePrint 2019/017); vetKeys (ePrint 2023/616); RFC 9380; RFC 9180; the IRTF pairing-friendly-curves draft; and TinyCloud's own design and plan. No source code, tests, issues or other material from TACo, nucypher, nucypher-core, ferveo, umbral or taco-web (GPL-3.0/AGPL-3.0) was opened, fetched, cloned, searched or used. Dependencies are permissively licensed and listed in the PR. Each PR keeps a provenance log of the sources consulted.

Dependencies: no change (existing blst, sha2, zeroize, subtle, rand_core, thiserror, hpke 0.12 with x25519; development ed25519-dalek, proptest, rand_chacha, serde, serde_json, hex).

Provenance log

  • Gennaro–Jarecki–Krawczyk–Rabin 1999/2007 (New-DKG): round structure, complaints, QUAL, extraction and reconstruction.
  • Pedersen 1991: commitments a·g2 + b·h and share checks. Feldman 1987: extraction vectors a·g2. Shamir 1979: polynomial evaluation and interpolation.
  • RFC 9180: base-mode sealing through the existing crate seal module. RFC 9380: the existing frozen hash-to-G2 for h.
  • TinyCloud design and plan, the crate's SPEC.md and existing crate APIs.

Details: TC-2220

Update: test additions at 82ab38c

One tests-only commit on a6721974, changing only src/dkg_relay.rs:

  • transitions_refuse_a_foreign_ceremony_closure_on_this_history: a closed R1 from another authorized ceremony that names this ceremony's initial link is refused with InvalidRound.
  • r2_naming_a_dealer_outside_the_cohort_supplies_no_complaints and r3_naming_a_recipient_outside_the_cohort_is_malformed: the R2 and R3 index rules for members outside the cohort.
  • within_budget_fault_patterns_finish_with_identical_outcomes (12 sampled cases) is replaced by every_within_budget_fault_pattern_finishes_with_identical_outcomes_2of3 and _3of5, which run every behaviour assignment of the in-tree fault model for two fixed seeds: 2 × (15 + 225) = 480 ceremonies. They cover that model only.

Checks at 82ab38cb (pinned 1.97.1, isolated, two jobs): each new test fails by assertion when the rule it covers is removed from a private copy (the ceremony-digest and R2 rules were shown at the previous local commit with identical tests; the R3 rule at this head); full crate suite 122 passed, 0 failed; checkpoint_2of3 printed all outcomes; clippy with -D warnings and cargo fmt -p tinycloud-threshold -- --check passed.

Details: TC-2220

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant