Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Partial-signing in the committee

audience: ai

This chapter walks what happens inside the signer committee when a SignatureRequest arrives: how the committee admits the request, how each provider produces a partial signature, and how partial sigs converge toward the aggregate. The committee-internal aggregation and the public commit live in aggregation.

The request pipeline

  requester                     committee                       verifier
      │                              │                              │
      │  SignatureRequest            │                              │
      │  (message_digest, scheme)    │                              │
      │─────────────────────────────>│                              │
      │                              │                              │
      │                              │   partial_sig(member i)      │
      │                              │ ◄──────── × committee_size   │
      │                              │                              │
      │                              │   aggregate (off-stream)     │
      │                              │ ──────────────────────────── │
      │                              │                              │
      │         SignatureOutcome     │                              │
      │<─────────────────────────────│                              │
      │  signature_digest,           │                              │
      │  participating_providers,    │                              │
      │  aggregate_attestation_level │                              │
      │                              │                              │
      │                              │   signature_bytes (sealed)   │
      │                              │ ─────────────────────────────>

Request admission

A SignatureRequest is admitted iff:

  1. ACL. The requester’s ticket composes cleanly with the organism’s TicketValidator. The check is the same mosaik primitive every other organism uses; nothing signer-specific.
  2. Scheme match. req.scheme equals Config.scheme. A request for an unsupported scheme is rejected at the stream ACL; it never reaches the committee.
  3. Body size. The side-channel body (delivered alongside the request digest via the operator- declared sealed channel) is ≤ M::MAX_BODY_BYTES.
  4. Deadline. req.deadline_unix_secs is in the future. Late requests are dropped rather than queued past their deadline.

Admission is cheap; the expensive work is the per-member partial-signing round below.

Per-member partial signing

Each committee member, on admitting the request, runs the scheme-specific partial-sign function:

// Inside the provider's TDX guest (for any
// attestation level above Software).
pub fn partial_sign<M: SignableMessage>(
    req:       &SignatureRequest<M>,
    body:      &[u8],                      // from sealed channel
    share_sk:  &SchemeSecretShare,
) -> PartialSignature {
    assert_eq!(UniqueId::hash(body), req.message_digest);
    match req.scheme {
        SignatureScheme::BlsAggregateG1 =>
            bls::partial_sign_g1(body, share_sk),
        SignatureScheme::BlsAggregateG2 =>
            bls::partial_sign_g2(body, share_sk),
        SignatureScheme::FrostSchnorrSecp256k1 =>
            frost_schnorr::partial_sign_secp256k1(
                body, share_sk, &current_nonce_commit(),
            ),
        SignatureScheme::FrostSchnorrEd25519 =>
            frost_schnorr::partial_sign_ed25519(
                body, share_sk, &current_nonce_commit(),
            ),
        SignatureScheme::FrostEcdsaSecp256k1 =>
            frost_ecdsa::partial_sign(
                body, share_sk, &current_nonce_commit(),
            ),
        SignatureScheme::LagrangeBls =>
            lagrange::partial_sign(body, share_sk),
    }
}

Two protocol families, one shape in the book. The member’s result is a PartialSignature committed to a committee-internal stream (not the public surface); aggregation runs off that stream.

Non-interactive vs. interactive schemes

The SignatureScheme::is_non_interactive() predicate separates the two families:

  • Non-interactive — BLS12-381 (both curves) and Shamir-Lagrange. A partial signature is self-contained; the committee aggregator can combine partials at any time in any order once the threshold is reached.

  • Interactive — FROST variants (Schnorr and ECDSA). Partial signatures reference a nonce commit the committee must run one round ahead of time. A missing nonce commit forces a retry, which the committee amortises across a window of upcoming requests.

The organism’s committee ships a nonce-commit rotation loop iff Config.scheme.is_non_interactive() is false. For BLS deployments the loop is absent and the commit bandwidth is zero.

if !Config::<M>::scheme(&cfg).is_non_interactive() {
    spawn_nonce_commit_rotator(&committee_handle);
}

Partial-sig visibility

The committee-internal stream carrying PartialSignatures is not publicly readable. Its ACL admits only bonded committee members. Reasons:

  • Partial-sig forgery window. A partial signature tied to a request id is meaningful only to the aggregator; leaking it early lets a byzantine aggregator claim the signature without running the full threshold. Restricting the audience to current committee members bounds the attack surface.
  • Cross-committee correlation. A provider that serves multiple signer deployments could leak one deployment’s partial sigs into another’s aggregator. The ACL composition pins each deployment’s committee to its own stream.

The publicly readable artefact from this rung is the SignatureOutcome committed in aggregation; partial sigs are committee-internal by design.

Member failure and threshold slack

The threshold is t-of-n; the committee tolerates n − t absent members per request. A request with fewer than t partial sigs at the deadline commits no outcome. The committee emits a RequestTimedOut entry (with the request id and the count achieved) so the requester can resubmit or escalate.

Non-adversarial absence — a committee member restarting, a transient network fault — resolves at the next cadence without operator intervention. Persistent absence triggers a committee rotation (sustainability).

Determinism

The partial-sign function is deterministic given (body, share_sk) for non-interactive schemes and deterministic given (body, share_sk, nonce_commit) for interactive schemes. Two honest providers running the same image against the same share produce the same partial signature. Aggregators treat a non- matching partial from a non-interactive provider as a byzantine fault and exclude the provider from the round.

Forward

Chapter 6 (aggregation) walks what happens after t partial sigs are in hand: the aggregate combine, the SignatureOutcome commit, and the sealed delivery of the signature bytes back to the requester.