Skip to content

feat(frost/roast): Phase 7.2b-2 share-submission envelope (wire foundation)#4058

Merged
mswilkison merged 2 commits into
feat/frost-schnorr-migration-scaffoldfrom
feat/phase-7-2b-2-share-submission-2026-06-14
Jun 14, 2026
Merged

feat(frost/roast): Phase 7.2b-2 share-submission envelope (wire foundation)#4058
mswilkison merged 2 commits into
feat/frost-schnorr-migration-scaffoldfrom
feat/phase-7-2b-2-share-submission-2026-06-14

Conversation

@mswilkison

Copy link
Copy Markdown
Contributor

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

Testing

gofmt/vet/build clean; full pkg/frost/roast suite passes under go 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 -race concurrency 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

…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>
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 514f79e2-b91d-41ea-b3d8-54f31762df97

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/phase-7-2b-2-share-submission-2026-06-14

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…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>
@mswilkison mswilkison merged commit c481826 into feat/frost-schnorr-migration-scaffold Jun 14, 2026
15 checks passed
@mswilkison mswilkison deleted the feat/phase-7-2b-2-share-submission-2026-06-14 branch June 14, 2026 19:04
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>
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