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(
103 self,
104 rng: &mut (impl rand_core::RngCore + rand_core::CryptoRng),
105 ) -> Result<Vec<CoreKeyShare<E>>, TrustedDealerError> {
106 let key_shares_indexes = (1..=self.n)
107 .map(|i| generic_ec::NonZero::from_scalar(Scalar::from(i)))
108 .collect::<Option<Vec<_>>>()
109 .ok_or(Reason::DeriveKeyShareIndex)?;
110 self.generate_shares_at(key_shares_indexes, rng)
111 }
112
113 pub fn generate_shares_at_random(
122 self,
123 rng: &mut (impl rand_core::RngCore + rand_core::CryptoRng),
124 ) -> Result<Vec<CoreKeyShare<E>>, TrustedDealerError> {
125 let points = (0..self.n)
129 .map(|_| generic_ec::NonZero::<Scalar<E>>::random(rng))
130 .collect();
131 self.generate_shares_at(points, rng)
132 }
133
134 pub fn generate_shares_at(
142 self,
143 preimages: Vec<NonZero<Scalar<E>>>,
144 rng: &mut (impl rand_core::RngCore + rand_core::CryptoRng),
145 ) -> Result<Vec<CoreKeyShare<E>>, TrustedDealerError> {
146 if preimages.len() != usize::from(self.n) {
147 return Err(Reason::InvalidPreimages.into());
148 }
149
150 let shared_secret_key = self
151 .shared_secret_key
152 .unwrap_or_else(|| NonZero::<SecretScalar<_>>::random(rng));
153 let shared_public_key = Point::generator() * &shared_secret_key;
154 let secret_shares = if let Some(t) = self.t {
155 let f = generic_ec_zkp::polynomial::Polynomial::sample_with_const_term(
156 rng,
157 usize::from(t) - 1,
158 shared_secret_key,
159 );
160 debug_assert_eq!(
161 shared_public_key,
162 Point::generator() * f.value::<_, Scalar<_>>(&Scalar::zero())
163 );
164
165 preimages
166 .iter()
167 .map(|I_i| f.value(I_i))
168 .map(|mut x_i| SecretScalar::new(&mut x_i))
169 .map(|x| NonZero::from_secret_scalar(x).ok_or(Reason::ZeroShare))
170 .collect::<Result<Vec<_>, _>>()?
171 } else {
172 let mut shares = core::iter::repeat_with(|| NonZero::<SecretScalar<E>>::random(rng))
173 .take((self.n - 1).into())
174 .collect::<Vec<_>>();
175 shares.push(
176 NonZero::from_secret_scalar(SecretScalar::new(
177 &mut (shared_secret_key - shares.iter().sum::<SecretScalar<E>>()),
178 ))
179 .ok_or(Reason::ZeroShare)?,
180 );
181 debug_assert_eq!(
182 shared_public_key,
183 shares.iter().sum::<SecretScalar<E>>() * Point::generator()
184 );
185 shares
186 };
187
188 let public_shares = secret_shares
189 .iter()
190 .map(|s_i| Point::generator() * s_i)
191 .collect::<Vec<_>>();
192
193 let vss_setup = self.t.map(|t| VssSetup {
194 min_signers: t,
195 I: preimages,
196 });
197
198 #[cfg(feature = "hd-wallet")]
199 let chain_code = if self.enable_hd {
200 let mut code = hd_wallet::ChainCode::default();
201 rng.fill_bytes(&mut code);
202 Some(code)
203 } else {
204 None
205 };
206
207 Ok((0u16..)
208 .zip(secret_shares)
209 .map(|(i, x_i)| {
210 crate::Validate::validate(crate::DirtyCoreKeyShare::<E> {
211 i,
212 key_info: crate::DirtyKeyInfo {
213 curve: Default::default(),
214 shared_public_key,
215 public_shares: public_shares.clone(),
216 vss_setup: vss_setup.clone(),
217 #[cfg(feature = "hd-wallet")]
218 chain_code,
219 },
220 x: x_i,
221 })
222 .map_err(|err| Reason::InvalidKeyShare(err.into_error()))
223 })
224 .collect::<Result<Vec<_>, _>>()?)
225 }
226}
227
228#[derive(Debug, displaydoc::Display)]
230#[cfg_attr(feature = "std", derive(thiserror::Error))]
231#[displaydoc("trusted dealer failed to generate shares")]
232pub struct TrustedDealerError(#[cfg_attr(feature = "std", source)] Reason);
233
234#[derive(Debug, displaydoc::Display)]
235#[cfg_attr(feature = "std", derive(thiserror::Error))]
236enum Reason {
237 #[displaydoc("trusted dealer failed to generate shares due to internal error")]
238 InvalidKeyShare(#[cfg_attr(feature = "std", source)] crate::InvalidCoreShare),
239 #[displaydoc("deriving key share index failed")]
240 DeriveKeyShareIndex,
241 #[displaydoc("randomly generated share is zero - probability of that is negligible")]
242 ZeroShare,
243 #[displaydoc("invalid share preimages given")]
244 InvalidPreimages,
245}
246
247impl From<Reason> for TrustedDealerError {
248 fn from(err: Reason) -> Self {
249 Self(err)
250 }
251}