#![no_std]
#![allow(non_snake_case)]
extern crate alloc;
#[cfg(any(test, feature = "test-impl"))]
pub mod tests;
use alloc::{collections::BTreeMap, string::ToString, vec::Vec};
use derive_getters::Getters;
pub use frost_core;
#[cfg(feature = "serialization")]
use frost_core::SigningPackage;
use frost_core::{
self as frost,
keys::{KeyPackage, PublicKeyPackage, SigningShare, VerifyingShare},
round1::{encode_group_commitments, SigningCommitments},
serialization::SerializableScalar,
CheaterDetection, Ciphersuite, Error, Field, Group, Identifier, Scalar, VerifyingKey,
};
#[cfg(feature = "serde")]
use frost_core::serde;
use rand_core::{CryptoRng, RngCore};
trait Randomize<C> {
fn randomize(&self, params: &RandomizedParams<C>) -> Result<Self, Error<C>>
where
Self: Sized,
C: Ciphersuite;
}
pub trait RandomizedCiphersuite: Ciphersuite {
fn hash_randomizer(m: &[u8]) -> Option<<<Self::Group as Group>::Field as Field>::Scalar>;
}
impl<C: Ciphersuite> Randomize<C> for KeyPackage<C> {
fn randomize(&self, randomized_params: &RandomizedParams<C>) -> Result<Self, Error<C>>
where
Self: Sized,
C: Ciphersuite,
{
let verifying_share = self.verifying_share();
let randomized_verifying_share = VerifyingShare::<C>::new(
verifying_share.to_element() + randomized_params.randomizer_element,
);
let signing_share = self.signing_share();
let randomized_signing_share =
SigningShare::new(signing_share.to_scalar() + randomized_params.randomizer.to_scalar());
let randomized_key_package = KeyPackage::new(
*self.identifier(),
randomized_signing_share,
randomized_verifying_share,
randomized_params.randomized_verifying_key,
*self.min_signers(),
);
Ok(randomized_key_package)
}
}
impl<C: Ciphersuite> Randomize<C> for PublicKeyPackage<C> {
fn randomize(&self, randomized_params: &RandomizedParams<C>) -> Result<Self, Error<C>>
where
Self: Sized,
C: Ciphersuite,
{
let verifying_shares = self.verifying_shares().clone();
let randomized_verifying_shares = verifying_shares
.iter()
.map(|(identifier, verifying_share)| {
(
*identifier,
VerifyingShare::<C>::new(
verifying_share.to_element() + randomized_params.randomizer_element,
),
)
})
.collect();
Ok(PublicKeyPackage::new_internal(
randomized_verifying_shares,
randomized_params.randomized_verifying_key,
self.min_signers(),
))
}
}
#[deprecated(
note = "switch to sign_with_randomizer_seed(), passing a seed generated with RandomizedParams::new_from_commitments()"
)]
pub fn sign<C: RandomizedCiphersuite>(
signing_package: &frost::SigningPackage<C>,
signer_nonces: &frost::round1::SigningNonces<C>,
key_package: &frost::keys::KeyPackage<C>,
randomizer: Randomizer<C>,
) -> Result<frost::round2::SignatureShare<C>, Error<C>> {
let randomized_params =
RandomizedParams::from_randomizer(key_package.verifying_key(), randomizer);
let randomized_key_package = key_package.randomize(&randomized_params)?;
frost::round2::sign(signing_package, signer_nonces, &randomized_key_package)
}
pub fn sign_with_randomizer_seed<C: RandomizedCiphersuite>(
signing_package: &frost::SigningPackage<C>,
signer_nonces: &frost::round1::SigningNonces<C>,
key_package: &frost::keys::KeyPackage<C>,
randomizer_seed: &[u8],
) -> Result<frost::round2::SignatureShare<C>, Error<C>> {
let randomized_params = RandomizedParams::regenerate_from_seed_and_commitments(
key_package.verifying_key(),
randomizer_seed,
signing_package.signing_commitments(),
)?;
let randomized_key_package = key_package.randomize(&randomized_params)?;
frost::round2::sign(signing_package, signer_nonces, &randomized_key_package)
}
pub fn aggregate<C>(
signing_package: &frost::SigningPackage<C>,
signature_shares: &BTreeMap<frost::Identifier<C>, frost::round2::SignatureShare<C>>,
pubkeys: &frost::keys::PublicKeyPackage<C>,
randomized_params: &RandomizedParams<C>,
) -> Result<frost_core::Signature<C>, Error<C>>
where
C: Ciphersuite,
{
let randomized_public_key_package = pubkeys.randomize(randomized_params)?;
frost::aggregate(
signing_package,
signature_shares,
&randomized_public_key_package,
)
}
pub fn aggregate_custom<C>(
signing_package: &frost::SigningPackage<C>,
signature_shares: &BTreeMap<frost::Identifier<C>, frost::round2::SignatureShare<C>>,
pubkeys: &frost::keys::PublicKeyPackage<C>,
cheater_detection: CheaterDetection,
randomized_params: &RandomizedParams<C>,
) -> Result<frost_core::Signature<C>, Error<C>>
where
C: Ciphersuite,
{
let randomized_public_key_package = pubkeys.randomize(randomized_params)?;
frost::aggregate_custom(
signing_package,
signature_shares,
&randomized_public_key_package,
cheater_detection,
)
}
#[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))]
#[cfg_attr(feature = "serde", serde(crate = "self::serde"))]
pub struct Randomizer<C: Ciphersuite>(SerializableScalar<C>);
impl<C> Randomizer<C>
where
C: Ciphersuite,
{
pub(crate) fn to_scalar(self) -> Scalar<C> {
self.0 .0
}
}
impl<C> Randomizer<C>
where
C: RandomizedCiphersuite,
{
#[cfg(feature = "serialization")]
#[deprecated(
note = "switch to new_from_commitments(), passing the commitments from SigningPackage"
)]
pub fn new<R: RngCore + CryptoRng>(
mut rng: R,
signing_package: &SigningPackage<C>,
) -> Result<Self, Error<C>> {
let rng_randomizer = <<C::Group as Group>::Field as Field>::random(&mut rng);
Self::from_randomizer_and_signing_package(rng_randomizer, signing_package)
}
#[cfg(feature = "serialization")]
fn from_randomizer_and_signing_package(
rng_randomizer: <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar,
signing_package: &SigningPackage<C>,
) -> Result<Randomizer<C>, Error<C>>
where
C: RandomizedCiphersuite,
{
let randomizer = C::hash_randomizer(
&[
<<C::Group as Group>::Field>::serialize(&rng_randomizer).as_ref(),
&signing_package.serialize()?,
]
.concat(),
)
.ok_or(Error::SerializationError)?;
Ok(Self(SerializableScalar(randomizer)))
}
pub fn new_from_commitments<R: RngCore + CryptoRng>(
mut rng: R,
signing_commitments: &BTreeMap<Identifier<C>, SigningCommitments<C>>,
) -> Result<(Self, Vec<u8>), Error<C>> {
let zero = <<C::Group as Group>::Field as Field>::zero();
let ns = <<C::Group as Group>::Field as Field>::serialize(&zero)
.as_ref()
.len();
let mut randomizer_seed = alloc::vec![0; ns];
rng.fill_bytes(&mut randomizer_seed);
Ok((
Self::regenerate_from_seed_and_commitments(&randomizer_seed, signing_commitments)?,
randomizer_seed,
))
}
pub fn regenerate_from_seed_and_commitments(
randomizer_seed: &[u8],
signing_commitments: &BTreeMap<Identifier<C>, SigningCommitments<C>>,
) -> Result<Randomizer<C>, Error<C>>
where
C: RandomizedCiphersuite,
{
let randomizer = C::hash_randomizer(
&[
randomizer_seed,
&encode_group_commitments(signing_commitments)?,
]
.concat(),
)
.ok_or(Error::SerializationError)?;
Ok(Self(SerializableScalar(randomizer)))
}
}
impl<C> Randomizer<C>
where
C: Ciphersuite,
{
pub fn from_scalar(scalar: Scalar<C>) -> Self {
Self(SerializableScalar(scalar))
}
pub fn serialize(&self) -> Vec<u8> {
self.0.serialize()
}
pub fn deserialize(buf: &[u8]) -> Result<Self, Error<C>> {
Ok(Self(SerializableScalar::deserialize(buf)?))
}
}
impl<C> core::fmt::Debug for Randomizer<C>
where
C: Ciphersuite,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Randomizer")
.field(&hex::encode(self.0.serialize()))
.finish()
}
}
#[derive(Clone, PartialEq, Eq, Getters)]
pub struct RandomizedParams<C: Ciphersuite> {
randomizer: Randomizer<C>,
randomizer_element: <C::Group as Group>::Element,
randomized_verifying_key: frost_core::VerifyingKey<C>,
}
impl<C> RandomizedParams<C>
where
C: RandomizedCiphersuite,
{
#[cfg(feature = "serialization")]
#[deprecated(
note = "switch to new_from_commitments(), passing the commitments from SigningPackage"
)]
pub fn new<R: RngCore + CryptoRng>(
group_verifying_key: &VerifyingKey<C>,
signing_package: &SigningPackage<C>,
rng: R,
) -> Result<Self, Error<C>> {
#[allow(deprecated)]
Ok(Self::from_randomizer(
group_verifying_key,
Randomizer::new(rng, signing_package)?,
))
}
pub fn new_from_commitments<R: RngCore + CryptoRng>(
group_verifying_key: &VerifyingKey<C>,
signing_commitments: &BTreeMap<Identifier<C>, SigningCommitments<C>>,
rng: R,
) -> Result<(Self, Vec<u8>), Error<C>> {
let (randomizer, randomizer_seed) =
Randomizer::new_from_commitments(rng, signing_commitments)?;
Ok((
Self::from_randomizer(group_verifying_key, randomizer),
randomizer_seed,
))
}
pub fn regenerate_from_seed_and_commitments(
group_verifying_key: &VerifyingKey<C>,
randomizer_seed: &[u8],
signing_commitments: &BTreeMap<Identifier<C>, SigningCommitments<C>>,
) -> Result<Self, Error<C>> {
let randomizer =
Randomizer::regenerate_from_seed_and_commitments(randomizer_seed, signing_commitments)?;
Ok(Self::from_randomizer(group_verifying_key, randomizer))
}
}
impl<C> RandomizedParams<C>
where
C: Ciphersuite,
{
pub fn from_randomizer(
group_verifying_key: &VerifyingKey<C>,
randomizer: Randomizer<C>,
) -> Self {
let randomizer_element = <C::Group as Group>::generator() * randomizer.to_scalar();
let verifying_key_element = group_verifying_key.to_element();
let randomized_verifying_key_element = verifying_key_element + randomizer_element;
let randomized_verifying_key = VerifyingKey::<C>::new(randomized_verifying_key_element);
Self {
randomizer,
randomizer_element,
randomized_verifying_key,
}
}
}
impl<C> core::fmt::Debug for RandomizedParams<C>
where
C: Ciphersuite,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("RandomizedParams")
.field("randomizer", &self.randomizer)
.field(
"randomizer_element",
&<C::Group as Group>::serialize(&self.randomizer_element)
.map(hex::encode)
.unwrap_or("<invalid>".to_string()),
)
.field("randomized_verifying_key", &self.randomized_verifying_key)
.finish()
}
}