feat(frost): conclude the signing done check on the t-subset (7.3 t-of-included PR3/3)#4094
Merged
mswilkison merged 1 commit intoJun 19, 2026
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
c0202f8 to
8f01156
Compare
…uorum (7.3 t-of-included PR3/3) Under RFC-21 Phase 7.3 t-of-included finalize, an interactive signing attempt is signed by the first t responsive committers of an (optionally) oversized included set; the non-subset and offline members never broadcast a signing done check, so the outer signingDoneCheck - which required a confirmation from EVERY attempt member - would hang an otherwise-successful attempt to its timeout and force a needless retry. Conclude the done check on a deterministic threshold quorum instead, keeping the legacy (non-oversized) path byte-for-byte unchanged: - non-oversized (included == honestThreshold; today's selector output and the whole coarse path): the legacy all-members rule is UNCHANGED - wait for every attempt member, require all signatures equal, return max(endBlock). - oversized (included > honestThreshold): bucket done checks by signature and conclude once a bucket holds >= honestThreshold distinct senders (the minimum that proves a valid threshold signature). Minority buckets (divergent or adversarial signatures) are IGNORED, never fatal, so one bad done message cannot fracture the group. The end block is the DETERMINISTIC attempt timeout block, not a network-order-dependent max over done messages. The deterministic end block is the crux: batch scheduling derives the next signature's start as signingStartBlock = prev endBlock + interlude, so a per-node max over a network-order-dependent subset would desync the batch. Returning attemptTimeoutBlock (which every honest node computes identically) fixes it. With honest majority (t > groupSize/2) at most one signature bucket can reach t - even under coordinator equivocation - so the quorum is unique and no body-hash / proto change is needed; the >1-quorum branch is unreachable and intentionally non-fatal. Design locked via a Codex+Gemini consult after the initial first-t-arrivals approach was shown to be cross-node non-deterministic (it fed an order-dependent end block into batch scheduling). Tests: legacy done-check tests unchanged; added oversized conclude-on-quorum (with a deterministic end block), minority-divergent-ignored, and split-below-quorum-times-out. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8f01156 to
0671d99
Compare
79ea845
into
feat/frost-schnorr-migration-scaffold
15 of 16 checks passed
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
Completes RFC-21 Phase 7.3 t-of-included finalize. With PR2 (#4093) an interactive signing attempt finalizes over the first
tresponsive committers of an (optionally) oversized included set. The non-subset and offline members never broadcast a signing done check, so the outersigningDoneCheck— which required a confirmation from every attempt member — would hang an otherwise-successful attempt to its timeout and force a needless retry.This concludes the done check on a deterministic threshold quorum, keeping the legacy path byte-for-byte unchanged.
Design (locked via a Codex + Gemini consult)
My first cut completed on "the first
tarrivals," which is network-order-dependent: the resultinglatestEndBlock(a per-node max over a network-order-dependent subset) differs across honest nodes, and that value feeds batch scheduling (signBatch:signingStartBlock = prev endBlock + interlude) → the batch desyncs. The consult locked this design:included == honestThreshold; today's selector output and the whole coarse path): the legacy all-members rule is UNCHANGED — wait for every attempt member, require all signatures equal, returnmax(endBlock).included > honestThreshold): bucket done checks by signature, conclude once a bucket holds>= honestThresholddistinct senders (the minimum that proves a valid threshold signature). Minority buckets (divergent / adversarial signatures) are ignored, never fatal — one bad done message can't fracture the group. The end block is the deterministicattemptTimeoutBlock(every honest node computes it identically), not a max over done messages.With honest majority (
t > groupSize/2) at most one signature bucket can reacht— even under coordinator equivocation (two disjointt-subsets can't coexist when2t > n) — so the quorum is unique. That means no body-hash / proto change is needed (bucket by the existing signature field), and nosignBatchchange (the oversized path feedsattemptTimeoutBlockthrough the existing return). The>1-quorum branch is unreachable and intentionally non-fatal (no noisy post-success failure).Inert until oversizing
included == honestThresholdtoday, so the legacy branch is taken and behavior is identical to before; the quorum path only activates once selection oversizes the set (MacLane's policy knob).Tests (
signing_done_test.go)TestSigningDoneCheck{,_MissingConfirmation,_AnotherSignature}— unchanged, still green (they use an attempt-member set of sizehonestThreshold).TestSigningDoneCheck_ThresholdSubsetConcludes— oversized; reporters carry different end blocks but the result is the deterministicattemptTimeoutBlock.TestSigningDoneCheck_OversizedIgnoresMinorityDivergentSignature—tcorrect + 1 divergent → concludes on the quorum, ignores the minority (no error).TestSigningDoneCheck_OversizedSplitBelowQuorumTimesOut— 2+2 split, no bucket reachest→ times out.Validated: build+vet across default /
frost_roast_retry/frost_native frost_roast_retry/ CGO; the done-check + signing-loop + roast-transition tests with-race; gofmt clean. ThesigningDoneCheckStrategyinterface +mockSigningDoneCheckare untouched (only the constructor signature changed).🤖 Generated with Claude Code