1use std::ops;
4use std::sync::Arc;
5
6use generic_ec::{Curve, NonZero, Point};
7use paillier_zk::backend::Integer;
8use paillier_zk::paillier_encryption_in_range as π_enc;
9use serde::{Deserialize, Serialize};
10use thiserror::Error;
11
12use crate::security_level::SecurityLevel;
13
14#[doc(inline)]
15pub use cggmp24_keygen::key_share::{
16 CoreKeyShare as IncompleteKeyShare, DirtyCoreKeyShare as DirtyIncompleteKeyShare, DirtyKeyInfo,
17 HdError, InvalidCoreShare as InvalidIncompleteKeyShare, KeyInfo, Valid, Validate,
18 ValidateError, ValidateFromParts, VssSetup,
19};
20
21#[doc = include_str!("../docs/key_share.md")]
24#[doc = include_str!("../docs/validated_key_share_note.md")]
26#[doc = include_str!("../docs/validated_key_share_disclaimer.md")]
27pub type KeyShare<E, L = crate::default_choice::SecurityLevel> = Valid<DirtyKeyShare<E, L>>;
28
29pub type AuxInfo<L = crate::default_choice::SecurityLevel> = Valid<DirtyAuxInfo<L>>;
31
32#[derive(Clone, Serialize, Deserialize)]
34#[serde(bound = "")]
35pub struct DirtyAuxInfo<L: SecurityLevel = crate::default_choice::SecurityLevel> {
36 pub p: Integer,
38 pub q: Integer,
40 pub N: Vec<Integer>,
42 pub pedersen_params: Vec<PedersenParams>,
49 #[serde(skip)]
51 pub security_level: std::marker::PhantomData<L>,
52}
53
54#[doc = include_str!("../docs/key_share.md")]
57#[derive(Clone, Serialize, Deserialize)]
58#[serde(bound = "")]
59pub struct DirtyKeyShare<E: Curve, L: SecurityLevel = crate::default_choice::SecurityLevel> {
60 pub core: DirtyIncompleteKeyShare<E>,
62 pub aux: DirtyAuxInfo<L>,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
68#[serde(bound = "")]
69pub struct PedersenParams {
70 pub hat_N: Integer,
72 pub s: Integer,
74 pub t: Integer,
76 #[serde(default)]
81 pub multiexp: Option<Arc<paillier_zk::multiexp::MultiexpTable>>,
82 #[serde(default)]
88 pub crt: Option<paillier_zk::fast_paillier::utils::CrtExp>,
89}
90
91impl<L: SecurityLevel> Validate for DirtyAuxInfo<L> {
92 type Error = InvalidKeyShare;
93
94 fn is_valid(&self) -> Result<(), InvalidKeyShare> {
95 if self
96 .pedersen_params
97 .iter()
98 .any(|p| !p.s.gcd_ref(&p.hat_N).is_one() || !p.t.gcd_ref(&p.hat_N).is_one())
99 {
100 return Err(InvalidKeyShareReason::StGcdN.into());
101 }
102
103 if [&self.p, &self.q]
104 .iter()
105 .any(|prime| !crate::security_level::validate_secret_paillier_prime_size::<L>(prime))
106 {
107 return Err(InvalidKeyShareReason::PaillierSkTooSmall.into());
108 }
109
110 if let Some(N) = self
111 .N
112 .iter()
113 .find(|N| !crate::security_level::validate_public_paillier_key_size::<L>(N))
114 {
115 return Err(InvalidKeyShareReason::PaillierPkTooSmall {
116 required: L::RSA_PUBKEY_BITLEN,
117 actual: N.significant_bits(),
118 }
119 .into());
120 }
121
122 if let Some(params) = self.pedersen_params.iter().find(|params| {
123 !crate::security_level::validate_public_paillier_key_size::<L>(¶ms.hat_N)
124 }) {
125 return Err(InvalidKeyShareReason::PedersenModuleTooSmall {
126 required: L::RSA_PUBKEY_BITLEN,
127 actual: params.hat_N.significant_bits(),
128 }
129 .into());
130 }
131
132 Ok(())
133 }
134}
135
136impl<L: SecurityLevel> DirtyAuxInfo<L> {
137 pub fn precompute_multiexp_tables(&mut self) -> Result<(), InvalidKeyShare> {
145 let (x_bits, y_bits) = crate::security_level::max_exponents_size::<L>();
146 let tables = self
147 .pedersen_params
148 .iter()
149 .map(|aux_i| {
150 paillier_zk::multiexp::MultiexpTable::build(
151 &aux_i.s,
152 &aux_i.t,
153 x_bits,
154 y_bits,
155 aux_i.hat_N.clone(),
156 )
157 .map(Arc::new)
158 })
159 .collect::<Option<Vec<_>>>()
160 .ok_or(InvalidKeyShareReason::BuildMultiexpTable)?;
161 self.pedersen_params
162 .iter_mut()
163 .zip(tables)
164 .for_each(|(aux_i, table_i)| aux_i.multiexp = Some(table_i));
165 Ok(())
166 }
167
168 pub fn multiexp_tables_size(&self) -> usize {
170 self.pedersen_params
171 .iter()
172 .map(|aux_i| {
173 aux_i
174 .multiexp
175 .as_ref()
176 .map(|t| t.size_in_bytes())
177 .unwrap_or(0)
178 })
179 .sum()
180 }
181
182 pub fn precompute_crt(&mut self, i: u16) -> Result<(), InvalidKeyShare> {
186 let aux_i = self
187 .pedersen_params
188 .get_mut(usize::from(i))
189 .ok_or(InvalidKeyShareReason::CrtINotInRange)?;
190 aux_i.precompute_crt(&self.p, &self.q)
191 }
192}
193
194impl PedersenParams {
195 pub fn precompute_multiexp_table<L: SecurityLevel>(&mut self) -> Result<(), InvalidKeyShare> {
206 let (x_bits, y_bits) = crate::security_level::max_exponents_size::<L>();
207 let multiexp = paillier_zk::multiexp::MultiexpTable::build(
208 &self.s,
209 &self.t,
210 x_bits,
211 y_bits,
212 self.hat_N.clone(),
213 )
214 .map(Arc::new)
215 .ok_or(InvalidKeyShareReason::BuildMultiexpTable)?;
216 self.multiexp = Some(multiexp);
217 Ok(())
218 }
219
220 pub fn precompute_crt(&mut self, p: &Integer, q: &Integer) -> Result<(), InvalidKeyShare> {
234 if p * q != self.hat_N {
235 return Err(InvalidKeyShareReason::CrtInvalidPq.into());
236 }
237 let crt = paillier_zk::fast_paillier::utils::CrtExp::build_n(p, q)
238 .ok_or(InvalidKeyShareReason::BuildCrt)?;
239 self.crt = Some(crt);
240 Ok(())
241 }
242}
243
244impl<E: Curve, L: SecurityLevel> Validate for DirtyKeyShare<E, L> {
245 type Error = InvalidKeyShare;
246
247 fn is_valid(&self) -> Result<(), InvalidKeyShare> {
248 self.core.is_valid()?;
249 self.aux.is_valid()?;
250 Self::validate_consistency(&self.core, &self.aux)
251 }
252}
253
254impl<E: Curve, L: SecurityLevel> ValidateFromParts<(IncompleteKeyShare<E>, AuxInfo<L>)>
255 for DirtyKeyShare<E, L>
256{
257 fn validate_parts(
258 (core, aux): &(IncompleteKeyShare<E>, AuxInfo<L>),
259 ) -> Result<(), Self::Error> {
260 Self::validate_consistency(core, aux)
261 }
262
263 fn from_parts((core, aux): (IncompleteKeyShare<E>, AuxInfo<L>)) -> Self {
264 Self {
265 core: core.into_inner(),
266 aux: aux.into_inner(),
267 }
268 }
269}
270
271impl<E: Curve, L: SecurityLevel> DirtyKeyShare<E, L> {
272 fn validate_consistency(
274 core: &DirtyIncompleteKeyShare<E>,
275 aux: &DirtyAuxInfo<L>,
276 ) -> Result<(), InvalidKeyShare> {
277 if core.public_shares.len() != aux.pedersen_params.len() {
278 return Err(InvalidKeyShareReason::AuxLen.into());
279 }
280
281 let N_i = &aux.N[usize::from(core.i)];
282 if *N_i != &aux.p * &aux.q {
283 return Err(InvalidKeyShareReason::PrimesMul.into());
284 }
285
286 Ok(())
287 }
288}
289
290impl<E: Curve> DirtyKeyShare<E> {
291 pub fn precompute_crt(&mut self) -> Result<(), InvalidKeyShare> {
302 let i = self.core.i;
303 self.aux.precompute_crt(i)
304 }
305}
306
307impl<E: Curve, L: SecurityLevel> AsRef<DirtyIncompleteKeyShare<E>> for DirtyKeyShare<E, L> {
308 fn as_ref(&self) -> &DirtyIncompleteKeyShare<E> {
309 &self.core
310 }
311}
312impl<E: Curve, L: SecurityLevel> AsRef<DirtyAuxInfo<L>> for DirtyKeyShare<E, L> {
313 fn as_ref(&self) -> &DirtyAuxInfo<L> {
314 &self.aux
315 }
316}
317
318impl<E: Curve, L: SecurityLevel> ops::Deref for DirtyKeyShare<E, L> {
319 type Target = DirtyIncompleteKeyShare<E>;
320
321 fn deref(&self) -> &Self::Target {
322 &self.core
323 }
324}
325
326pub trait AnyKeyShare<E: Curve>: AsRef<IncompleteKeyShare<E>> {
331 fn n(&self) -> u16 {
333 #[allow(clippy::expect_used)]
334 self.as_ref()
335 .public_shares
336 .len()
337 .try_into()
338 .expect("valid key share is guaranteed to have amount of signers fitting into u16")
339 }
340
341 fn min_signers(&self) -> u16 {
346 self.as_ref()
347 .vss_setup
348 .as_ref()
349 .map(|s| s.min_signers)
350 .unwrap_or_else(|| self.n())
351 }
352
353 fn shared_public_key(&self) -> NonZero<Point<E>> {
355 self.as_ref().shared_public_key
356 }
357}
358
359impl<E: Curve, T: AsRef<IncompleteKeyShare<E>>> AnyKeyShare<E> for T {}
360
361#[cfg(feature = "spof")]
371pub fn reconstruct_secret_key<E: Curve>(
372 key_shares: &[impl AnyKeyShare<E>],
373) -> Result<generic_ec::SecretScalar<E>, ReconstructError> {
374 cggmp24_keygen::key_share::reconstruct_secret_key(key_shares)
375}
376
377impl From<&PedersenParams> for π_enc::Aux {
378 fn from(aux: &PedersenParams) -> Self {
379 Self {
380 s: aux.s.clone(),
381 t: aux.t.clone(),
382 rsa_modulo: aux.hat_N.clone(),
383 multiexp: aux.multiexp.clone(),
384 crt: aux.crt.clone(),
385 }
386 }
387}
388
389#[derive(Debug, Error)]
391#[error(transparent)]
392pub struct InvalidKeyShare(#[from] InvalidKeyShareReason);
393
394#[derive(Debug, Error)]
395enum InvalidKeyShareReason {
396 #[error(transparent)]
397 InvalidCoreShare(InvalidIncompleteKeyShare),
398 #[error("size of parties auxiliary data list doesn't match `n`: n != parties.len()")]
399 AuxLen,
400 #[error("N_i != p q")]
401 PrimesMul,
402 #[error("gcd(s_j, N_j) != 1 or gcd(t_j, N_j) != 1")]
403 StGcdN,
404 #[error("paillier secret key doesn't match security level (primes are too small)")]
405 PaillierSkTooSmall,
406 #[error("paillier public key of one of the signers doesn't match security level: required bit length = {required}, actual = {actual}")]
407 PaillierPkTooSmall { required: u32, actual: u64 },
408 #[error("pedersen module of one of the signers doesn't match security level: required bit length = {required}, actual = {actual}")]
409 PedersenModuleTooSmall { required: u32, actual: u64 },
410 #[error("couldn't build a multiexp table")]
411 BuildMultiexpTable,
412 #[error("provided index `i` does not correspond to an index of the signer at key generation")]
413 CrtINotInRange,
414 #[error("provided primes `p`, `q` do not correspond to signer Paillier public key")]
415 CrtInvalidPq,
416 #[error("couldn't build CRT parameters")]
417 BuildCrt,
418}
419
420#[cfg(feature = "spof")]
422pub use cggmp24_keygen::key_share::ReconstructError;
423
424impl From<InvalidIncompleteKeyShare> for InvalidKeyShare {
425 fn from(err: InvalidIncompleteKeyShare) -> Self {
426 Self(InvalidKeyShareReason::InvalidCoreShare(err))
427 }
428}
429
430impl<T> From<ValidateError<T, InvalidIncompleteKeyShare>> for InvalidKeyShare {
431 fn from(err: ValidateError<T, InvalidIncompleteKeyShare>) -> Self {
432 err.into_error().into()
433 }
434}
435
436impl<T> From<ValidateError<T, InvalidKeyShare>> for InvalidKeyShare {
437 fn from(err: cggmp24_keygen::key_share::ValidateError<T, InvalidKeyShare>) -> Self {
438 err.into_error()
439 }
440}
441
442pub mod cggmp21_compat {
455 #[derive(serde::Deserialize, Clone)]
457 pub struct ExtractCoreShare<E: generic_ec::Curve> {
458 pub core: super::IncompleteKeyShare<E>,
460 #[serde(rename = "aux")]
461 _aux: serde::de::IgnoredAny,
462 }
463}