Distributed Key Generation

The diagram below shows the distributed key generation process. Dashed lines represent data being sent through an authenticated and confidential communication channel. Note that the first dashed line requires a broadcast channel

Diagram of Distributed Key Generation, illustrating what is explained in the text

Part 1

To start the DKG, each participant calls dkg::part1() passing its identifier, the desired threshold and total number of participants. (Thus, they need to agree on those parameters via some mechanism which is up to the application.) It returns a round1::SecretPackage and a round1::Package:

use rand::thread_rng;
use std::collections::BTreeMap;

use frost_ristretto255 as frost;

let mut rng = thread_rng();

let max_signers = 5;
let min_signers = 3;

    // Ask the user which identifier they would like to use. You can create
    // an identifier from a non-zero u16 or derive from an arbitrary string.
    // Some fixed examples follow (each participant must choose a different identifier)
    let participant_identifier = Identifier::try_from(7u16)?;
    let participant_identifier = Identifier::derive("alice@example.com".as_bytes())?;

    let (round1_secret_package, round1_package) = frost::keys::dkg::part1(
        &mut rng,


Check the crate documentation for a full working example; keep in mind it's an artificial one since everything runs in the same program.

The round1::SecretPackage must be kept in memory to use in the next round. The round1::Package must be sent to all other participants using a broadcast channel to ensure that all participants receive the same value.


A broadcast channel in this context is not simply broadcasting the value to all participants. It requires running a protocol to ensure that all participants have the same value or that the protocol is aborted. Check the linked Terminology section for more details.

Failure in using a proper broadcast channel will make the key generation insecure.

Part 2

Upon receiving the other participants' round1::Packages, each participant then calls dkg::part2() passing their own previously created round1::SecretPackage and the list of received round1::Packages. It returns a round2::SecretPackage and a BTreeMap mapping other participants's Identifiers to round2::Packages:

    let (round2_secret_package, round2_packages) =
        frost::keys::dkg::part2(round1_secret_package, round1_packages)?;

The round2::SecretPackage must be kept in memory for the next part; the round1::SecretPackage is consumed and is not required anymore.

The round2::Packages must be sent to their respective participants with the given Identifiers, using an authenticated and confidential communication channel.

Part 3

Finally, upon receiving the other participant's round2::Package, the DKG is concluded by calling dkg::part3() passing the same round1::Packages received in Part 2, the round2::Packages just received, and the previously stored round2::SecretPackage for the participant. It returns a KeyPackage, with the participant's secret share, and a PublicKeyPackage containing the group verifying key:

    let (key_package, pubkey_package) = frost::keys::dkg::part3(


All participants will generate the same PublicKeyPackage.