Skip to main content

cggmp24/
trusted_dealer.rs

1//! Trusted dealer
2//!
3//! Trusted dealer can be used to generate key shares in one place. Note
4//! that it creates an SPOF/T (single point of failure/trust). Trusted
5//! dealer is mainly intended to be used in tests, or it can be used to
6//! import key into TSS.
7//!
8//! ## Example
9//! Import a key into 3-out-of-5 TSS:
10//! ```rust,no_run
11//! # use rand::rngs::OsRng;
12//! # let mut rng = OsRng;
13//! use cggmp24::{supported_curves::Secp256k1, security_level::SecurityLevel128};
14//! use cggmp24::generic_ec::{SecretScalar, NonZero};
15//!
16//! let secret_key_to_be_imported = NonZero::<SecretScalar<Secp256k1>>::random(&mut rng);
17//!
18//! let key_shares = cggmp24::trusted_dealer::builder::<Secp256k1, SecurityLevel128>(5)
19//!     .set_threshold(Some(3))
20//!     .set_shared_secret_key(secret_key_to_be_imported)
21//!     .generate_shares(&mut rng)?;
22//! # Ok::<_, cggmp24::trusted_dealer::TrustedDealerError>(())
23//! ```
24
25use std::{iter, marker::PhantomData};
26
27use generic_ec::{Curve, NonZero, SecretScalar};
28use rand_core::{CryptoRng, RngCore};
29use thiserror::Error;
30
31use crate::{
32    key_share::{AuxInfo, DirtyAuxInfo, IncompleteKeyShare, InvalidKeyShare, KeyShare, Validate},
33    security_level::SecurityLevel,
34    utils, PregeneratedPrimes,
35};
36
37/// Construct a trusted dealer builder
38///
39/// Takes amount of key shares `n` to be generated
40///
41/// Alias to [`TrustedDealerBuilder::new`]
42pub fn builder<E: Curve, L: SecurityLevel>(n: u16) -> TrustedDealerBuilder<E, L> {
43    TrustedDealerBuilder::new(n)
44}
45
46type CoreBuilder<E> = cggmp24_keygen::key_share::trusted_dealer::TrustedDealerBuilder<E>;
47
48/// Trusted dealer builder
49pub struct TrustedDealerBuilder<E: Curve, L: SecurityLevel> {
50    inner: CoreBuilder<E>,
51    n: u16,
52    pregenerated_primes: Option<Vec<PregeneratedPrimes<L>>>,
53    enable_mulitexp: bool,
54    _ph: PhantomData<L>,
55}
56
57impl<E: Curve, L: SecurityLevel> TrustedDealerBuilder<E, L> {
58    /// Construct a trusted dealer builder
59    ///
60    /// Takes amount of key shares `n` to be generated
61    pub fn new(n: u16) -> Self {
62        TrustedDealerBuilder {
63            inner: CoreBuilder::new(n),
64            n,
65            pregenerated_primes: None,
66            enable_mulitexp: false,
67            _ph: PhantomData,
68        }
69    }
70
71    /// Sets threshold value
72    ///
73    /// If threshold is `Some(_)`, resulting key shares will be generated
74    /// using t-out-of-n VSS scheme. If it's `None`, trusted dealer will
75    /// generate additive key shares in n-out-ouf-n scheme.
76    ///
77    /// Note that setting `t=Some(n)` is not the same as setting `t=None`.
78    /// Both produce n-out-of-n key shares, but `t=Some(n)` mocks threshold
79    /// key generation with `threshold=n`, `t=None` mock non-threshold key
80    /// generation.
81    ///
82    /// Default: `None`
83    pub fn set_threshold(self, t: Option<u16>) -> Self {
84        Self {
85            inner: self.inner.set_threshold(t),
86            ..self
87        }
88    }
89
90    /// Sets shared secret key to be generated
91    ///
92    /// Resulting key shares will share specified secret key.
93    pub fn set_shared_secret_key(self, sk: NonZero<SecretScalar<E>>) -> Self {
94        Self {
95            inner: self.inner.set_shared_secret_key(sk),
96            ..self
97        }
98    }
99
100    /// Sets pregenerated primes to use
101    ///
102    /// `primes` should have exactly `n` pairs of primes.
103    pub fn set_pregenerated_primes(self, primes: Vec<PregeneratedPrimes<L>>) -> Self {
104        Self {
105            pregenerated_primes: Some(primes),
106            ..self
107        }
108    }
109
110    /// Enables multiexp optimization
111    ///
112    /// It takes additional time to precompute multiexp tables, and it makes the key shares larger,
113    /// but it makes the signing and presignature generation protocols faster
114    pub fn enable_multiexp(self, v: bool) -> Self {
115        Self {
116            enable_mulitexp: v,
117            ..self
118        }
119    }
120
121    /// Specifies that the key being generated shall support HD derivation
122    #[cfg(feature = "hd-wallet")]
123    pub fn hd_wallet(self, v: bool) -> Self {
124        Self {
125            inner: self.inner.hd_wallet(v),
126            ..self
127        }
128    }
129
130    /// Generates [`IncompleteKeyShare`]s
131    ///
132    /// Returns error if provided inputs are invalid, or if internal
133    /// error has occurred.
134    pub fn generate_core_shares(
135        self,
136        rng: &mut (impl RngCore + CryptoRng),
137    ) -> Result<Vec<IncompleteKeyShare<E>>, TrustedDealerError> {
138        self.inner
139            .generate_shares(rng)
140            .map_err(Reason::CoreError)
141            .map_err(TrustedDealerError)
142    }
143
144    /// Generates [`KeyShare`]s
145    ///
146    /// Returns error if provided inputs are invalid, or if internal
147    /// error has occurred.
148    pub fn generate_shares(
149        mut self,
150        rng: &mut (impl RngCore + CryptoRng),
151    ) -> Result<Vec<KeyShare<E, L>>, TrustedDealerError> {
152        let n = self.n;
153        let enable_multiexp = self.enable_mulitexp;
154
155        let primes = self.pregenerated_primes.take();
156        let core_key_shares = self.inner.generate_shares(rng).map_err(Reason::CoreError)?;
157        let aux_data = if let Some(primes) = primes {
158            generate_aux_data_with_primes(rng, primes, enable_multiexp)?
159        } else {
160            generate_aux_data(rng, n, enable_multiexp)?
161        };
162
163        let key_shares = core_key_shares
164            .into_iter()
165            .zip(aux_data)
166            .map(|(core, aux)| KeyShare::from_parts((core, aux)).map_err(|err| err.into_error()))
167            .collect::<Result<Vec<_>, _>>()
168            .map_err(Reason::InvalidKeyShare)?;
169
170        Ok(key_shares)
171    }
172}
173
174/// Generates auxiliary data for `n` signers
175///
176/// Auxiliary data can be used to "complete" core key share using [`KeyShare::from_parts`] constructor.
177///
178/// `enable_multiexp` flag configures whether to enable [multiexp](TrustedDealerBuilder::enable_multiexp)
179/// optimization.
180pub fn generate_aux_data<L: SecurityLevel, R: RngCore + CryptoRng>(
181    rng: &mut R,
182    n: u16,
183    enable_multiexp: bool,
184) -> Result<Vec<AuxInfo<L>>, TrustedDealerError> {
185    let primes = iter::repeat_with(|| crate::key_refresh::PregeneratedPrimes::<L>::generate(rng))
186        .take(n.into())
187        .collect::<Vec<_>>();
188
189    generate_aux_data_with_primes(rng, primes, enable_multiexp)
190}
191
192/// Generates auxiliary data for `n` signers using provided pregenerated primes
193///
194/// `pregenerated_primes` should have exactly `n` pairs of primes.
195///
196/// `enable_multiexp` flag configures whether to enable [multiexp](TrustedDealerBuilder::enable_multiexp)
197/// optimization.
198pub fn generate_aux_data_with_primes<L: SecurityLevel, R: RngCore + CryptoRng>(
199    rng: &mut R,
200    pregenerated_primes: Vec<crate::PregeneratedPrimes<L>>,
201    enable_multiexp: bool,
202) -> Result<Vec<AuxInfo<L>>, TrustedDealerError> {
203    let (N, pedersen_params) = pregenerated_primes
204        .iter()
205        .map(|primes| {
206            let [p, q, hat_p, hat_q] = primes.primes_ref();
207            let N = p * q;
208
209            let (mut params, _phi, _lambda) =
210                utils::generate_pedersen_params(rng, hat_p.clone(), hat_q.clone())?;
211
212            if enable_multiexp {
213                params
214                    .precompute_multiexp_table::<L>()
215                    .map_err(Reason::BuildMultiexp)?;
216            }
217            Ok((N, params))
218        })
219        .collect::<Result<(Vec<_>, Vec<_>), Reason>>()?;
220
221    pregenerated_primes
222        .into_iter()
223        .enumerate()
224        .map(|(i, primes)| {
225            let mut pedersen_params = pedersen_params.clone();
226            for (j, params) in pedersen_params.iter_mut().enumerate() {
227                if i != j {
228                    params.crt = None;
229                }
230            }
231
232            let [p, q, _, _] = primes.into_primes();
233
234            DirtyAuxInfo {
235                p,
236                q,
237                N: N.clone(),
238                pedersen_params,
239                security_level: PhantomData,
240            }
241            .validate()
242            .map_err(|err| Reason::InvalidKeyShare(err.into_error()))
243        })
244        .collect::<Result<Vec<_>, _>>()
245        .map_err(TrustedDealerError)
246}
247
248/// Error explaining why trusted dealer failed to generate shares
249#[derive(Debug, Error)]
250#[error(transparent)]
251pub struct TrustedDealerError(#[from] Reason);
252
253#[derive(Debug, Error)]
254enum Reason {
255    #[error("trusted dealer failed to generate shares due to internal error")]
256    InvalidKeyShare(#[source] InvalidKeyShare),
257    #[error("couldn't build multiexp tables")]
258    BuildMultiexp(#[source] InvalidKeyShare),
259    #[error(transparent)]
260    CoreError(#[from] cggmp24_keygen::key_share::trusted_dealer::TrustedDealerError),
261    #[error("generate pedersen params")]
262    GenPedersen(#[from] utils::GenPedersenError),
263}