changes required for randomization
This commit is contained in:
parent
1815280576
commit
1ace998b8b
|
@ -25,6 +25,7 @@ hex = { version = "0.4.3", features = ["serde"] }
|
||||||
rand_core = "0.6"
|
rand_core = "0.6"
|
||||||
serde = { version = "1", optional = true, features = ["derive"] }
|
serde = { version = "1", optional = true, features = ["derive"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
visibility = "0.0.1"
|
||||||
zeroize = { version = "1.5.4", default-features = false, features = ["derive"] }
|
zeroize = { version = "1.5.4", default-features = false, features = ["derive"] }
|
||||||
|
|
||||||
# Test dependencies used with the test-impl feature
|
# Test dependencies used with the test-impl feature
|
||||||
|
@ -46,3 +47,4 @@ nightly = []
|
||||||
default = ["serde"]
|
default = ["serde"]
|
||||||
# Exposes ciphersuite-generic tests for other crates to use
|
# Exposes ciphersuite-generic tests for other crates to use
|
||||||
test-impl = ["proptest", "proptest-derive", "serde_json"]
|
test-impl = ["proptest", "proptest-derive", "serde_json"]
|
||||||
|
internals = []
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, HashMap},
|
collections::{BTreeMap, HashMap},
|
||||||
convert::TryFrom,
|
|
||||||
fmt::{self, Debug},
|
fmt::{self, Debug},
|
||||||
ops::Index,
|
ops::Index,
|
||||||
};
|
};
|
||||||
|
@ -41,6 +40,18 @@ impl<C> BindingFactor<C>
|
||||||
where
|
where
|
||||||
C: Ciphersuite,
|
C: Ciphersuite,
|
||||||
{
|
{
|
||||||
|
/// Create a new [`Rho`] from the given scalar.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
pub fn new(scalar: <<C::Group as Group>::Field as Field>::Scalar) -> Self {
|
||||||
|
Self(scalar)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the underlying scalar.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
pub fn to_scalar(self) -> <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
/// Deserializes [`BindingFactor`] from bytes.
|
/// Deserializes [`BindingFactor`] from bytes.
|
||||||
pub fn from_bytes(
|
pub fn from_bytes(
|
||||||
bytes: <<C::Group as Group>::Field as Field>::Serialization,
|
bytes: <<C::Group as Group>::Field as Field>::Serialization,
|
||||||
|
@ -73,6 +84,12 @@ impl<C> BindingFactorList<C>
|
||||||
where
|
where
|
||||||
C: Ciphersuite,
|
C: Ciphersuite,
|
||||||
{
|
{
|
||||||
|
/// Create a new [`BindingFactorList`] from a vector of binding factors.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
pub fn new(binding_factors: BTreeMap<Identifier<C>, BindingFactor<C>>) -> Self {
|
||||||
|
Self(binding_factors)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return iterator through all factors.
|
/// Return iterator through all factors.
|
||||||
pub fn iter(&self) -> impl Iterator<Item = (&Identifier<C>, &BindingFactor<C>)> {
|
pub fn iter(&self) -> impl Iterator<Item = (&Identifier<C>, &BindingFactor<C>)> {
|
||||||
self.0.iter()
|
self.0.iter()
|
||||||
|
@ -136,6 +153,7 @@ where
|
||||||
// TODO: pub struct Lagrange<C: Ciphersuite>(Scalar);
|
// TODO: pub struct Lagrange<C: Ciphersuite>(Scalar);
|
||||||
|
|
||||||
/// Generates the lagrange coefficient for the i'th participant.
|
/// Generates the lagrange coefficient for the i'th participant.
|
||||||
|
#[cfg_attr(feature = "internals", visibility::make(pub))]
|
||||||
fn derive_lagrange_coeff<C: Ciphersuite>(
|
fn derive_lagrange_coeff<C: Ciphersuite>(
|
||||||
signer_id: &Identifier<C>,
|
signer_id: &Identifier<C>,
|
||||||
signing_package: &SigningPackage<C>,
|
signing_package: &SigningPackage<C>,
|
||||||
|
@ -185,7 +203,7 @@ impl<C> SigningPackage<C>
|
||||||
where
|
where
|
||||||
C: Ciphersuite,
|
C: Ciphersuite,
|
||||||
{
|
{
|
||||||
/// Create a new `SigingPackage`
|
/// Create a new `SigningPackage`
|
||||||
///
|
///
|
||||||
/// The `signing_commitments` are sorted by participant `identifier`.
|
/// The `signing_commitments` are sorted by participant `identifier`.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
@ -244,9 +262,25 @@ where
|
||||||
|
|
||||||
/// The product of all signers' individual commitments, published as part of the
|
/// The product of all signers' individual commitments, published as part of the
|
||||||
/// final signature.
|
/// final signature.
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct GroupCommitment<C: Ciphersuite>(pub(super) Element<C>);
|
pub struct GroupCommitment<C: Ciphersuite>(pub(super) Element<C>);
|
||||||
|
|
||||||
|
impl<C> GroupCommitment<C>
|
||||||
|
where
|
||||||
|
C: Ciphersuite,
|
||||||
|
{
|
||||||
|
/// Create a new `GroupCommitment`
|
||||||
|
pub fn new(element: <C::Group as Group>::Element) -> Self {
|
||||||
|
Self(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the underlying element.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
pub fn to_element(self) -> <C::Group as Group>::Element {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// impl<C> Debug for GroupCommitment<C> where C: Ciphersuite {
|
// impl<C> Debug for GroupCommitment<C> where C: Ciphersuite {
|
||||||
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
// f.debug_tuple("GroupCommitment")
|
// f.debug_tuple("GroupCommitment")
|
||||||
|
@ -255,43 +289,41 @@ pub struct GroupCommitment<C: Ciphersuite>(pub(super) Element<C>);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
impl<C> TryFrom<&SigningPackage<C>> for GroupCommitment<C>
|
/// Generates the group commitment which is published as part of the joint
|
||||||
|
/// Schnorr signature.
|
||||||
|
///
|
||||||
|
/// Implements [`compute_group_commitment`] from the spec.
|
||||||
|
///
|
||||||
|
/// [`compute_group_commitment`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-10.html#section-4.5
|
||||||
|
#[cfg_attr(feature = "internals", visibility::make(pub))]
|
||||||
|
fn compute_group_commitment<C>(
|
||||||
|
signing_package: &SigningPackage<C>,
|
||||||
|
binding_factor_list: &BindingFactorList<C>,
|
||||||
|
) -> Result<GroupCommitment<C>, Error>
|
||||||
where
|
where
|
||||||
C: Ciphersuite,
|
C: Ciphersuite,
|
||||||
{
|
{
|
||||||
type Error = Error;
|
let identity = <C::Group as Group>::identity();
|
||||||
|
|
||||||
/// Generates the group commitment which is published as part of the joint
|
let mut group_commitment = <C::Group as Group>::identity();
|
||||||
/// Schnorr signature.
|
|
||||||
///
|
|
||||||
/// Implements [`compute_group_commitment`] from the spec.
|
|
||||||
///
|
|
||||||
/// [`compute_group_commitment`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-4.5
|
|
||||||
fn try_from(signing_package: &SigningPackage<C>) -> Result<GroupCommitment<C>, Error> {
|
|
||||||
let binding_factor_list: BindingFactorList<C> = signing_package.into();
|
|
||||||
|
|
||||||
let identity = <C::Group>::identity();
|
// Ala the sorting of B, just always sort by identifier in ascending order
|
||||||
|
//
|
||||||
let mut group_commitment = <C::Group>::identity();
|
// https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#encoding-operations-dep-encoding
|
||||||
|
for commitment in signing_package.signing_commitments() {
|
||||||
// Ala the sorting of B, just always sort by identifier in ascending order
|
// The following check prevents a party from accidentally revealing their share.
|
||||||
//
|
// Note that the '&&' operator would be sufficient.
|
||||||
// https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#encoding-operations-dep-encoding
|
if identity == commitment.binding.0 || identity == commitment.hiding.0 {
|
||||||
for commitment in signing_package.signing_commitments() {
|
return Err(Error::IdentityCommitment);
|
||||||
// The following check prevents a party from accidentally revealing their share.
|
|
||||||
// Note that the '&&' operator would be sufficient.
|
|
||||||
if identity == commitment.binding.0 || identity == commitment.hiding.0 {
|
|
||||||
return Err(Error::IdentityCommitment);
|
|
||||||
}
|
|
||||||
|
|
||||||
let binding_factor = binding_factor_list[commitment.identifier].clone();
|
|
||||||
|
|
||||||
group_commitment = group_commitment
|
|
||||||
+ (commitment.hiding.0 + (commitment.binding.0 * binding_factor.0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(GroupCommitment(group_commitment))
|
let binding_factor = binding_factor_list[commitment.identifier].clone();
|
||||||
|
|
||||||
|
group_commitment =
|
||||||
|
group_commitment + (commitment.hiding.0 + (commitment.binding.0 * binding_factor.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(GroupCommitment::new(group_commitment))
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -326,7 +358,7 @@ where
|
||||||
let binding_factor_list: BindingFactorList<C> = signing_package.into();
|
let binding_factor_list: BindingFactorList<C> = signing_package.into();
|
||||||
|
|
||||||
// Compute the group commitment from signing commitments produced in round one.
|
// Compute the group commitment from signing commitments produced in round one.
|
||||||
let group_commitment = GroupCommitment::<C>::try_from(signing_package)?;
|
let group_commitment = compute_group_commitment(signing_package, &binding_factor_list)?;
|
||||||
|
|
||||||
// Compute the per-message challenge.
|
// Compute the per-message challenge.
|
||||||
let challenge = crate::challenge::<C>(
|
let challenge = crate::challenge::<C>(
|
||||||
|
|
|
@ -19,7 +19,8 @@ impl<C> Identifier<C>
|
||||||
where
|
where
|
||||||
C: Ciphersuite,
|
C: Ciphersuite,
|
||||||
{
|
{
|
||||||
// Serialize the underlying scalar.
|
/// Serialize the underlying scalar.
|
||||||
|
#[cfg_attr(feature = "internals", visibility::make(pub))]
|
||||||
pub(crate) fn serialize(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
|
pub(crate) fn serialize(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
|
||||||
<<C::Group as Group>::Field>::serialize(&self.0)
|
<<C::Group as Group>::Field>::serialize(&self.0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,6 +121,12 @@ impl<C> SigningShare<C>
|
||||||
where
|
where
|
||||||
C: Ciphersuite,
|
C: Ciphersuite,
|
||||||
{
|
{
|
||||||
|
/// Return the underlying scalar.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
pub fn to_scalar(self) -> <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
/// Deserialize from bytes
|
/// Deserialize from bytes
|
||||||
pub fn from_bytes(
|
pub fn from_bytes(
|
||||||
bytes: <<C::Group as Group>::Field as Field>::Serialization,
|
bytes: <<C::Group as Group>::Field as Field>::Serialization,
|
||||||
|
|
|
@ -54,6 +54,12 @@ where
|
||||||
Self(C::H3(input.as_slice()))
|
Self(C::H3(input.as_slice()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the underlying scalar.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
pub fn to_scalar(self) -> <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
/// Deserialize [`Nonce`] from bytes
|
/// Deserialize [`Nonce`] from bytes
|
||||||
pub fn from_bytes(
|
pub fn from_bytes(
|
||||||
bytes: <<C::Group as Group>::Field as Field>::Serialization,
|
bytes: <<C::Group as Group>::Field as Field>::Serialization,
|
||||||
|
@ -100,6 +106,12 @@ impl<C> NonceCommitment<C>
|
||||||
where
|
where
|
||||||
C: Ciphersuite,
|
C: Ciphersuite,
|
||||||
{
|
{
|
||||||
|
/// Return the underlying element.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
pub fn to_element(self) -> <C::Group as Group>::Element {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
/// Deserialize [`NonceCommitment`] from bytes
|
/// Deserialize [`NonceCommitment`] from bytes
|
||||||
pub fn from_bytes(bytes: <C::Group as Group>::Serialization) -> Result<Self, Error> {
|
pub fn from_bytes(bytes: <C::Group as Group>::Serialization) -> Result<Self, Error> {
|
||||||
<C::Group>::deserialize(&bytes).map(|element| Self(element))
|
<C::Group>::deserialize(&bytes).map(|element| Self(element))
|
||||||
|
@ -221,6 +233,7 @@ where
|
||||||
/// Computes the [signature commitment share] from these round one signing commitments.
|
/// Computes the [signature commitment share] from these round one signing commitments.
|
||||||
///
|
///
|
||||||
/// [signature commitment share]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-signature-share-verificatio
|
/// [signature commitment share]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-signature-share-verificatio
|
||||||
|
#[cfg_attr(feature = "internals", visibility::make(pub))]
|
||||||
pub(super) fn to_group_commitment_share(
|
pub(super) fn to_group_commitment_share(
|
||||||
self,
|
self,
|
||||||
binding_factor: &frost::BindingFactor<C>,
|
binding_factor: &frost::BindingFactor<C>,
|
||||||
|
@ -271,6 +284,7 @@ pub struct GroupCommitmentShare<C: Ciphersuite>(pub(super) Element<C>);
|
||||||
/// - A byte string containing the serialized representation of B.
|
/// - A byte string containing the serialized representation of B.
|
||||||
///
|
///
|
||||||
/// [`encode_group_commitment_list()`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-list-operations
|
/// [`encode_group_commitment_list()`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-list-operations
|
||||||
|
#[cfg_attr(feature = "internals", visibility::make(pub))]
|
||||||
pub(super) fn encode_group_commitments<C: Ciphersuite>(
|
pub(super) fn encode_group_commitments<C: Ciphersuite>(
|
||||||
signing_commitments: Vec<SigningCommitments<C>>,
|
signing_commitments: Vec<SigningCommitments<C>>,
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
|
|
|
@ -139,7 +139,7 @@ pub fn sign<C: Ciphersuite>(
|
||||||
binding_factor_list[key_package.identifier].clone();
|
binding_factor_list[key_package.identifier].clone();
|
||||||
|
|
||||||
// Compute the group commitment from signing commitments produced in round one.
|
// Compute the group commitment from signing commitments produced in round one.
|
||||||
let group_commitment = GroupCommitment::<C>::try_from(signing_package)?;
|
let group_commitment = compute_group_commitment(signing_package, &binding_factor_list)?;
|
||||||
|
|
||||||
// Compute Lagrange coefficient.
|
// Compute Lagrange coefficient.
|
||||||
let lambda_i = frost::derive_lagrange_coeff(key_package.identifier(), signing_package)?;
|
let lambda_i = frost::derive_lagrange_coeff(key_package.identifier(), signing_package)?;
|
||||||
|
|
|
@ -241,6 +241,17 @@ pub trait Ciphersuite: Copy + Clone + PartialEq {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Challenge<C: Ciphersuite>(pub(crate) <<C::Group as Group>::Field as Field>::Scalar);
|
pub struct Challenge<C: Ciphersuite>(pub(crate) <<C::Group as Group>::Field as Field>::Scalar);
|
||||||
|
|
||||||
|
impl<C> Challenge<C>
|
||||||
|
where
|
||||||
|
C: Ciphersuite,
|
||||||
|
{
|
||||||
|
/// Return the underlying scalar.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
pub fn to_scalar(self) -> <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<C> Debug for Challenge<C>
|
impl<C> Debug for Challenge<C>
|
||||||
where
|
where
|
||||||
C: Ciphersuite,
|
C: Ciphersuite,
|
||||||
|
@ -263,6 +274,7 @@ where
|
||||||
///
|
///
|
||||||
/// [FROST]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-10.html#name-signature-challenge-computa
|
/// [FROST]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-10.html#name-signature-challenge-computa
|
||||||
/// [RFC]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-10.html#section-3.2
|
/// [RFC]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-10.html#section-3.2
|
||||||
|
#[cfg_attr(feature = "internals", visibility::make(pub))]
|
||||||
fn challenge<C>(R: &Element<C>, verifying_key: &Element<C>, msg: &[u8]) -> Challenge<C>
|
fn challenge<C>(R: &Element<C>, verifying_key: &Element<C>, msg: &[u8]) -> Challenge<C>
|
||||||
where
|
where
|
||||||
C: Ciphersuite,
|
C: Ciphersuite,
|
||||||
|
|
|
@ -20,6 +20,15 @@ where
|
||||||
C::Group: Group,
|
C::Group: Group,
|
||||||
<C::Group as Group>::Field: Field,
|
<C::Group as Group>::Field: Field,
|
||||||
{
|
{
|
||||||
|
/// Create a new Signature.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
pub fn new(
|
||||||
|
R: <C::Group as Group>::Element,
|
||||||
|
z: <<C::Group as Group>::Field as Field>::Scalar,
|
||||||
|
) -> Self {
|
||||||
|
Self { R, z }
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts bytes as [`Ciphersuite::SignatureSerialization`] into a `Signature<C>`.
|
/// Converts bytes as [`Ciphersuite::SignatureSerialization`] into a `Signature<C>`.
|
||||||
pub fn from_bytes(bytes: C::SignatureSerialization) -> Result<Self, Error> {
|
pub fn from_bytes(bytes: C::SignatureSerialization) -> Result<Self, Error> {
|
||||||
// To compute the expected length of the encoded point, encode the generator
|
// To compute the expected length of the encoded point, encode the generator
|
||||||
|
|
|
@ -23,6 +23,18 @@ where
|
||||||
// VerifyingKey { element }
|
// VerifyingKey { element }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
/// Create a new VerifyingKey from the given element.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
pub fn new(element: <C::Group as Group>::Element) -> Self {
|
||||||
|
Self { element }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the underlying element.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
pub fn to_element(self) -> <C::Group as Group>::Element {
|
||||||
|
self.element
|
||||||
|
}
|
||||||
|
|
||||||
/// Deserialize from bytes
|
/// Deserialize from bytes
|
||||||
pub fn from_bytes(bytes: <C::Group as Group>::Serialization) -> Result<VerifyingKey<C>, Error> {
|
pub fn from_bytes(bytes: <C::Group as Group>::Serialization) -> Result<VerifyingKey<C>, Error> {
|
||||||
<C::Group>::deserialize(&bytes).map(|element| VerifyingKey { element })
|
<C::Group>::deserialize(&bytes).map(|element| VerifyingKey { element })
|
||||||
|
|
Loading…
Reference in New Issue