mirror of
https://github.com/luxfi/cggmp21.rs.git
synced 2026-11-02 10:02:41 +00:00
359 lines
12 KiB
Rust
359 lines
12 KiB
Rust
//! Trusted dealer
|
|
//!
|
|
//! Trusted dealer can be used to generate key shares in one place. Note
|
|
//! that it creates an SPOF/T (single point of failure/trust). Trusted
|
|
//! dealer is mainly intended to be used in tests, or it can be used to
|
|
//! import key into TSS.
|
|
//!
|
|
//! ## Example
|
|
//! Import a key into 3-out-of-5 TSS:
|
|
//! ```rust,no_run
|
|
//! # use rand::rngs::OsRng;
|
|
//! # let mut rng = OsRng;
|
|
//! use cggmp21::{supported_curves::Secp256k1, security_level::SecurityLevel128};
|
|
//! use cggmp21::generic_ec::{SecretScalar, NonZero};
|
|
//!
|
|
//! let secret_key_to_be_imported = NonZero::<SecretScalar<Secp256k1>>::random(&mut rng);
|
|
//!
|
|
//! let key_shares = cggmp21::trusted_dealer::builder::<Secp256k1, SecurityLevel128>(5)
|
|
//! .set_threshold(Some(3))
|
|
//! .set_shared_secret_key(secret_key_to_be_imported)
|
|
//! .generate_shares(&mut rng)?;
|
|
//! # Ok::<_, cggmp21::trusted_dealer::TrustedDealerError>(())
|
|
//! ```
|
|
|
|
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,
|
|
};
|
|
|
|
/// Construct a trusted dealer builder
|
|
///
|
|
/// Takes amount of key shares `n` to be generated
|
|
///
|
|
/// Alias to [`TrustedDealerBuilder::new`]
|
|
pub fn builder<E: Curve, L: SecurityLevel>(n: u16) -> TrustedDealerBuilder<E, L> {
|
|
TrustedDealerBuilder::new(n)
|
|
}
|
|
|
|
type CoreBuilder<E> = key_share::trusted_dealer::TrustedDealerBuilder<E>;
|
|
|
|
/// Trusted dealer builder
|
|
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> {
|
|
/// Construct a trusted dealer builder
|
|
///
|
|
/// Takes amount of key shares `n` to be generated
|
|
pub fn new(n: u16) -> Self {
|
|
TrustedDealerBuilder {
|
|
inner: CoreBuilder::new(n),
|
|
n,
|
|
pregenerated_primes: None,
|
|
enable_mulitexp: false,
|
|
enable_crt: false,
|
|
_ph: PhantomData,
|
|
}
|
|
}
|
|
|
|
/// Sets threshold value
|
|
///
|
|
/// If threshold is `Some(_)`, resulting key shares will be generated
|
|
/// using t-out-of-n VSS scheme. If it's `None`, trusted dealer will
|
|
/// generate additive key shares in n-out-ouf-n scheme.
|
|
///
|
|
/// Note that setting `t=Some(n)` is not the same as setting `t=None`.
|
|
/// Both produce n-out-of-n key shares, but `t=Some(n)` mocks threshold
|
|
/// key generation with `threshold=n`, `t=None` mock non-threshold key
|
|
/// generation.
|
|
///
|
|
/// Default: `None`
|
|
pub fn set_threshold(self, t: Option<u16>) -> Self {
|
|
Self {
|
|
inner: self.inner.set_threshold(t),
|
|
..self
|
|
}
|
|
}
|
|
|
|
/// Sets shared secret key to be generated
|
|
///
|
|
/// Resulting key shares will share specified secret key.
|
|
pub fn set_shared_secret_key(self, sk: NonZero<SecretScalar<E>>) -> Self {
|
|
Self {
|
|
inner: self.inner.set_shared_secret_key(sk),
|
|
..self
|
|
}
|
|
}
|
|
|
|
/// Sets pregenerated primes to use
|
|
///
|
|
/// `primes` should have exactly `n` pairs of primes.
|
|
pub fn set_pregenerated_primes(self, primes: Vec<(Integer, Integer)>) -> Self {
|
|
Self {
|
|
pregenerated_primes: Some(primes),
|
|
..self
|
|
}
|
|
}
|
|
|
|
/// Enables multiexp optimization
|
|
///
|
|
/// It takes additional time to precompute multiexp tables, and it makes the key shares larger,
|
|
/// but it makes the signing and presignature generation protocols faster
|
|
pub fn enable_multiexp(self, v: bool) -> Self {
|
|
Self {
|
|
enable_mulitexp: v,
|
|
..self
|
|
}
|
|
}
|
|
|
|
/// Enables CRT optimization
|
|
///
|
|
/// CRT optimization makes ZK proofs verification faster, and by doing so it makes the overall performance better
|
|
pub fn enable_crt(self, v: bool) -> Self {
|
|
Self {
|
|
enable_crt: v,
|
|
..self
|
|
}
|
|
}
|
|
|
|
/// Specifies that the key being generated shall support HD derivation
|
|
#[cfg(feature = "hd-wallet")]
|
|
pub fn hd_wallet(self, v: bool) -> Self {
|
|
Self {
|
|
inner: self.inner.hd_wallet(v),
|
|
..self
|
|
}
|
|
}
|
|
|
|
/// Generates [`IncompleteKeyShare`]s
|
|
///
|
|
/// For Shamir secret sharing, it's shared at points `1` to `n`
|
|
///
|
|
/// Returns error if provided inputs are invalid, or if internal
|
|
/// error has occurred.
|
|
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)
|
|
}
|
|
|
|
/// Generates [`KeyShare`]s
|
|
///
|
|
/// For Shamir secret sharing, it's shared at points `1` to `n`
|
|
///
|
|
/// Returns error if provided inputs are invalid, or if internal
|
|
/// error has occurred.
|
|
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,
|
|
)
|
|
}
|
|
|
|
/// Generates [`KeyShare`]s shared at preimages provided. Each share is
|
|
/// going to have the given `preimages` as its `I` component.
|
|
///
|
|
/// Preimages are ignored for additive key shares.
|
|
///
|
|
/// Returns error if provided inputs are invalid, or if internal
|
|
/// error has occurred.
|
|
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,
|
|
)
|
|
}
|
|
|
|
/// Generates [`KeyShare`]s shared at random points
|
|
///
|
|
/// Returns error if provided inputs are invalid, or if internal
|
|
/// error has occurred.
|
|
///
|
|
/// For Shamir secret sharing, the points at which the value is shared at
|
|
/// are chosen at random between `1` and `u16::MAX`. For additive shares,
|
|
/// this is the same as [`TrustedDealerBuilder::generate_shares`]
|
|
///
|
|
/// Returns error if provided inputs are invalid, or if internal
|
|
/// error has occurred.
|
|
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)
|
|
}
|
|
}
|
|
|
|
/// Generates auxiliary data for `n` signers
|
|
///
|
|
/// Auxiliary data can be used to "complete" core key share using [`KeyShare::from_parts`] constructor.
|
|
///
|
|
/// `enable_multiexp` and `enable_crt` flags configure whether to enable [multiexp](TrustedDealerBuilder::enable_multiexp)
|
|
/// and [CRT](TrustedDealerBuilder::enable_crt) optimizations.
|
|
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)
|
|
}
|
|
|
|
/// Generates auxiliary data for `n` signers using provided pregenerated primes
|
|
///
|
|
/// `pregenerated_primes` should have exactly `n` pairs of primes.
|
|
///
|
|
/// `enable_multiexp` and `enable_crt` flags configure whether to enable [multiexp](TrustedDealerBuilder::enable_multiexp)
|
|
/// and [CRT](TrustedDealerBuilder::enable_crt) optimizations.
|
|
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)
|
|
}
|
|
|
|
/// Error explaining why trusted dealer failed to generate shares
|
|
#[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),
|
|
}
|