use std::{iter, marker::PhantomData};
use generic_ec::{Curve, NonZero, SecretScalar};
use paillier_zk::{
rug::{Complete, Integer},
IntegerExt,
};
use rand_core::{CryptoRng, RngCore};
use thiserror::Error;
use crate::{
key_share::{
AuxInfo, DirtyAuxInfo, IncompleteKeyShare, InvalidKeyShare, KeyShare, PartyAux, Validate,
},
security_level::SecurityLevel,
utils,
};
pub fn builder<E: Curve, L: SecurityLevel>(n: u16) -> TrustedDealerBuilder<E, L> {
TrustedDealerBuilder::new(n)
}
type CoreBuilder<E> = key_share::trusted_dealer::TrustedDealerBuilder<E>;
pub struct TrustedDealerBuilder<E: Curve, L: SecurityLevel> {
inner: CoreBuilder<E>,
n: u16,
pregenerated_primes: Option<Vec<(Integer, Integer)>>,
enable_mulitexp: bool,
enable_crt: bool,
_ph: PhantomData<L>,
}
impl<E: Curve, L: SecurityLevel> TrustedDealerBuilder<E, L> {
pub fn new(n: u16) -> Self {
TrustedDealerBuilder {
inner: CoreBuilder::new(n),
n,
pregenerated_primes: None,
enable_mulitexp: false,
enable_crt: false,
_ph: PhantomData,
}
}
pub fn set_threshold(self, t: Option<u16>) -> Self {
Self {
inner: self.inner.set_threshold(t),
..self
}
}
pub fn set_shared_secret_key(self, sk: NonZero<SecretScalar<E>>) -> Self {
Self {
inner: self.inner.set_shared_secret_key(sk),
..self
}
}
pub fn set_pregenerated_primes(self, primes: Vec<(Integer, Integer)>) -> Self {
Self {
pregenerated_primes: Some(primes),
..self
}
}
pub fn enable_multiexp(self, v: bool) -> Self {
Self {
enable_mulitexp: v,
..self
}
}
pub fn enable_crt(self, v: bool) -> Self {
Self {
enable_crt: v,
..self
}
}
#[cfg(feature = "hd-wallet")]
pub fn hd_wallet(self, v: bool) -> Self {
Self {
inner: self.inner.hd_wallet(v),
..self
}
}
pub fn generate_core_shares(
self,
rng: &mut (impl RngCore + CryptoRng),
) -> Result<Vec<IncompleteKeyShare<E>>, TrustedDealerError> {
self.inner
.generate_shares(rng)
.map_err(Reason::CoreError)
.map_err(TrustedDealerError)
}
pub fn generate_shares(
self,
rng: &mut (impl RngCore + CryptoRng),
) -> Result<Vec<KeyShare<E, L>>, TrustedDealerError> {
self.generate_shares_at_internal(
key_share::trusted_dealer::TrustedDealerBuilder::generate_shares,
rng,
)
}
pub fn generate_shares_at(
self,
preimages: Vec<NonZero<generic_ec::Scalar<E>>>,
rng: &mut (impl RngCore + CryptoRng),
) -> Result<Vec<KeyShare<E, L>>, TrustedDealerError> {
self.generate_shares_at_internal(
|builder, rng| builder.generate_shares_at(preimages, rng),
rng,
)
}
pub fn generate_shares_at_random(
self,
rng: &mut (impl rand_core::RngCore + rand_core::CryptoRng),
) -> Result<Vec<KeyShare<E, L>>, TrustedDealerError> {
self.generate_shares_at_internal(
key_share::trusted_dealer::TrustedDealerBuilder::generate_shares_at_random,
rng,
)
}
fn generate_shares_at_internal<R, F>(
mut self,
inner_generate: F,
rng: &mut R,
) -> Result<Vec<KeyShare<E, L>>, TrustedDealerError>
where
F: FnOnce(
CoreBuilder<E>,
&mut R,
) -> Result<
Vec<IncompleteKeyShare<E>>,
key_share::trusted_dealer::TrustedDealerError,
>,
R: rand_core::RngCore + rand_core::CryptoRng,
{
let n = self.n;
let enable_multiexp = self.enable_mulitexp;
let enable_crt = self.enable_crt;
let primes = self.pregenerated_primes.take();
let core_key_shares = inner_generate(self.inner, rng).map_err(Reason::CoreError)?;
let aux_data = if let Some(primes) = primes {
generate_aux_data_with_primes(rng, primes, enable_multiexp, enable_crt)?
} else {
generate_aux_data(rng, n, enable_multiexp, enable_crt)?
};
let key_shares = core_key_shares
.into_iter()
.zip(aux_data)
.map(|(core, aux)| KeyShare::from_parts((core, aux)))
.collect::<Result<Vec<_>, _>>()
.map_err(|err| Reason::InvalidKeyShare(err.into_error()))?;
Ok(key_shares)
}
}
pub fn generate_aux_data<L: SecurityLevel, R: RngCore + CryptoRng>(
rng: &mut R,
n: u16,
enable_multiexp: bool,
enable_crt: bool,
) -> Result<Vec<AuxInfo<L>>, TrustedDealerError> {
let primes =
iter::repeat_with(|| crate::key_refresh::PregeneratedPrimes::<L>::generate(rng).split())
.take(n.into())
.collect::<Vec<_>>();
generate_aux_data_with_primes(rng, primes, enable_multiexp, enable_crt)
}
pub fn generate_aux_data_with_primes<L: SecurityLevel, R: RngCore + CryptoRng>(
rng: &mut R,
pregenerated_primes: Vec<(Integer, Integer)>,
enable_multiexp: bool,
enable_crt: bool,
) -> Result<Vec<AuxInfo<L>>, TrustedDealerError> {
let public_aux_data = pregenerated_primes
.iter()
.map(|(p, q)| {
let N = (p * q).complete();
let φ_N = (p - 1u8).complete() * (q - 1u8).complete();
let r = Integer::gen_invertible(&N, rng);
let λ = φ_N.random_below_ref(&mut utils::external_rand(rng)).into();
let t = r.square().modulo(&N);
let s = t.pow_mod_ref(&λ, &N).ok_or(Reason::PowMod)?.into();
let mut aux = PartyAux {
N,
s,
t,
multiexp: None,
crt: None,
};
if enable_multiexp {
aux.precompute_multiexp_table::<L>()
.map_err(Reason::BuildMultiexp)?;
}
Ok(aux)
})
.collect::<Result<Vec<_>, Reason>>()?;
pregenerated_primes
.into_iter()
.enumerate()
.map(|(i, (p, q))| {
let mut public_aux_data = public_aux_data.clone();
if enable_crt {
public_aux_data[i]
.precompute_crt(&p, &q)
.map_err(Reason::BuildCrt)?;
}
DirtyAuxInfo {
p,
q,
parties: public_aux_data,
security_level: PhantomData,
}
.validate()
.map_err(|err| Reason::InvalidKeyShare(err.into_error()))
})
.collect::<Result<Vec<_>, _>>()
.map_err(TrustedDealerError)
}
#[derive(Debug, Error)]
#[error(transparent)]
pub struct TrustedDealerError(#[from] Reason);
#[derive(Debug, Error)]
enum Reason {
#[error("trusted dealer failed to generate shares due to internal error")]
InvalidKeyShare(#[source] InvalidKeyShare),
#[error("pow mod undefined")]
PowMod,
#[error("couldn't build a CRT")]
BuildCrt(#[source] InvalidKeyShare),
#[error("couldn't build multiexp tables")]
BuildMultiexp(#[source] InvalidKeyShare),
#[error(transparent)]
CoreError(#[from] key_share::trusted_dealer::TrustedDealerError),
}