feat(frost/roast): Phase 7.2b-2 share-submission envelope (wire foundation)#4058
Merged
mswilkison merged 2 commits intoJun 14, 2026
Conversation
…ation)
The context-bound, member-authenticated Round2 share submission - the wire
foundation. After a member authenticates a SignedSigningPackage and accepts its
taproot root, it returns its FROST round-2 share bound to that exact package;
this binding is the hard prerequisite for blame adjudication (Phase 7.2b-4).
- share_submission.proto: ShareSubmissionBody{attempt_context_hash,
submitter_id, signing_package_hash, signature_share} + SignedShareSubmission
{body, submitter_signature}; generated pb.go.
- ShareSubmission Go wire type mirroring the signing-package envelope:
bodyBytes() (bare wire body) + SignableBytes() (domain || body) with the
leading-0x00 illegal-tag domain (roast/signed-share-submission/v1);
Marshal/Unmarshal/Validate. Unmarshal bounds the envelope before parse,
rejects an over-cap share field before copy, and primes the signable cache so
concurrent verification is race-free; submitter_id is bounded to
group.MemberIndex.
- Tests: verbatim round-trip, non-canonical survival, domain-separated +
undecodable, prefix-free distinctness vs the signing-package / snapshot /
transition domains, validate-rejects-malformed, marshal-requires-signature,
unmarshal-rejects-oversize-before-copy, and a -race guard. Full
pkg/frost/roast suite passes under -race.
Member sign/retain + network distribution land in the next increment.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
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 |
…are submission (review) Folds the #4058 review (Gemini + Codex): - Gemini P1: add coordinator_id to ShareSubmissionBody so the share explicitly declares which elected coordinator it authorizes - self-describing for blame and non-repudiation, consistent with the other signed bodies - bounded to group.MemberIndex. Regenerated pb.go. - Codex P2: Validate now caps submitter_signature at MaxOperatorSignatureBytes, matching the other ROAST envelopes (an over-cap-but-under-envelope-cap signature previously reached verification/retention). - Gemini P1 (binding): keep signing_package_hash bound to the SignedSigningPackage ENVELOPE (Gemini affirmed - ties the share to the exact branch each member received); documented that this assumes canonical / non-malleable operator signatures, else the Phase 7.2b-4 blame layer must compare package bodies. Tests: round-trip asserts coordinator_id; validate-rejects adds zero / out-of-range coordinator + oversize submitter signature. Full pkg/frost/roast suite passes under -race. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
c481826
into
feat/frost-schnorr-migration-scaffold
15 checks passed
mswilkison
added a commit
that referenced
this pull request
Jun 14, 2026
#4059) ## What Member-side authentication for the Round2 share submission (#4058 added the wire type). This completes the share-submission **sign/authenticate** path; network distribution is the next increment. ## How - **`AuthenticateShareSubmission(verifier, sub, electedCoordinator, liveAttemptContextHash, liveSigningPackageHash)`** — mirrors `AuthenticateSigningPackage`. In order (cheap → expensive): signature present → `coordinator_id == electedCoordinator` → `attempt_context_hash == live` → `signing_package_hash == the distributed package` → signature verifies under the **submitter's** operator key over the domain-tagged body. - The signature is verified over `sub.SubmitterID()`, so a forged `submitter_id` doesn't verify — the signature binds the declared submitter to the actual signer. - Pass = attributable + package-bound, so the caller retains the exact received bytes for the 7.2b-4 equivocation compare; fail = reject without retention. Included-set membership and de-dup remain the caller's responsibility. - **`SignShareSubmission(signer, sub)`** — sets `SubmitterSignature` over `SignableBytes()`. - **`SigningPackage.EnvelopeHash()`** — SHA-256 of the on-wire `SignedSigningPackage` envelope, the value a share commits to in `signing_package_hash`. For a parsed package it hashes the received bytes verbatim, so the submitter and every verifier derive the same binding over the bytes the coordinator distributed. ## Testing `gofmt`/`vet`/`build` clean; full `pkg/frost/roast` suite passes under `go test -race`. New tests: round-trip authenticate + 6 rejections (missing/tampered signature, non-elected coordinator, wrong attempt, wrong package, non-submitter signer), an **end-to-end binding** test (a share bound to a real package's `EnvelopeHash` authenticates; a different package is rejected with `ErrShareSubmissionWrongPackage`), and `EnvelopeHash` wire-stability. ## Next Network distribution of the share submission, then 7.2b-3 (FFI candidate culprits) and 7.2b-4 (equivocation compare + f+1 quorum blame). Carried-forward design item for 7.2b-4: the envelope-hash binding assumes canonical/non-malleable operator signatures (documented on the `signing_package_hash` field) — to be confirmed, or the blame compare made body-aware, before blame lands. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
mswilkison
added a commit
that referenced
this pull request
Jun 14, 2026
… envelope (review) Folds the #4060 review (Codex + Gemini, converged P2s) and reverses the #4058 envelope-hash binding it surfaced as wrong: - False equivocation / fragile binding: the coordinator signs domain||body, NOT the outer envelope. An unsigned re-encoding of the same (body, signature) - which SigningPackage.Unmarshal deliberately preserves - changes an envelope hash without being equivocation, letting a MitM frame an honest coordinator and fragmenting share bindings across members. Switch the package identity to the BODY hash for BOTH the share binding (signing_package_hash) and the collector's equivocation detection. SigningPackage.EnvelopeHash -> BodyHash (sha256 of the signed body, stable across envelope re-encoding); proto + struct docs updated. - Defensive copy: Round2Collector.RecordSigningPackage retains a collector-owned copy of the package envelope, so a caller reusing the SigningPackage (receive-loop Unmarshal) cannot mutate the retained blame evidence. - Also hardens the two-phase lock: re-check the binding's elected coordinator after re-acquiring (prune + re-begin TOCTOU). Tests: body hash stable across an envelope re-encoding; the collector treats a re-encoded same-body package as idempotent (not equivocation) and retains its own copy across caller mutation. Full pkg/frost/roast suite passes under -race. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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
The wire foundation for the context-bound, member-authenticated Round2 share submission — the remaining 7.2b-2 piece. After a member authenticates the elected coordinator's
SignedSigningPackage(#4056) and accepts its taproot root, it returns its FROST round-2 signature share bound to that exact package. That binding is the hard prerequisite for blame adjudication (Phase 7.2b-4): a member's share is provably tied to the specific package bytes it received, so coordinator equivocation across members is detectable and a member's submission is non-repudiable.This PR is the wire type only (mirrors how #4056 landed the signing-package envelope first). Member sign/retain + network distribution come next.
How
share_submission.proto:ShareSubmissionBody{attempt_context_hash, submitter_id, signing_package_hash, signature_share}+SignedShareSubmission{body, submitter_signature}; generatedpb.go.ShareSubmissionGo wire type, structurally identical to the signing-package envelope:bodyBytes()(the bare body that travels) +SignableBytes()(domain ‖ body) with the leading-0x00illegal-tag domainroast/signed-share-submission/v1— consistent with the domain-separation sweep (feat(frost/roast): domain-separate evidence-snapshot + transition-message signatures #4057), so the share signature is non-confusable with the signing-package / snapshot / transition signatures.Marshal/Unmarshal/Validate.Unmarshalbounds the envelope beforeproto.Unmarshal, rejects an over-capsignature_sharebefore copying, and primes the signable-bytes cache so concurrent verification is race-free (incorporating the fix from feat(frost/roast): Phase 7.2b-2 signed signing-package envelope (wire foundation) #4056/feat(frost/roast): domain-separate evidence-snapshot + transition-message signatures #4057 up front).submitter_idis bounded togroup.MemberIndex.Testing
gofmt/vet/buildclean; fullpkg/frost/roastsuite passes undergo test -race. New tests: verbatim round-trip, non-canonical-encoding survival, domain-separated + undecodable-as-protobuf, prefix-free distinctness vs the signing-package / snapshot / transition domains, validate-rejects-malformed (incl. submitter out of member-index range, short hashes, over-cap share), marshal-requires-signature, unmarshal-rejects-oversize-before-copy, and a-raceconcurrency guard.Next
Member-side
AuthenticateShareSubmission(verify under the submitter's operator key + bind to the live attempt + the retained signing-package hash) and the network distribution path — then the equivocation compare + f+1 quorum blame (7.2b-4).🤖 Generated with Claude Code