key_share/
trusted_dealer.rs1use alloc::vec::Vec;
24
25use generic_ec::{Curve, NonZero, Point, Scalar, SecretScalar};
26
27use crate::{CoreKeyShare, VssSetup};
28
29pub fn builder<E: Curve>(n: u16) -> TrustedDealerBuilder<E> {
35 TrustedDealerBuilder::new(n)
36}
37
38pub struct TrustedDealerBuilder<E: Curve> {
40 t: Option<u16>,
41 n: u16,
42 shared_secret_key: Option<NonZero<SecretScalar<E>>>,
43 #[cfg(feature = "hd-wallet")]
44 enable_hd: bool,
45}
46
47impl<E: Curve> TrustedDealerBuilder<E> {
48 pub fn new(n: u16) -> Self {
52 TrustedDealerBuilder {
53 t: None,
54 n,
55 shared_secret_key: None,
56 #[cfg(feature = "hd-wallet")]
57 enable_hd: true,
58 }
59 }
60
61 pub fn set_threshold(self, t: Option<u16>) -> Self {
74 Self { t, ..self }
75 }
76
77 pub fn set_shared_secret_key(self, sk: NonZero<SecretScalar<E>>) -> Self {
81 Self {
82 shared_secret_key: Some(sk),
83 ..self
84 }
85 }
86
87 #[cfg(feature = "hd-wallet")]
89 pub fn hd_wallet(self, v: bool) -> Self {
90 Self {
91 enable_hd: v,
92 ..self
93 }
94 }
95
96 pub fn generate_shares(
106 self,
107 rng: &mut (impl rand_core::RngCore + rand_core::CryptoRng),
108 ) -> Result<Vec<CoreKeyShare<E>>, TrustedDealerError> {
109 let key_shares_indexes = (1..=self.n)
110 .map(|i| generic_ec::NonZero::from_scalar(Scalar::from(i)))
111 .collect::<Option<Vec<_>>>()
112 .ok_or(Reason::DeriveKeyShareIndex)?;
113 self.generate_shares_at(key_shares_indexes, rng)
114 }
115
116 pub fn generate_shares_at_random(
128 self,
129 rng: &mut (impl rand_core::RngCore + rand_core::CryptoRng),
130 ) -> Result<Vec<CoreKeyShare<E>>, TrustedDealerError> {
131 let points = (0..self.n)
135 .map(|_| generic_ec::NonZero::<Scalar<E>>::random(rng))
136 .collect();
137 self.generate_shares_at(points, rng)
138 }
139
140 pub fn generate_shares_at(
148 self,
149 preimages: Vec<NonZero<Scalar<E>>>,
150 rng: &mut (impl rand_core::RngCore + rand_core::CryptoRng),
151 ) -> Result<Vec<CoreKeyShare<E>>, TrustedDealerError> {
152 if preimages.len() != usize::from(self.n) {
153 return Err(Reason::InvalidPreimages.into());
154 }
155
156 let shared_secret_key = self
157 .shared_secret_key
158 .unwrap_or_else(|| NonZero::<SecretScalar<_>>::random(rng));
159 let shared_public_key = Point::generator() * &shared_secret_key;
160 let secret_shares = if let Some(t) = self.t {
161 let f = generic_ec_zkp::polynomial::Polynomial::sample_with_const_term(
162 rng,
163 usize::from(t) - 1,
164 shared_secret_key,
165 );
166 debug_assert_eq!(
167 shared_public_key,
168 Point::generator() * f.value::<_, Scalar<_>>(&Scalar::zero())
169 );
170
171 preimages
172 .iter()
173 .map(|I_i| f.value(I_i))
174 .map(|mut x_i| SecretScalar::new(&mut x_i))
175 .map(|x| NonZero::from_secret_scalar(x).ok_or(Reason::ZeroShare))
176 .collect::<Result<Vec<_>, _>>()?
177 } else {
178 let mut shares = core::iter::repeat_with(|| NonZero::<SecretScalar<E>>::random(rng))
179 .take((self.n - 1).into())
180 .collect::<Vec<_>>();
181 shares.push(
182 NonZero::from_secret_scalar(SecretScalar::new(
183 &mut (shared_secret_key - shares.iter().sum::<SecretScalar<E>>()),
184 ))
185 .ok_or(Reason::ZeroShare)?,
186 );
187 debug_assert_eq!(
188 shared_public_key,
189 shares.iter().sum::<SecretScalar<E>>() * Point::generator()
190 );
191 shares
192 };
193
194 let public_shares = secret_shares
195 .iter()
196 .map(|s_i| Point::generator() * s_i)
197 .collect::<Vec<_>>();
198
199 let vss_setup = self.t.map(|t| VssSetup {
200 min_signers: t,
201 I: preimages,
202 });
203
204 #[cfg(feature = "hd-wallet")]
205 let chain_code = if self.enable_hd {
206 let mut code = hd_wallet::ChainCode::default();
207 rng.fill_bytes(&mut code);
208 Some(code)
209 } else {
210 None
211 };
212
213 Ok((0u16..)
214 .zip(secret_shares)
215 .map(|(i, x_i)| {
216 crate::Validate::validate(crate::DirtyCoreKeyShare::<E> {
217 i,
218 key_info: crate::DirtyKeyInfo {
219 curve: Default::default(),
220 shared_public_key,
221 public_shares: public_shares.clone(),
222 vss_setup: vss_setup.clone(),
223 #[cfg(feature = "hd-wallet")]
224 chain_code,
225 },
226 x: x_i,
227 })
228 .map_err(|err| Reason::InvalidKeyShare(err.into_error()))
229 })
230 .collect::<Result<Vec<_>, _>>()?)
231 }
232}
233
234#[derive(Debug, displaydoc::Display)]
236#[cfg_attr(feature = "std", derive(thiserror::Error))]
237#[displaydoc("trusted dealer failed to generate shares")]
238pub struct TrustedDealerError(#[cfg_attr(feature = "std", source)] Reason);
239
240#[derive(Debug, displaydoc::Display)]
241#[cfg_attr(feature = "std", derive(thiserror::Error))]
242enum Reason {
243 #[displaydoc("trusted dealer failed to generate shares due to internal error")]
244 InvalidKeyShare(#[cfg_attr(feature = "std", source)] crate::InvalidCoreShare),
245 #[displaydoc("deriving key share index failed")]
246 DeriveKeyShareIndex,
247 #[displaydoc("randomly generated share is zero - probability of that is negligible")]
248 ZeroShare,
249 #[displaydoc("invalid share preimages given")]
250 InvalidPreimages,
251}
252
253impl From<Reason> for TrustedDealerError {
254 fn from(err: Reason) -> Self {
255 Self(err)
256 }
257}