use std::ops;
use std::sync::Arc;
use generic_ec::{Curve, NonZero, Point, SecretScalar};
use paillier_zk::paillier_encryption_in_range as π_enc;
use paillier_zk::rug::{Complete, Integer};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::security_level::SecurityLevel;
#[doc(inline)]
pub use cggmp21_keygen::key_share::{
CoreKeyShare as IncompleteKeyShare, DirtyCoreKeyShare as DirtyIncompleteKeyShare, DirtyKeyInfo,
HdError, InvalidCoreShare as InvalidIncompleteKeyShare, KeyInfo, Valid, Validate,
ValidateError, ValidateFromParts, VssSetup,
};
#[doc = include_str!("../docs/key_share.md")]
#[doc = include_str!("../docs/validated_key_share_note.md")]
#[doc = include_str!("../docs/validated_key_share_disclaimer.md")]
pub type KeyShare<E, L = crate::default_choice::SecurityLevel> = Valid<DirtyKeyShare<E, L>>;
pub type AuxInfo<L = crate::default_choice::SecurityLevel> = Valid<DirtyAuxInfo<L>>;
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct DirtyAuxInfo<L: SecurityLevel = crate::default_choice::SecurityLevel> {
pub p: Integer,
pub q: Integer,
pub parties: Vec<PartyAux>,
#[serde(skip)]
pub security_level: std::marker::PhantomData<L>,
}
#[doc = include_str!("../docs/key_share.md")]
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct DirtyKeyShare<E: Curve, L: SecurityLevel = crate::default_choice::SecurityLevel> {
pub core: DirtyIncompleteKeyShare<E>,
pub aux: DirtyAuxInfo<L>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct PartyAux {
pub N: Integer,
pub s: Integer,
pub t: Integer,
#[serde(default)]
pub multiexp: Option<Arc<paillier_zk::multiexp::MultiexpTable>>,
#[serde(default)]
pub crt: Option<paillier_zk::fast_paillier::utils::CrtExp>,
}
impl<L: SecurityLevel> Validate for DirtyAuxInfo<L> {
type Error = InvalidKeyShare;
fn is_valid(&self) -> Result<(), InvalidKeyShare> {
if self.parties.iter().any(|p| {
p.s.gcd_ref(&p.N).complete() != *Integer::ONE
|| p.t.gcd_ref(&p.N).complete() != *Integer::ONE
}) {
return Err(InvalidKeyShareReason::StGcdN.into());
}
if !crate::security_level::validate_secret_paillier_key_size::<L>(&self.p, &self.q) {
return Err(InvalidKeyShareReason::PaillierSkTooSmall.into());
}
if let Some(invalid_aux) = self
.parties
.iter()
.find(|p| !crate::security_level::validate_public_paillier_key_size::<L>(&p.N))
{
return Err(InvalidKeyShareReason::PaillierPkTooSmall {
required: 8 * L::SECURITY_BITS - 1,
actual: invalid_aux.N.significant_bits(),
}
.into());
}
Ok(())
}
}
impl<L: SecurityLevel> DirtyAuxInfo<L> {
pub fn precompute_multiexp_tables(&mut self) -> Result<(), InvalidKeyShare> {
let (x_bits, y_bits) = crate::security_level::max_exponents_size::<L>();
let tables = self
.parties
.iter()
.map(|aux_i| {
paillier_zk::multiexp::MultiexpTable::build(
&aux_i.s,
&aux_i.t,
x_bits,
y_bits,
aux_i.N.clone(),
)
.map(Arc::new)
})
.collect::<Option<Vec<_>>>()
.ok_or(InvalidKeyShareReason::BuildMultiexpTable)?;
self.parties
.iter_mut()
.zip(tables)
.for_each(|(aux_i, table_i)| aux_i.multiexp = Some(table_i));
Ok(())
}
pub fn multiexp_tables_size(&self) -> usize {
self.parties
.iter()
.map(|aux_i| {
aux_i
.multiexp
.as_ref()
.map(|t| t.size_in_bytes())
.unwrap_or(0)
})
.sum()
}
pub fn precompute_crt(&mut self, i: u16) -> Result<(), InvalidKeyShare> {
let aux_i = self
.parties
.get_mut(usize::from(i))
.ok_or(InvalidKeyShareReason::CrtINotInRange)?;
aux_i.precompute_crt(&self.p, &self.q)
}
}
impl PartyAux {
pub fn precompute_multiexp_table<L: SecurityLevel>(&mut self) -> Result<(), InvalidKeyShare> {
let (x_bits, y_bits) = crate::security_level::max_exponents_size::<L>();
let multiexp = paillier_zk::multiexp::MultiexpTable::build(
&self.s,
&self.t,
x_bits,
y_bits,
self.N.clone(),
)
.map(Arc::new)
.ok_or(InvalidKeyShareReason::BuildMultiexpTable)?;
self.multiexp = Some(multiexp);
Ok(())
}
pub fn precompute_crt(&mut self, p: &Integer, q: &Integer) -> Result<(), InvalidKeyShare> {
if (p * q).complete() != self.N {
return Err(InvalidKeyShareReason::CrtInvalidPq.into());
}
let crt = paillier_zk::fast_paillier::utils::CrtExp::build_n(p, q)
.ok_or(InvalidKeyShareReason::BuildCrt)?;
self.crt = Some(crt);
Ok(())
}
}
impl<E: Curve, L: SecurityLevel> Validate for DirtyKeyShare<E, L> {
type Error = InvalidKeyShare;
fn is_valid(&self) -> Result<(), InvalidKeyShare> {
self.core.is_valid()?;
self.aux.is_valid()?;
Self::validate_consistency(&self.core, &self.aux)
}
}
impl<E: Curve, L: SecurityLevel> ValidateFromParts<(IncompleteKeyShare<E>, AuxInfo<L>)>
for DirtyKeyShare<E, L>
{
fn validate_parts(
(core, aux): &(IncompleteKeyShare<E>, AuxInfo<L>),
) -> Result<(), Self::Error> {
Self::validate_consistency(core, aux)
}
fn from_parts((core, aux): (IncompleteKeyShare<E>, AuxInfo<L>)) -> Self {
Self {
core: core.into_inner(),
aux: aux.into_inner(),
}
}
}
impl<E: Curve, L: SecurityLevel> DirtyKeyShare<E, L> {
fn validate_consistency(
core: &DirtyIncompleteKeyShare<E>,
aux: &DirtyAuxInfo<L>,
) -> Result<(), InvalidKeyShare> {
if core.public_shares.len() != aux.parties.len() {
return Err(InvalidKeyShareReason::AuxLen.into());
}
let N_i = &aux.parties[usize::from(core.i)].N;
if *N_i != (&aux.p * &aux.q).complete() {
return Err(InvalidKeyShareReason::PrimesMul.into());
}
Ok(())
}
}
impl<E: Curve> DirtyKeyShare<E> {
pub fn precompute_crt(&mut self) -> Result<(), InvalidKeyShare> {
let i = self.core.i;
self.aux.precompute_crt(i)
}
}
impl<E: Curve, L: SecurityLevel> AsRef<DirtyIncompleteKeyShare<E>> for DirtyKeyShare<E, L> {
fn as_ref(&self) -> &DirtyIncompleteKeyShare<E> {
&self.core
}
}
impl<E: Curve, L: SecurityLevel> AsRef<DirtyAuxInfo<L>> for DirtyKeyShare<E, L> {
fn as_ref(&self) -> &DirtyAuxInfo<L> {
&self.aux
}
}
impl<E: Curve, L: SecurityLevel> ops::Deref for DirtyKeyShare<E, L> {
type Target = DirtyIncompleteKeyShare<E>;
fn deref(&self) -> &Self::Target {
&self.core
}
}
pub trait AnyKeyShare<E: Curve>: AsRef<IncompleteKeyShare<E>> {
fn n(&self) -> u16 {
#[allow(clippy::expect_used)]
self.as_ref()
.public_shares
.len()
.try_into()
.expect("valid key share is guaranteed to have amount of signers fitting into u16")
}
fn min_signers(&self) -> u16 {
self.as_ref()
.vss_setup
.as_ref()
.map(|s| s.min_signers)
.unwrap_or_else(|| self.n())
}
fn shared_public_key(&self) -> NonZero<Point<E>> {
self.as_ref().shared_public_key
}
}
impl<E: Curve, T: AsRef<IncompleteKeyShare<E>>> AnyKeyShare<E> for T {}
#[cfg(feature = "spof")]
pub fn reconstruct_secret_key<E: Curve>(
key_shares: &[impl AnyKeyShare<E>],
) -> Result<SecretScalar<E>, ReconstructError> {
key_share::reconstruct_secret_key(key_shares)
}
impl From<&PartyAux> for π_enc::Aux {
fn from(aux: &PartyAux) -> Self {
Self {
s: aux.s.clone(),
t: aux.t.clone(),
rsa_modulo: aux.N.clone(),
multiexp: aux.multiexp.clone(),
crt: aux.crt.clone(),
}
}
}
#[derive(Debug, Error)]
#[error(transparent)]
pub struct InvalidKeyShare(#[from] InvalidKeyShareReason);
#[derive(Debug, Error)]
enum InvalidKeyShareReason {
#[error(transparent)]
InvalidCoreShare(InvalidIncompleteKeyShare),
#[error("size of parties auxiliary data list doesn't match `n`: n != parties.len()")]
AuxLen,
#[error("N_i != p q")]
PrimesMul,
#[error("gcd(s_j, N_j) != 1 or gcd(t_j, N_j) != 1")]
StGcdN,
#[error("paillier secret key doesn't match security level (primes are too small)")]
PaillierSkTooSmall,
#[error("paillier public key of one of the signers doesn't match security level: required bit length = {required}, actual = {actual}")]
PaillierPkTooSmall { required: u32, actual: u32 },
#[error("couldn't build a multiexp table")]
BuildMultiexpTable,
#[error("provided index `i` does not correspond to an index of the signer at key generation")]
CrtINotInRange,
#[error("provided primes `p`, `q` do not correspond to signer Paillier public key")]
CrtInvalidPq,
#[error("couldn't build CRT parameters")]
BuildCrt,
}
#[cfg(feature = "spof")]
pub use key_share::ReconstructError;
impl From<InvalidIncompleteKeyShare> for InvalidKeyShare {
fn from(err: InvalidIncompleteKeyShare) -> Self {
Self(InvalidKeyShareReason::InvalidCoreShare(err))
}
}
impl<T> From<ValidateError<T, InvalidIncompleteKeyShare>> for InvalidKeyShare {
fn from(err: ValidateError<T, InvalidIncompleteKeyShare>) -> Self {
err.into_error().into()
}
}
impl<T> From<ValidateError<T, InvalidKeyShare>> for InvalidKeyShare {
fn from(err: cggmp21_keygen::key_share::ValidateError<T, InvalidKeyShare>) -> Self {
err.into_error()
}
}