#[macro_use] mod macros; mod crypto; pub mod participants; pub mod confidential_key_derivation; pub mod ecdsa; pub mod errors; pub mod frost; #[cfg(feature = "test-utils")] pub mod test_utils; // TODO: We should probably no expose the full modules, but only the types // that make sense for our library pub use blstrs; pub use frost_core; pub use frost_ed25519; pub use frost_secp256k1; pub use crypto::ciphersuite::Ciphersuite; pub use participants::ParticipantList; // For benchmark pub use crypto::polynomials::{ batch_compute_lagrange_coefficients, batch_invert, compute_lagrange_coefficient, }; use zeroize::ZeroizeOnDrop; mod dkg; pub mod protocol; mod thresholds; use crate::dkg::{assert_key_invariants, assert_reshare_keys_invariants, do_keygen, do_reshare}; use crate::errors::InitializationError; use crate::participants::Participant; use crate::protocol::Protocol; use crate::protocol::internal::{Comms, make_protocol}; pub use crate::thresholds::{MaxMalicious, ReconstructionThreshold}; use rand_core::CryptoRngCore; use std::marker::Send; use frost_core::serialization::SerializableScalar; use frost_core::{Group, VerifyingKey, keys::SigningShare}; use serde::{Deserialize, Serialize}; pub type Scalar = frost_core::Scalar; pub type Element = frost_core::Element; #[derive(Clone, Deserialize, Serialize, Eq, PartialEq, ZeroizeOnDrop)] #[serde(bound = "C: Ciphersuite")] /// Generic type of key pairs pub struct KeygenOutput { pub private_share: SigningShare, #[zeroize(skip)] pub public_key: VerifyingKey, } impl_secret_debug!({C: Ciphersuite} KeygenOutput { show: [public_key], redact: [private_share] }); /// This is a necessary element to be able to derive different keys /// from signing shares. /// We do not bind the user with the way to compute the inner scalar of the tweak #[derive(Copy, Clone, Deserialize, Serialize, Eq, PartialEq)] #[serde(bound = "C: Ciphersuite")] pub struct Tweak(SerializableScalar); impl Tweak { pub fn new(tweak: Scalar) -> Self { Self(SerializableScalar(tweak)) } /// Outputs the inner value of the tweak pub fn value(&self) -> Scalar { self.0.0 } /// Derives the signing share as x + tweak pub fn derive_signing_share(&self, private_share: &SigningShare) -> SigningShare { let derived_share = private_share.to_scalar() + self.value(); SigningShare::new(derived_share) } /// Derives the verifying key as X + tweak . G pub fn derive_verifying_key(&self, public_key: &VerifyingKey) -> VerifyingKey { let derived_share = public_key.to_element() + C::Group::generator() * self.value(); VerifyingKey::new(derived_share) } } /// Maximum incoming buffer entries for keygen, reshare, and refresh protocols. pub(crate) const DKG_MAX_INCOMING_BUFFER_ENTRIES: usize = 5; /// Generic key generation function agnostic of the curve pub fn keygen( participants: &[Participant], me: Participant, threshold: T, rng: R, ) -> Result> + use, InitializationError> where C: Ciphersuite, T: Into + Send + Copy + 'static, R: CryptoRngCore + Send + 'static, { let comms = Comms::with_buffer_capacity(DKG_MAX_INCOMING_BUFFER_ENTRIES); let participants = assert_key_invariants(participants, me, threshold)?; let fut = do_keygen::(comms.shared_channel(), participants, me, threshold, rng); Ok(make_protocol(comms, fut)) } /// Performs the key reshare protocol #[allow(clippy::too_many_arguments)] pub fn reshare( old_participants: &[Participant], old_threshold: OT, old_signing_key: Option>, old_public_key: VerifyingKey, new_participants: &[Participant], new_threshold: NT, me: Participant, rng: R, ) -> Result> + use, InitializationError> where C: Ciphersuite, OT: Into + Send + 'static, NT: Into + Copy + Send + 'static, R: CryptoRngCore + Send + 'static, { let comms = Comms::with_buffer_capacity(DKG_MAX_INCOMING_BUFFER_ENTRIES); let threshold = new_threshold; let (participants, old_participants) = assert_reshare_keys_invariants::( new_participants, me, threshold, old_signing_key, old_threshold, old_participants, )?; let fut = do_reshare( comms.shared_channel(), participants, me, threshold, old_signing_key, old_public_key, old_participants, rng, ); Ok(make_protocol(comms, fut)) } /// Performs the refresh protocol pub fn refresh( old_signing_key: Option>, old_public_key: VerifyingKey, old_participants: &[Participant], old_threshold: T, me: Participant, rng: R, ) -> Result> + use, InitializationError> where C: Ciphersuite, T: Into + Copy + Send + 'static, R: CryptoRngCore + Send + 'static, { if old_signing_key.is_none() { return Err(InitializationError::BadParameters(format!( "The participant {me:?} is running refresh without an old share", ))); } let comms = Comms::with_buffer_capacity(DKG_MAX_INCOMING_BUFFER_ENTRIES); // NOTE: this equality must be kept, as changing the threshold during `key refresh` // might lead to insecure scenarios. For more information see https://github.com/ZcashFoundation/frost/security/advisories/GHSA-wgq8-vr6r-mqxm let threshold = old_threshold; let (participants, old_participants) = assert_reshare_keys_invariants::( old_participants, me, threshold, old_signing_key, threshold, old_participants, )?; let fut = do_reshare( comms.shared_channel(), participants, me, threshold, old_signing_key, old_public_key, old_participants, rng, ); Ok(make_protocol(comms, fut)) }