frost_bluepallas/keys.rs
1//! This module contains utilities for FROST key management using the BluePallas curve
2
3use alloc::collections::BTreeMap;
4
5use frost_core::{self as frost};
6use rand_core::{CryptoRng, RngCore};
7
8use crate::{BluePallas, ChallengeMessage, Error, Identifier, SigningKey};
9
10pub type IdentifierList<'a, M> = frost::keys::IdentifierList<'a, BluePallas<M>>;
11
12/// Secret and public key material generated by a dealer performing
13/// [`generate_with_dealer`].
14///
15/// # Security
16///
17/// To derive a FROST(Pallas, Poseidon) keypair, the receiver of the [`SecretShare`] *must* call
18/// .into(), which under the hood also performs validation.
19pub type SecretShare<M> = frost::keys::SecretShare<BluePallas<M>>;
20
21/// A secret scalar value representing a signer's share of the group secret.
22pub type SigningShare<M> = frost::keys::SigningShare<BluePallas<M>>;
23
24/// A public group element that represents a single signer's public verification share.
25pub type VerifyingShare<M> = frost::keys::VerifyingShare<BluePallas<M>>;
26
27/// A FROST(Pallas, Poseidon) keypair, which can be generated either by a trusted dealer or using
28/// a DKG.
29///
30/// When using a central dealer, [`SecretShare`]s are distributed to
31/// participants, who then perform verification, before deriving
32/// [`KeyPackage`]s, which they store to later use during signing.
33pub type KeyPackage<M> = frost::keys::KeyPackage<BluePallas<M>>;
34
35/// Public data that contains all the signers' public keys as well as the
36/// group public key.
37///
38/// Used for verification purposes before publishing a signature.
39pub type PublicKeyPackage<M> = frost::keys::PublicKeyPackage<BluePallas<M>>;
40
41/// Contains the commitments to the coefficients for our secret polynomial _f_,
42/// used to generate participants' key shares.
43///
44/// [`VerifiableSecretSharingCommitment`] contains a set of commitments to the coefficients (which
45/// themselves are scalars) for a secret polynomial f, where f is used to
46/// generate each ith participant's key share f(i). Participants use this set of
47/// commitments to perform verifiable secret sharing.
48///
49/// Note that participants MUST be assured that they have the *same*
50/// [`VerifiableSecretSharingCommitment`], either by performing pairwise comparison, or by using
51/// some agreed-upon public location for publication, where each participant can
52/// ensure that they received the correct (and same) value.
53pub type VerifiableSecretSharingCommitment<M> =
54 frost::keys::VerifiableSecretSharingCommitment<BluePallas<M>>;
55type DealerOutput<M> = (BTreeMap<Identifier<M>, SecretShare<M>>, PublicKeyPackage<M>);
56
57/// Generate a random keypair and split into FROST keyshares.
58pub fn generate_with_dealer<M, RNG: RngCore + CryptoRng>(
59 max_signers: u16,
60 min_signers: u16,
61 identifiers: IdentifierList<'_, M>,
62 mut rng: RNG,
63) -> Result<DealerOutput<M>, Error<M>>
64where
65 M: ChallengeMessage,
66{
67 frost::keys::generate_with_dealer(max_signers, min_signers, identifiers, &mut rng)
68}
69
70/// Splits an existing key into FROST shares.
71///
72/// This is identical to [`generate_with_dealer`] but receives an existing key
73/// instead of generating a fresh one. This is useful in scenarios where
74/// the key needs to be generated externally or must be derived from e.g. a
75/// seed phrase.
76pub fn split<M, R: RngCore + CryptoRng>(
77 key: &SigningKey<M>,
78 max_signers: u16,
79 min_signers: u16,
80 identifiers: IdentifierList<'_, M>,
81 rng: &mut R,
82) -> Result<DealerOutput<M>, Error<M>>
83where
84 M: ChallengeMessage,
85{
86 frost::keys::split(key, max_signers, min_signers, identifiers, rng)
87}
88
89/// Distributed Key Generation (DKG) protocol types and functions.
90pub mod dkg {
91 use super::*;
92 type DkgPart2Output<M> = (
93 round2::SecretPackage<M>,
94 BTreeMap<Identifier<M>, round2::Package<M>>,
95 );
96
97 /// DKG Round 1 structures.
98 pub mod round1 {
99 use super::*;
100
101 /// The secret package that must be kept in memory by the participant
102 /// between the first and second parts of the DKG protocol (round 1).
103 ///
104 /// # Security
105 ///
106 /// This package MUST NOT be sent to other participants!
107 pub type SecretPackage<M> = frost::keys::dkg::round1::SecretPackage<BluePallas<M>>;
108
109 /// The package that must be broadcast by each participant to all other participants
110 /// between the first and second parts of the DKG protocol (round 1).
111 pub type Package<M> = frost::keys::dkg::round1::Package<BluePallas<M>>;
112 }
113
114 /// DKG Round 2 structures.
115 pub mod round2 {
116 use super::*;
117
118 /// The secret package that must be kept in memory by the participant
119 /// between the second and third parts of the DKG protocol (round 2).
120 ///
121 /// # Security
122 ///
123 /// This package MUST NOT be sent to other participants!
124 pub type SecretPackage<M> = frost::keys::dkg::round2::SecretPackage<BluePallas<M>>;
125
126 /// A package that must be sent by each participant to some other participants
127 /// in Round 2 of the DKG protocol. Note that there is one specific package
128 /// for each specific recipient, in contrast to Round 1.
129 ///
130 /// # Security
131 ///
132 /// The package must be sent on an *confidential* and *authenticated* channel.
133 pub type Package<M> = frost::keys::dkg::round2::Package<BluePallas<M>>;
134 }
135
136 /// Performs the first part of the distributed key generation protocol
137 /// for the given participant.
138 ///
139 /// It returns the [`round1::SecretPackage`] that must be kept in memory
140 /// by the participant for the other steps, and the [`round1::Package`] that
141 /// must be sent to other participants.
142 pub fn part1<M, R: RngCore + CryptoRng>(
143 identifier: Identifier<M>,
144 max_signers: u16,
145 min_signers: u16,
146 mut rng: R,
147 ) -> Result<(round1::SecretPackage<M>, round1::Package<M>), Error<M>>
148 where
149 M: ChallengeMessage,
150 {
151 frost::keys::dkg::part1(identifier, max_signers, min_signers, &mut rng)
152 }
153
154 /// Performs the second part of the distributed key generation protocol
155 /// for the participant holding the given [`round1::SecretPackage`],
156 /// given the received [`round1::Package`]s received from the other participants.
157 ///
158 /// It returns the [`round2::SecretPackage`] that must be kept in memory
159 /// by the participant for the final step, and the [`round2::Package`]s that
160 /// must be sent to other participants.
161 pub fn part2<M>(
162 secret_package: round1::SecretPackage<M>,
163 round1_packages: &BTreeMap<Identifier<M>, round1::Package<M>>,
164 ) -> Result<DkgPart2Output<M>, Error<M>>
165 where
166 M: ChallengeMessage,
167 {
168 frost::keys::dkg::part2(secret_package, round1_packages)
169 }
170
171 /// Performs the third and final part of the distributed key generation protocol
172 /// for the participant holding the given [`round2::SecretPackage`],
173 /// given the received [`round1::Package`]s and [`round2::Package`]s received from
174 /// the other participants.
175 ///
176 /// It returns the [`KeyPackage`] that has the long-lived key share for the
177 /// participant, and the [`PublicKeyPackage`]s that has public information
178 /// about all participants; both of which are required to compute FROST
179 /// signatures.
180 pub fn part3<M>(
181 round2_secret_package: &round2::SecretPackage<M>,
182 round1_packages: &BTreeMap<Identifier<M>, round1::Package<M>>,
183 round2_packages: &BTreeMap<Identifier<M>, round2::Package<M>>,
184 ) -> Result<(KeyPackage<M>, PublicKeyPackage<M>), Error<M>>
185 where
186 M: ChallengeMessage,
187 {
188 let (key_package, public_key_package) =
189 frost::keys::dkg::part3(round2_secret_package, round1_packages, round2_packages)?;
190 Ok((key_package, public_key_package))
191 }
192}