#![allow(clippy::type_complexity)]
#![allow(unused_assignments)]
use core::iter;
use alloc::{
collections::{BTreeMap, BTreeSet},
fmt::{self, Debug},
string::ToString,
vec::Vec,
};
use derive_getters::Getters;
#[cfg(any(test, feature = "test-impl"))]
use hex::FromHex;
use rand_core::{CryptoRng, RngCore};
use zeroize::{DefaultIsZeroes, Zeroize, ZeroizeOnDrop};
use crate::{
serialization::{SerializableElement, SerializableScalar},
Ciphersuite, Element, Error, Field, Group, Header, Identifier, Scalar, SigningKey,
VerifyingKey,
};
#[cfg(feature = "serialization")]
use crate::serialization::{Deserialize, Serialize};
use super::compute_lagrange_coefficient;
pub mod dkg;
pub mod refresh;
pub mod repairable;
#[cfg_attr(feature = "internals", visibility::make(pub))]
pub(crate) fn sum_commitments<C: Ciphersuite>(
commitments: &[&VerifiableSecretSharingCommitment<C>],
) -> Result<VerifiableSecretSharingCommitment<C>, Error<C>> {
let mut group_commitment = vec![
CoefficientCommitment::new(<C::Group>::identity());
commitments
.first()
.ok_or(Error::IncorrectNumberOfCommitments)?
.0
.len()
];
for commitment in commitments {
for (i, c) in group_commitment.iter_mut().enumerate() {
*c = CoefficientCommitment::new(
c.value()
+ commitment
.0
.get(i)
.ok_or(Error::IncorrectNumberOfCommitments)?
.value(),
);
}
}
Ok(VerifiableSecretSharingCommitment(group_commitment))
}
pub(crate) fn generate_coefficients<C: Ciphersuite, R: RngCore + CryptoRng>(
size: usize,
rng: &mut R,
) -> Vec<Scalar<C>> {
iter::repeat_with(|| <<C::Group as Group>::Field>::random(rng))
.take(size)
.collect()
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
pub(crate) fn default_identifiers<C: Ciphersuite>(max_signers: u16) -> Vec<Identifier<C>> {
(1..=max_signers)
.map(|i| Identifier::<C>::try_from(i).expect("nonzero"))
.collect::<Vec<_>>()
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct SigningShare<C: Ciphersuite>(pub(crate) SerializableScalar<C>);
impl<C> SigningShare<C>
where
C: Ciphersuite,
{
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn new(scalar: Scalar<C>) -> Self {
Self(SerializableScalar(scalar))
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn to_scalar(&self) -> Scalar<C> {
self.0 .0
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Ok(Self(SerializableScalar::deserialize(bytes)?))
}
pub fn serialize(&self) -> Vec<u8> {
self.0.serialize()
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
pub(crate) fn from_coefficients(coefficients: &[Scalar<C>], peer: Identifier<C>) -> Self {
Self::new(evaluate_polynomial(peer, coefficients))
}
}
impl<C> Debug for SigningShare<C>
where
C: Ciphersuite,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("SigningShare").field(&"<redacted>").finish()
}
}
impl<C> Default for SigningShare<C>
where
C: Ciphersuite,
{
fn default() -> Self {
Self::new(<<C::Group as Group>::Field>::zero())
}
}
impl<C> DefaultIsZeroes for SigningShare<C> where C: Ciphersuite {}
#[cfg(any(test, feature = "test-impl"))]
impl<C> FromHex for SigningShare<C>
where
C: Ciphersuite,
{
type Error = &'static str;
fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
let v: Vec<u8> = FromHex::from_hex(hex).map_err(|_| "invalid hex")?;
Self::deserialize(&v).map_err(|_| "malformed scalar")
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct VerifyingShare<C>(pub(super) SerializableElement<C>)
where
C: Ciphersuite;
impl<C> VerifyingShare<C>
where
C: Ciphersuite,
{
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn new(element: Element<C>) -> Self {
Self(SerializableElement(element))
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
#[allow(dead_code)]
pub(crate) fn to_element(&self) -> Element<C> {
self.0 .0
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Ok(Self(SerializableElement::deserialize(bytes)?))
}
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
self.0.serialize()
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
pub(crate) fn from_commitment(
identifier: Identifier<C>,
commitment: &VerifiableSecretSharingCommitment<C>,
) -> VerifyingShare<C> {
VerifyingShare::new(evaluate_vss(identifier, commitment))
}
}
impl<C> Debug for VerifyingShare<C>
where
C: Ciphersuite,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("VerifyingShare")
.field(
&self
.serialize()
.map(hex::encode)
.unwrap_or("<invalid>".to_string()),
)
.finish()
}
}
impl<C> From<SigningShare<C>> for VerifyingShare<C>
where
C: Ciphersuite,
{
fn from(secret: SigningShare<C>) -> VerifyingShare<C> {
VerifyingShare::new(<C::Group>::generator() * secret.to_scalar())
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
pub struct CoefficientCommitment<C: Ciphersuite>(pub(crate) SerializableElement<C>);
impl<C> CoefficientCommitment<C>
where
C: Ciphersuite,
{
#[cfg_attr(feature = "internals", visibility::make(pub))]
pub(crate) fn new(value: Element<C>) -> Self {
Self(SerializableElement(value))
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Ok(Self(SerializableElement::deserialize(bytes)?))
}
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
self.0.serialize()
}
pub fn value(&self) -> Element<C> {
self.0 .0
}
}
impl<C> Debug for CoefficientCommitment<C>
where
C: Ciphersuite,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("CoefficientCommitment")
.field(
&self
.serialize()
.map(hex::encode)
.unwrap_or("<invalid>".to_string()),
)
.finish()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
pub struct VerifiableSecretSharingCommitment<C: Ciphersuite>(
pub(crate) Vec<CoefficientCommitment<C>>,
);
impl<C> VerifiableSecretSharingCommitment<C>
where
C: Ciphersuite,
{
#[cfg_attr(feature = "internals", visibility::make(pub))]
pub(crate) fn new(coefficients: Vec<CoefficientCommitment<C>>) -> Self {
Self(coefficients)
}
pub fn serialize(&self) -> Result<Vec<Vec<u8>>, Error<C>> {
self.0
.iter()
.map(|cc| cc.serialize())
.collect::<Result<_, Error<C>>>()
}
pub fn serialize_whole(&self) -> Result<Vec<u8>, Error<C>> {
self.serialize().map(|v| v.concat())
}
pub fn deserialize<I, V>(serialized_coefficient_commitments: I) -> Result<Self, Error<C>>
where
I: IntoIterator<Item = V>,
V: AsRef<[u8]>,
{
let mut coefficient_commitments = Vec::new();
for cc in serialized_coefficient_commitments.into_iter() {
coefficient_commitments.push(CoefficientCommitment::<C>::deserialize(cc.as_ref())?);
}
Ok(Self::new(coefficient_commitments))
}
pub fn deserialize_whole(bytes: &[u8]) -> Result<Self, Error<C>> {
let generator = <C::Group>::generator();
let len = <C::Group>::serialize(&generator)
.expect("serializing the generator always works")
.as_ref()
.len();
let serialized_coefficient_commitments = bytes.chunks_exact(len);
if !serialized_coefficient_commitments.remainder().is_empty() {
return Err(Error::InvalidCoefficient);
}
Self::deserialize(serialized_coefficient_commitments)
}
pub(crate) fn verifying_key(&self) -> Result<VerifyingKey<C>, Error<C>> {
Ok(VerifyingKey::new(
self.0.first().ok_or(Error::MissingCommitment)?.0 .0,
))
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
pub(crate) fn coefficients(&self) -> &[CoefficientCommitment<C>] {
&self.0
}
pub(crate) fn min_signers(&self) -> u16 {
self.0.len() as u16
}
}
#[derive(Clone, Debug, Zeroize, PartialEq, Eq, Getters, ZeroizeOnDrop)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct SecretShare<C: Ciphersuite> {
#[getter(skip)]
pub(crate) header: Header<C>,
#[zeroize(skip)]
pub(crate) identifier: Identifier<C>,
pub(crate) signing_share: SigningShare<C>,
#[zeroize(skip)]
pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
}
impl<C> SecretShare<C>
where
C: Ciphersuite,
{
pub fn new(
identifier: Identifier<C>,
signing_share: SigningShare<C>,
commitment: VerifiableSecretSharingCommitment<C>,
) -> Self {
SecretShare {
header: Header::default(),
identifier,
signing_share,
commitment,
}
}
pub fn verify(&self) -> Result<(VerifyingShare<C>, VerifyingKey<C>), Error<C>> {
let f_result = <C::Group>::generator() * self.signing_share.to_scalar();
let result = evaluate_vss(self.identifier, &self.commitment);
if !(f_result == result) {
return Err(Error::InvalidSecretShare { culprit: None });
}
Ok((
VerifyingShare::new(result),
self.commitment.verifying_key()?,
))
}
}
#[cfg(feature = "serialization")]
impl<C> SecretShare<C>
where
C: Ciphersuite,
{
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
Serialize::serialize(&self)
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Deserialize::deserialize(bytes)
}
}
pub enum IdentifierList<'a, C: Ciphersuite> {
Default,
Custom(&'a [Identifier<C>]),
}
pub fn generate_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>(
max_signers: u16,
min_signers: u16,
identifiers: IdentifierList<C>,
rng: &mut R,
) -> Result<(BTreeMap<Identifier<C>, SecretShare<C>>, PublicKeyPackage<C>), Error<C>> {
let key = SigningKey::new(rng);
split(&key, max_signers, min_signers, identifiers, rng)
}
pub fn split<C: Ciphersuite, R: RngCore + CryptoRng>(
key: &SigningKey<C>,
max_signers: u16,
min_signers: u16,
identifiers: IdentifierList<C>,
rng: &mut R,
) -> Result<(BTreeMap<Identifier<C>, SecretShare<C>>, PublicKeyPackage<C>), Error<C>> {
validate_num_of_signers(min_signers, max_signers)?;
if let IdentifierList::Custom(identifiers) = &identifiers {
if identifiers.len() != max_signers as usize {
return Err(Error::IncorrectNumberOfIdentifiers);
}
}
let verifying_key = VerifyingKey::from(key);
let coefficients = generate_coefficients::<C, R>(min_signers as usize - 1, rng);
let secret_shares = match identifiers {
IdentifierList::Default => {
let identifiers = default_identifiers(max_signers);
generate_secret_shares(key, max_signers, min_signers, coefficients, &identifiers)?
}
IdentifierList::Custom(identifiers) => {
generate_secret_shares(key, max_signers, min_signers, coefficients, identifiers)?
}
};
let mut verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>> = BTreeMap::new();
let mut secret_shares_by_id: BTreeMap<Identifier<C>, SecretShare<C>> = BTreeMap::new();
for secret_share in secret_shares {
let signer_public = secret_share.signing_share.into();
verifying_shares.insert(secret_share.identifier, signer_public);
secret_shares_by_id.insert(secret_share.identifier, secret_share);
}
let public_key_package = PublicKeyPackage {
header: Header::default(),
verifying_shares,
verifying_key,
min_signers: Some(min_signers),
};
let (processed_secret_shares, processed_public_key_package) =
C::post_generate(secret_shares_by_id, public_key_package)?;
Ok((processed_secret_shares, processed_public_key_package))
}
fn evaluate_polynomial<C: Ciphersuite>(
identifier: Identifier<C>,
coefficients: &[Scalar<C>],
) -> Scalar<C> {
let mut value = <<C::Group as Group>::Field>::zero();
let ell = identifier;
for coeff in coefficients.iter().skip(1).rev() {
value = value + *coeff;
value = value * ell.to_scalar();
}
value = value
+ *coefficients
.first()
.expect("coefficients must have at least one element");
value
}
fn evaluate_vss<C: Ciphersuite>(
identifier: Identifier<C>,
commitment: &VerifiableSecretSharingCommitment<C>,
) -> Element<C> {
let i = identifier.to_scalar();
let (_, result) = commitment.0.iter().fold(
(<<C::Group as Group>::Field>::one(), <C::Group>::identity()),
|(i_to_the_k, sum_so_far), comm_k| {
(i * i_to_the_k, sum_so_far + comm_k.value() * i_to_the_k)
},
);
result
}
#[derive(Clone, Debug, PartialEq, Eq, Getters, Zeroize, ZeroizeOnDrop)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct KeyPackage<C: Ciphersuite> {
#[getter(skip)]
pub(crate) header: Header<C>,
#[zeroize(skip)]
pub(crate) identifier: Identifier<C>,
pub(crate) signing_share: SigningShare<C>,
#[zeroize(skip)]
pub(crate) verifying_share: VerifyingShare<C>,
#[zeroize(skip)]
pub(crate) verifying_key: VerifyingKey<C>,
pub(crate) min_signers: u16,
}
impl<C> KeyPackage<C>
where
C: Ciphersuite,
{
pub fn new(
identifier: Identifier<C>,
signing_share: SigningShare<C>,
verifying_share: VerifyingShare<C>,
verifying_key: VerifyingKey<C>,
min_signers: u16,
) -> Self {
Self {
header: Header::default(),
identifier,
signing_share,
verifying_share,
verifying_key,
min_signers,
}
}
}
#[cfg(feature = "serialization")]
impl<C> KeyPackage<C>
where
C: Ciphersuite,
{
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
Serialize::serialize(&self)
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Deserialize::deserialize(bytes)
}
}
impl<C> TryFrom<SecretShare<C>> for KeyPackage<C>
where
C: Ciphersuite,
{
type Error = Error<C>;
fn try_from(secret_share: SecretShare<C>) -> Result<Self, Error<C>> {
let (verifying_share, verifying_key) = secret_share.verify()?;
Ok(KeyPackage {
header: Header::default(),
identifier: secret_share.identifier,
signing_share: secret_share.signing_share,
verifying_share,
verifying_key,
min_signers: secret_share.commitment.min_signers(),
})
}
}
#[derive(Clone, Debug, PartialEq, Eq, Getters)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct PublicKeyPackage<C: Ciphersuite> {
#[getter(skip)]
pub(crate) header: Header<C>,
pub(crate) verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>>,
pub(crate) verifying_key: VerifyingKey<C>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(feature = "serde", serde(default))]
#[getter(copy)]
pub(crate) min_signers: Option<u16>,
}
impl<C> PublicKeyPackage<C>
where
C: Ciphersuite,
{
pub fn new(
verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>>,
verifying_key: VerifyingKey<C>,
min_signers: Option<u16>,
) -> Self {
Self::new_internal(verifying_shares, verifying_key, min_signers)
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn new_internal(
verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>>,
verifying_key: VerifyingKey<C>,
min_signers: Option<u16>,
) -> Self {
Self {
header: Header::default(),
verifying_shares,
verifying_key,
min_signers,
}
}
pub fn from_commitment(
identifiers: &BTreeSet<Identifier<C>>,
commitment: &VerifiableSecretSharingCommitment<C>,
) -> Result<PublicKeyPackage<C>, Error<C>> {
let verifying_keys: BTreeMap<_, _> = identifiers
.iter()
.map(|id| (*id, VerifyingShare::from_commitment(*id, commitment)))
.collect();
Ok(PublicKeyPackage::new(
verifying_keys,
VerifyingKey::from_commitment(commitment)?,
Some(commitment.min_signers()),
))
}
pub fn from_dkg_commitments(
commitments: &BTreeMap<Identifier<C>, &VerifiableSecretSharingCommitment<C>>,
) -> Result<PublicKeyPackage<C>, Error<C>> {
let identifiers: BTreeSet<_> = commitments.keys().copied().collect();
let commitments: Vec<_> = commitments.values().copied().collect();
let group_commitment = sum_commitments(&commitments)?;
Self::from_commitment(&identifiers, &group_commitment)
}
pub fn max_signers(&self) -> u16 {
self.verifying_shares.len() as u16
}
}
#[cfg(feature = "serialization")]
impl<C> PublicKeyPackage<C>
where
C: Ciphersuite,
{
pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
Serialize::serialize(&self)
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Deserialize::deserialize(bytes)
}
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
fn validate_num_of_signers<C: Ciphersuite>(
min_signers: u16,
max_signers: u16,
) -> Result<(), Error<C>> {
if min_signers < 2 {
return Err(Error::InvalidMinSigners);
}
if max_signers < 2 {
return Err(Error::InvalidMaxSigners);
}
if min_signers > max_signers {
return Err(Error::InvalidMinSigners);
}
Ok(())
}
pub(crate) fn generate_secret_polynomial<C: Ciphersuite>(
secret: &SigningKey<C>,
max_signers: u16,
min_signers: u16,
mut coefficients: Vec<Scalar<C>>,
) -> Result<(Vec<Scalar<C>>, VerifiableSecretSharingCommitment<C>), Error<C>> {
validate_num_of_signers(min_signers, max_signers)?;
if coefficients.len() != min_signers as usize - 1 {
return Err(Error::InvalidCoefficients);
}
coefficients.insert(0, secret.scalar);
let commitment: Vec<_> = coefficients
.iter()
.map(|c| CoefficientCommitment::new(<C::Group as Group>::generator() * *c))
.collect();
let commitment: VerifiableSecretSharingCommitment<C> =
VerifiableSecretSharingCommitment(commitment);
Ok((coefficients, commitment))
}
pub(crate) fn generate_secret_shares<C: Ciphersuite>(
secret: &SigningKey<C>,
max_signers: u16,
min_signers: u16,
coefficients: Vec<Scalar<C>>,
identifiers: &[Identifier<C>],
) -> Result<Vec<SecretShare<C>>, Error<C>> {
let mut secret_shares: Vec<SecretShare<C>> = Vec::with_capacity(max_signers as usize);
let (coefficients, commitment) =
generate_secret_polynomial(secret, max_signers, min_signers, coefficients)?;
let identifiers_set: BTreeSet<_> = identifiers.iter().collect();
if identifiers_set.len() != identifiers.len() {
return Err(Error::DuplicatedIdentifier);
}
for id in identifiers {
let signing_share = SigningShare::from_coefficients(&coefficients, *id);
secret_shares.push(SecretShare {
header: Header::default(),
identifier: *id,
signing_share,
commitment: commitment.clone(),
});
}
Ok(secret_shares)
}
pub fn reconstruct<C: Ciphersuite>(
key_packages: &[KeyPackage<C>],
) -> Result<SigningKey<C>, Error<C>> {
if key_packages.is_empty() {
return Err(Error::IncorrectNumberOfShares);
}
let min_signers = key_packages
.iter()
.map(|k| k.min_signers)
.min()
.expect("should not be empty since that was just tested");
if key_packages.len() < min_signers as usize {
return Err(Error::IncorrectNumberOfShares);
}
let mut secret = <<C::Group as Group>::Field>::zero();
let identifiers: BTreeSet<_> = key_packages
.iter()
.map(|s| s.identifier())
.cloned()
.collect();
if identifiers.len() != key_packages.len() {
return Err(Error::DuplicatedIdentifier);
}
for key_package in key_packages.iter() {
let lagrange_coefficient =
compute_lagrange_coefficient(&identifiers, None, key_package.identifier)?;
secret = secret + (lagrange_coefficient * key_package.signing_share().to_scalar());
}
Ok(SigningKey { scalar: secret })
}