rename keys::{Secret, Public} (#106)

* rename keys::{Secret, Public} to SecretShareValue, PublicVerificationShare

* Add SharedSecret; rename types to SigningShare, VerifyingShare

* Tidy rustdoc

* round2 rustdoc

* Happy rustdoc

* Remove commented out random() associated function for SigningShare

Co-authored-by: Deirdre Connolly <durumcrustulum@gmail.com>
This commit is contained in:
Conrado Gouvea 2022-09-15 13:15:53 -03:00 committed by GitHub
parent 6de0e09b87
commit d0c969d40a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 130 additions and 79 deletions

View File

@ -17,10 +17,3 @@ scratch. End-users should not use `frost-core` if they want to sign and verify s
should use the crate specific to their ciphersuite/curve parameters that uses `frost-core` as a
dependency, such as `frost-ristretto255`.
## Example
```rust
```

View File

@ -13,22 +13,26 @@ use zeroize::{DefaultIsZeroes, Zeroize};
use crate::{frost::Identifier, Ciphersuite, Error, Field, Group, Scalar, VerifyingKey};
/// A secret scalar value representing a signer's secret key.
/// A group secret to be split between participants.
///
/// This is similar to a [`crate::SigningKey`], but this secret is not intended to be used
/// on its own for signing, but split into shares that a threshold number of signers will use to
/// sign.
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Secret<C: Ciphersuite>(pub(crate) Scalar<C>);
pub struct SharedSecret<C: Ciphersuite>(pub(crate) Scalar<C>);
impl<C> Secret<C>
impl<C> SharedSecret<C>
where
C: Ciphersuite,
{
/// Deserialize [`Secret`] from bytes
/// Deserialize from bytes
pub fn from_bytes(
bytes: <<C::Group as Group>::Field as Field>::Serialization,
) -> Result<Self, Error> {
<<C::Group as Group>::Field as Field>::deserialize(&bytes).map(|scalar| Self(scalar))
}
/// Serialize [`Secret`] to bytes
/// Serialize to bytes
pub fn to_bytes(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
<<C::Group as Group>::Field as Field>::serialize(&self.0)
}
@ -45,18 +49,18 @@ where
}
}
impl<C> Debug for Secret<C>
impl<C> Debug for SharedSecret<C>
where
C: Ciphersuite,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Secret")
f.debug_tuple("SharedSecret")
.field(&hex::encode(self.to_bytes()))
.finish()
}
}
impl<C> Default for Secret<C>
impl<C> Default for SharedSecret<C>
where
C: Ciphersuite,
{
@ -66,29 +70,20 @@ where
}
// Implements [`Zeroize`] by overwriting a value with the [`Default::default()`] value
impl<C> DefaultIsZeroes for Secret<C> where C: Ciphersuite {}
impl<C> DefaultIsZeroes for SharedSecret<C> where C: Ciphersuite {}
// impl<C> Drop for Secret<C>
// where
// C: Ciphersuite,
// {
// fn drop(&mut self) {
// self.zeroize()
// }
// }
impl<C> From<&Secret<C>> for VerifyingKey<C>
impl<C> From<&SharedSecret<C>> for VerifyingKey<C>
where
C: Ciphersuite,
{
fn from(secret: &Secret<C>) -> Self {
fn from(secret: &SharedSecret<C>) -> Self {
let element = <C::Group as Group>::generator() * secret.0;
VerifyingKey { element }
}
}
impl<C> FromHex for Secret<C>
impl<C> FromHex for SharedSecret<C>
where
C: Ciphersuite,
{
@ -103,13 +98,72 @@ where
}
}
/// A public group element that represents a single signer's public key.
/// A secret scalar value representing a signer's share of the group secret.
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct SigningShare<C: Ciphersuite>(pub(crate) Scalar<C>);
impl<C> SigningShare<C>
where
C: Ciphersuite,
{
/// Deserialize from bytes
pub fn from_bytes(
bytes: <<C::Group as Group>::Field as Field>::Serialization,
) -> Result<Self, Error> {
<<C::Group as Group>::Field as Field>::deserialize(&bytes).map(|scalar| Self(scalar))
}
/// Serialize to bytes
pub fn to_bytes(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
<<C::Group as Group>::Field as Field>::serialize(&self.0)
}
}
impl<C> Debug for SigningShare<C>
where
C: Ciphersuite,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("SigningShare")
.field(&hex::encode(self.to_bytes()))
.finish()
}
}
impl<C> Default for SigningShare<C>
where
C: Ciphersuite,
{
fn default() -> Self {
Self(<<C::Group as Group>::Field as Field>::zero())
}
}
// Implements [`Zeroize`] by overwriting a value with the [`Default::default()`] value
impl<C> DefaultIsZeroes for SigningShare<C> where C: Ciphersuite {}
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")?;
match v.try_into() {
Ok(bytes) => Self::from_bytes(bytes).map_err(|_| "malformed secret encoding"),
Err(_) => Err("malformed secret encoding"),
}
}
}
/// A public group element that represents a single signer's public verification share.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Public<C>(pub(super) <C::Group as Group>::Element)
pub struct VerifyingShare<C>(pub(super) <C::Group as Group>::Element)
where
C: Ciphersuite;
impl<C> Public<C>
impl<C> VerifyingShare<C>
where
C: Ciphersuite,
{
@ -118,33 +172,33 @@ where
<C::Group as Group>::deserialize(&bytes).map(|element| Self(element))
}
/// Serialize [`Public`] to bytes
/// Serialize to bytes
pub fn to_bytes(&self) -> <C::Group as Group>::Serialization {
<C::Group as Group>::serialize(&self.0)
}
}
impl<C> Debug for Public<C>
impl<C> Debug for VerifyingShare<C>
where
C: Ciphersuite,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Public")
f.debug_tuple("VerifyingShare")
.field(&hex::encode(self.to_bytes()))
.finish()
}
}
impl<C> From<Secret<C>> for Public<C>
impl<C> From<SigningShare<C>> for VerifyingShare<C>
where
C: Ciphersuite,
{
fn from(secret: Secret<C>) -> Public<C> {
Public(<C::Group as Group>::generator() * secret.0 as Scalar<C>)
fn from(secret: SigningShare<C>) -> VerifyingShare<C> {
VerifyingShare(<C::Group as Group>::generator() * secret.0 as Scalar<C>)
}
}
/// A [`Group::Element`] that is a commitment to one coefficient of our secret polynomial.
/// A [`Group::Element`] newtype that is a commitment to one coefficient of our secret polynomial.
///
/// This is a (public) commitment to one coefficient of a secret polynomial used for performing
/// verifiable secret sharing for a Shamir secret share.
@ -180,7 +234,7 @@ pub struct SecretShare<C: Ciphersuite> {
/// The participant identifier of this [`SecretShare`].
pub identifier: Identifier<C>,
/// Secret Key.
pub value: Secret<C>,
pub value: SigningShare<C>,
/// The commitments to be distributed among signers.
pub commitment: VerifiableSecretSharingCommitment<C>,
}
@ -189,8 +243,8 @@ impl<C> SecretShare<C>
where
C: Ciphersuite,
{
/// Gets the inner [`Secret`] share value.
pub fn secret(&self) -> &Secret<C> {
/// Gets the inner [`SigningShare`] value.
pub fn secret(&self) -> &SigningShare<C> {
&self.value
}
@ -237,8 +291,8 @@ pub struct SharePackage<C: Ciphersuite> {
/// This participant's secret share.
pub secret_share: SecretShare<C>,
/// This participant's public key.
pub public: Public<C>,
/// The public signing key that represents the entire group.
pub public: VerifyingShare<C>,
/// The public verifying key that represents the entire group.
pub group_public: VerifyingKey<C>,
}
@ -262,11 +316,11 @@ pub fn keygen_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>(
let mut bytes = [0; 64];
rng.fill_bytes(&mut bytes);
let secret = Secret::random(&mut rng);
let secret = SharedSecret::random(&mut rng);
let group_public = VerifyingKey::from(&secret);
let secret_shares = generate_secret_shares(&secret, num_signers, threshold, rng)?;
let mut share_packages: Vec<SharePackage<C>> = Vec::with_capacity(num_signers as usize);
let mut signer_pubkeys: HashMap<Identifier<C>, Public<C>> =
let mut signer_pubkeys: HashMap<Identifier<C>, VerifyingShare<C>> =
HashMap::with_capacity(num_signers as usize);
for secret_share in secret_shares {
@ -302,9 +356,9 @@ pub struct KeyPackage<C: Ciphersuite> {
/// Denotes the participant identifier each secret share key package is owned by.
pub identifier: Identifier<C>,
/// This participant's secret share.
pub secret_share: Secret<C>,
pub secret_share: SigningShare<C>,
/// This participant's public key.
pub public: Public<C>,
pub public: VerifyingShare<C>,
/// The public signing key that represents the entire group.
pub group_public: VerifyingKey<C>,
}
@ -318,13 +372,13 @@ where
&self.identifier
}
/// Gets the participant's [`Secret`] share associated with this [`KeyPackage`].
pub fn secret_share(&self) -> &Secret<C> {
/// Gets the participant's [`SigningShare`] associated with this [`KeyPackage`].
pub fn secret_share(&self) -> &SigningShare<C> {
&self.secret_share
}
/// Gets the participant's [`Public`] key associated with this [`Secret`] share in this [`KeyPackage`].
pub fn public(&self) -> &Public<C> {
/// Gets the participant's [`VerifyingShare`] associated with the [`SigningShare`] in this [`KeyPackage`].
pub fn public(&self) -> &VerifyingShare<C> {
&self.public
}
@ -369,7 +423,7 @@ pub struct PublicKeyPackage<C: Ciphersuite> {
/// correct view of participants' public keys to perform verification before
/// publishing a signature. `signer_pubkeys` represents all signers for a
/// signing operation.
pub signer_pubkeys: HashMap<Identifier<C>, Public<C>>,
pub signer_pubkeys: HashMap<Identifier<C>, VerifyingShare<C>>,
/// The joint public key for the entire group.
pub group_public: VerifyingKey<C>,
}
@ -394,7 +448,7 @@ pub struct PublicKeyPackage<C: Ciphersuite> {
///
/// [`secret_key_shard`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-03.html#appendix-B.1
pub fn generate_secret_shares<C: Ciphersuite, R: RngCore + CryptoRng>(
secret: &Secret<C>,
secret: &SharedSecret<C>,
numshares: u8,
threshold: u8,
mut rng: R,
@ -456,7 +510,7 @@ pub fn generate_secret_shares<C: Ciphersuite, R: RngCore + CryptoRng>(
secret_shares.push(SecretShare {
identifier: id,
value: Secret(value),
value: SigningShare(value),
commitment: commitment.clone(),
});
}
@ -467,7 +521,7 @@ pub fn generate_secret_shares<C: Ciphersuite, R: RngCore + CryptoRng>(
/// Recompute the secret from t-of-n secret shares using Lagrange interpolation.
pub fn reconstruct_secret<C: Ciphersuite>(
secret_shares: Vec<SecretShare<C>>,
) -> Result<Secret<C>, &'static str> {
) -> Result<SharedSecret<C>, &'static str> {
if secret_shares.is_empty() {
return Err("No secret_shares provided");
}
@ -512,5 +566,8 @@ pub fn reconstruct_secret<C: Ciphersuite>(
secret = secret + (lagrange_coefficient * secret_share.value.0);
}
Ok(Secret::from_bytes(<<C::Group as Group>::Field as Field>::serialize(&secret)).unwrap())
Ok(
SharedSecret::from_bytes(<<C::Group as Group>::Field as Field>::serialize(&secret))
.unwrap(),
)
}

View File

@ -8,7 +8,7 @@ use zeroize::Zeroize;
use crate::{frost, Ciphersuite, Error, Field, Group};
use super::{keys::Secret, Identifier};
use super::{keys::SigningShare, Identifier};
/// A scalar that is a signing nonce.
#[derive(Clone, PartialEq, Eq, Zeroize)]
@ -18,9 +18,8 @@ impl<C> Nonce<C>
where
C: Ciphersuite,
{
/// Generates a new uniformly random signing nonce by sourcing fresh
/// randomness and combining with the secret key, to hedge against a bad
/// RNG.
/// Generates a new uniformly random signing nonce by sourcing fresh randomness and combining
/// with the secret signing share, to hedge against a bad RNG.
///
/// Each participant generates signing nonces before performing a signing
/// operation.
@ -28,7 +27,7 @@ where
/// An implementation of `nonce_generate(secret)` from the [spec].
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#name-nonce-generation
pub fn new<R>(secret: &Secret<C>, rng: &mut R) -> Self
pub fn new<R>(secret: &SigningShare<C>, rng: &mut R) -> Self
where
R: CryptoRng + RngCore,
{
@ -167,7 +166,7 @@ where
///
/// Each participant generates signing nonces before performing a signing
/// operation.
pub fn new<R>(secret: &Secret<C>, rng: &mut R) -> Self
pub fn new<R>(secret: &SigningShare<C>, rng: &mut R) -> Self
where
R: CryptoRng + RngCore,
{
@ -301,7 +300,7 @@ pub(super) fn encode_group_commitments<C: Ciphersuite>(
pub fn preprocess<C, R>(
num_nonces: u8,
participant_identifier: Identifier<C>,
secret: &Secret<C>,
secret: &SigningShare<C>,
rng: &mut R,
) -> (Vec<SigningNonces<C>>, Vec<SigningCommitments<C>>)
where
@ -331,7 +330,7 @@ where
/// [`commit`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-5.1
pub fn commit<C, R>(
participant_identifier: Identifier<C>,
secret: &Secret<C>,
secret: &SigningShare<C>,
rng: &mut R,
) -> (SigningNonces<C>, SigningCommitments<C>)
where

View File

@ -11,7 +11,7 @@ use crate::{
/// A representation of a single signature share used in FROST structures and messages.
#[derive(Clone, Copy)]
pub struct SignatureResponse<C: Ciphersuite> {
/// The [`Scalar`] contribution to the group signature.
/// The scalar contribution to the group signature.
pub z_share: <<C::Group as Group>::Field as Field>::Scalar,
}
@ -84,7 +84,7 @@ where
pub fn verify(
&self,
group_commitment_share: &round1::GroupCommitmentShare<C>,
public_key: &frost::keys::Public<C>,
public_key: &frost::keys::VerifyingShare<C>,
lambda_i: <<C::Group as Group>::Field as Field>::Scalar,
challenge: &Challenge<C>,
) -> Result<(), &'static str> {

View File

@ -79,7 +79,7 @@ pub trait Field: Copy + Clone {
/// A member function of a [`Field`] that attempts to map a byte array `buf` to a [`Scalar`].
///
/// Fails if the input is not a valid byte representation of an [`Scalar`] of the
/// [`Field`]. This function can raise a [`DeserializeError`] if deserialization fails or if the
/// [`Field`]. This function can raise an [`Error`] if deserialization fails or if the
/// resulting [`Scalar`] is zero
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-3.1-3.8>
@ -130,7 +130,8 @@ pub trait Group: Copy + Clone + PartialEq {
/// The fixed generator element of the prime order group.
///
/// The 'base' of [`ScalarBaseMult()`] from the spec.
/// The 'base' of ['ScalarBaseMult()'] from the spec.
///
/// [`ScalarBaseMult()`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-3.1
fn generator() -> Self::Element;
@ -143,7 +144,7 @@ pub trait Group: Copy + Clone + PartialEq {
/// A member function of a [`Group`] that attempts to map a byte array `buf` to an [`Element`].
///
/// Fails if the input is not a valid byte representation of an [`Element`] of the
/// [`Group`]. This function can raise a [`DeserializeError`] if deserialization fails or if the
/// [`Group`]. This function can raise an [`Error`] if deserialization fails or if the
/// resulting [`Element`] is the identity element of the group
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-3.1-3.6>

View File

@ -20,7 +20,7 @@ where
C::Group: Group,
<C::Group as Group>::Field: Field,
{
/// Converts bytes as [`C::SignatureSerialization`] into a `Signature<C>`.
/// Converts bytes as [`Ciphersuite::SignatureSerialization`] into a `Signature<C>`.
pub fn from_bytes(bytes: C::SignatureSerialization) -> Result<Self, Error> {
// To compute the expected length of the encoded point, encode the generator
// and get its length. Note that we can't use the identity because it can be encoded
@ -50,7 +50,7 @@ where
})
}
/// Converts this signature to its [`C::SignatureSerialization`] in bytes.
/// Converts this signature to its [`Ciphersuite::SignatureSerialization`] in bytes.
pub fn to_bytes(&self) -> C::SignatureSerialization {
let mut bytes = vec![];

View File

@ -10,7 +10,7 @@ pub struct SigningKey<C>
where
C: Ciphersuite,
{
scalar: <<C::Group as Group>::Field as Field>::Scalar,
pub(crate) scalar: <<C::Group as Group>::Field as Field>::Scalar,
}
impl<C> SigningKey<C>

View File

@ -11,7 +11,7 @@ pub mod vectors;
/// Test share generation with a Ciphersuite
pub fn check_share_generation<C: Ciphersuite, R: RngCore + CryptoRng>(mut rng: R) {
let secret = frost::keys::Secret::<C>::random(&mut rng);
let secret = frost::keys::SharedSecret::<C>::random(&mut rng);
let secret_shares = frost::keys::generate_secret_shares(&secret, 5, 3, rng).unwrap();

View File

@ -41,7 +41,8 @@ pub fn parse_test_vectors<C: Ciphersuite>(
VerifyingKey::<C>::from_hex(inputs["group_public_key"].as_str().unwrap()).unwrap();
for (i, secret_share) in possible_signers {
let secret = Secret::<C>::from_hex(secret_share["signer_share"].as_str().unwrap()).unwrap();
let secret =
SigningShare::<C>::from_hex(secret_share["signer_share"].as_str().unwrap()).unwrap();
let signer_public = secret.into();
let key_package = KeyPackage::<C> {
@ -159,7 +160,7 @@ pub fn check_sign_with_test_vectors<C: Ciphersuite>(json_vectors: &Value) {
for key_package in key_packages.values() {
assert_eq!(
*key_package.public(),
frost::keys::Public::from(*key_package.secret_share())
frost::keys::VerifyingShare::from(*key_package.secret_share())
);
}

View File

@ -229,7 +229,7 @@ pub mod keys {
///
pub mod round1 {
use frost_core::frost::keys::Secret;
use frost_core::frost::keys::SigningShare;
use super::*;
///
@ -241,7 +241,7 @@ pub mod round1 {
///
pub fn commit<RNG>(
participant_identifier: frost::Identifier<P>,
secret: &Secret<P>,
secret: &SigningShare<P>,
rng: &mut RNG,
) -> (SigningNonces, SigningCommitments)
where

View File

@ -210,7 +210,7 @@ pub mod keys {
///
pub mod round1 {
use frost_core::frost::keys::Secret;
use frost_core::frost::keys::SigningShare;
use super::*;
///
@ -222,7 +222,7 @@ pub mod round1 {
///
pub fn commit<RNG>(
participant_identifier: frost::Identifier<R>,
secret: &Secret<R>,
secret: &SigningShare<R>,
rng: &mut RNG,
) -> (SigningNonces, SigningCommitments)
where