Skip to main content

FROST and DKG

To support multisig-controlled shielded transactions, Bermuda uses threshold Schnorr signing under a single group public key: multiple participants hold independent key shares, and any threshold-sized subset can jointly produce a standard Schnorr signature.

FROST, short for Flexible Round-Optimized Schnorr Threshold signatures, is the signing protocol used for this model. Bermuda supports two setup paths for the resulting shares: dealer-based key generation and distributed key generation (DKG).

For background, see the original FROST paper: Komlo and Goldberg, "FROST: Flexible Round-Optimized Schnorr Threshold Signatures".

Threshold key material

Let GG be the Grumpkin generator and let qq be the Grumpkin scalar field order.

A threshold shared secret is defined by a degree-(t1)(t-1) polynomial

f(X)=a0+a1X++at1Xt1(modq)f(X) = a_0 + a_1 X + \cdots + a_{t-1} X^{t-1} \pmod q

whose constant term

x=f(0)=a0x = f(0) = a_0

is the group secret, with corresponding group public key

X=xG=a0G.X = xG = a_0 G.

Each participant is assigned a non-zero identifier iFqi \in \mathbb{F}_q and receives the secret share

si=f(i).s_i = f(i).

To make these shares publicly verifiable, the polynomial coefficients are committed to as

Φk=akG\Phi_k = a_k G

for 0k<t0 \le k < t.

A share sis_i is valid if it satisfies

siG=?k=0t1ikΦk.s_i G \stackrel{?}{=} \sum_{k=0}^{t-1} i^k \Phi_k.

This is the verifiable secret sharing (VSS) relation used in both dealer-based setup and DKG share verification in the SDK.

Two setup models

Bermuda supports two setup models for arriving at the same threshold key material:

  • a dealer samples the polynomial and distributes the shares
  • the participants jointly generate the polynomial material through DKG

In both cases, the output is the same shape:

  • one group public key
  • one long-lived secret share per participant
  • public commitments that let recipients verify shares

Those shares can then be used with FROST to produce a standard Schnorr signature.

Dealer-based key generation

Dealer-based key generation is the simplest setup path in the SDK.

The dealer:

  1. samples the polynomial f(X)f(X)
  2. evaluates si=f(i)s_i = f(i) for each participant id
  3. computes the coefficient commitments Φk=akG\Phi_k = a_k G
  4. returns one key package per participant together with the full VSS commitment

The group public key is the first coefficient commitment:

X=Φ0.X = \Phi_0.

Each participant can verify its received share against the VSS relation before accepting it.

Distributed key generation (DKG)

Dealer-based setup is simple, but it assumes one trusted party sampled the secret polynomial correctly and did not retain the full secret material. DKG removes that assumption by having every participant contribute its own polynomial and secret shares, so that no single participant ever constructs the full group secret on its own.

Round 1

Each participant \ell samples its own degree-(t1)(t-1) polynomial

f(X)=a,0+a,1X++a,t1Xt1(modq)f_{\ell}(X) = a_{\ell,0} + a_{\ell,1} X + \cdots + a_{\ell,t-1} X^{t-1} \pmod q

and publishes the coefficient commitments

Φ,k=a,kG\Phi_{\ell,k} = a_{\ell,k} G

for 0k<t0 \le k < t.

The participant also proves knowledge of the constant coefficient a,0a_{\ell,0} behind Φ,0\Phi_{\ell,0}.

The SDK uses a Schnorr-style proof of knowledge:

R=kGR_{\ell} = k_{\ell} G c=Hdkg(,Φ,0,R)c_{\ell} = H_{\mathrm{dkg}}(\ell, \Phi_{\ell,0}, R_{\ell}) μ=k+a,0c(modq)\mu_{\ell} = k_{\ell} + a_{\ell,0} c_{\ell} \pmod q

The resulting proof is the pair

σ=(R,μ)\sigma_{\ell} = (R_{\ell}, \mu_{\ell})

Verification checks the equivalent relation

μG=?R+cΦ,0\mu_{\ell} G \stackrel{?}{=} R_{\ell} + c_{\ell} \Phi_{\ell,0}

This prevents a participant from publishing a first coefficient commitment without knowing its discrete log.

Round 2

After all round-1 packages have been collected and verified, participant \ell evaluates its local polynomial at every participant id ii and privately sends

si=f(i)s_{\ell \to i} = f_{\ell}(i)

Recipient ii verifies each incoming share against sender \ell's round-1 commitments:

siG=?k=0t1ikΦ,ks_{\ell \to i} G \stackrel{?}{=} \sum_{k=0}^{t-1} i^k \Phi_{\ell,k}

If a share fails this relation, the SDK rejects it.

Final share derivation

After recipient ii has accepted all incoming round-2 shares, it computes its long-lived threshold share as

si==1nsi(modq)s_i = \sum_{\ell=1}^{n} s_{\ell \to i} \pmod q

This is exactly the evaluation of the aggregate polynomial

F(X)==1nf(X)F(X) = \sum_{\ell=1}^{n} f_{\ell}(X)

at X=iX = i.

Conceptually, the resulting group secret is

x=F(0)==1na,0x = F(0) = \sum_{\ell=1}^{n} a_{\ell,0}

but it is never explicitly reconstructed during the protocol.

and the group public key is obtained without reconstructing xx:

X=xG==1nΦ,0X = xG = \sum_{\ell=1}^{n} \Phi_{\ell,0}

This is how the SDK finalizes DKG: it sums the constant-term commitments for the public key and the verified incoming shares for the participant's private share.

FROST signing

Once either setup flow has produced the long-lived shares {si}\{s_i\} and the group public key XX, Bermuda uses FROST to sign.

Let SS be the active signer set for a message mm, where St|S| \ge t.

Each signer iSi \in S holds its long-lived share sis_i and samples two fresh non-zero nonces:

di,ei$Fqd_i, e_i \xleftarrow{\$} \mathbb{F}_q^{*}

with public nonce commitments

Di=diGD_i = d_i G

and

Ei=eiG.E_i = e_i G.

The coordinator constructs a canonical signing package by sorting the signer commitments by participant id. This canonical ordering matters because all signers must derive the same transcript.

For each signer, Bermuda derives a binding factor

ρi=Hbind(m,X,{(j,Dj,Ej)}jS,i)\rho_i = H_{\mathrm{bind}}(m, X, \{(j, D_j, E_j)\}_{j \in S}, i)

where the implementation hashes:

  • a dedicated FROST binding-factor domain separator
  • the message field element
  • the group public key coordinates
  • the full canonical commitment list
  • the participant id ii

Each signer's effective commitment is then

Ri=Di+ρiEiR_i = D_i + \rho_i E_i

and the aggregate commitment is

R=iSRi.R = \sum_{i \in S} R_i.

The Schnorr challenge is

c=Hsig(R,X,m),c = H_{\mathrm{sig}}(R, X, m),

using the FROST signature domain separator.

In a threshold signature, any signer set of size at least tt can sign. To make that signer set produce a signature under the same group public key, each signer weights its share by the Lagrange coefficient at zero:

λi=jSjijij(modq)\lambda_i = \prod_{\substack{j \in S \\ j \ne i}} \frac{-j}{i - j} \pmod q

Signer ii then returns the partial signature

zi=di+ρiei+λicsi(modq).z_i = d_i + \rho_i e_i + \lambda_i c s_i \pmod q.

The aggregator sums the responses

z=iSzi(modq)z = \sum_{i \in S} z_i \pmod q

and outputs the final group signature

(R,z),(R, z),

which verifies exactly like a standard Schnorr signature under the group public key XX.