Skip to content

Commit

Permalink
add frost-secp256k1-tr crate (BIP340/BIP341)
Browse files Browse the repository at this point in the history
  • Loading branch information
zebra-lucky committed Nov 20, 2023
1 parent 4406e01 commit 1f4b852
Show file tree
Hide file tree
Showing 46 changed files with 4,156 additions and 32 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ Cargo.lock
*~
**/.DS_Store
.vscode/*
*.swp
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"frost-p256",
"frost-ristretto255",
"frost-secp256k1",
"frost-secp256k1-tr",
"frost-rerandomized",
"gencode"
]
11 changes: 8 additions & 3 deletions frost-core/src/batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ where
{
fn from((vk, sig, msg): (VerifyingKey<C>, Signature<C>, &'msg M)) -> Self {
// Compute c now to avoid dependency on the msg lifetime.
let c = crate::challenge(&sig.R, &vk, msg.as_ref());
let c = <C>::challenge(&sig.R, &vk, msg.as_ref());

Self { vk, sig, c }
}
Expand Down Expand Up @@ -118,7 +118,12 @@ where

for item in self.signatures.iter() {
let z = item.sig.z;
let R = item.sig.R;
let mut R = item.sig.R;
let mut vk = item.vk.element;
if <C>::is_need_tweaking() {
R = <C>::tweaked_R(&item.sig.R);
vk = <C>::tweaked_public_key(&item.vk.element);
}

let blind = <<C::Group as Group>::Field>::random(&mut rng);

Expand All @@ -129,7 +134,7 @@ where
Rs.push(R);

VK_coeffs.push(<<C::Group as Group>::Field>::zero() + (blind * item.c.0));
VKs.push(item.vk.element);
VKs.push(vk);
}

let scalars = once(&P_coeff_acc)
Expand Down
10 changes: 10 additions & 0 deletions frost-core/src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ where
pub(crate) fn from_coefficients(coefficients: &[Scalar<C>], peer: Identifier<C>) -> Self {
Self(evaluate_polynomial(peer, coefficients))
}

/// Returns negated SigningShare
pub fn negate(&mut self) {
self.0 = <<C::Group as Group>::Field>::negate(&self.0);
}
}

impl<C> Debug for SigningShare<C>
Expand Down Expand Up @@ -674,6 +679,11 @@ where
min_signers,
}
}

/// Negate `SigningShare`.
pub fn negate_signing_share(&mut self) {
self.signing_share.negate();
}
}

#[cfg(feature = "serialization")]
Expand Down
20 changes: 17 additions & 3 deletions frost-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,13 @@ where
C: Ciphersuite,
{
/// Creates a challenge from a scalar.
#[cfg(feature = "internals")]
pub fn from_scalar(
scalar: <<<C as Ciphersuite>::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
}
Expand Down Expand Up @@ -465,6 +463,11 @@ where
pub fn to_element(self) -> <C::Group as Group>::Element {
self.0
}

/// Check if group commitment is odd
pub fn y_is_odd(&self) -> bool {
<C::Group as Group>::y_is_odd(&self.0)
}
}

/// Generates the group commitment which is published as part of the joint
Expand Down Expand Up @@ -585,6 +588,15 @@ where
z = z + signature_share.share;
}

if <C>::is_need_tweaking() {
let challenge = <C>::challenge(
&group_commitment.0,
&pubkeys.verifying_key,
signing_package.message().as_slice(),
);
z = <C>::aggregate_tweak_z(z, &challenge, &pubkeys.verifying_key.element);
}

let signature = Signature {
R: group_commitment.0,
z,
Expand All @@ -601,7 +613,7 @@ where
#[cfg(feature = "cheater-detection")]
if let Err(err) = verification_result {
// Compute the per-message challenge.
let challenge = crate::challenge::<C>(
let challenge = <C>::challenge(
&group_commitment.0,
&pubkeys.verifying_key,
signing_package.message().as_slice(),
Expand Down Expand Up @@ -636,6 +648,8 @@ where
signer_pubkey,
lambda_i,
&challenge,
&group_commitment,
&pubkeys.verifying_key,
)?;
}

Expand Down
11 changes: 11 additions & 0 deletions frost-core/src/round1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ where
Self::nonce_generate_from_random_bytes(secret, random_bytes)
}

/// Negate `Nonce`.
pub fn negate(&mut self) {
self.0 = <<C::Group as Group>::Field>::negate(&self.0);
}

/// Generates a nonce from the given random bytes.
/// This function allows testing and MUST NOT be made public.
pub(crate) fn nonce_generate_from_random_bytes(
Expand Down Expand Up @@ -263,6 +268,12 @@ where
pub fn binding(&self) -> &Nonce<C> {
&self.binding
}

/// Negate `SigningShare`.
pub fn negate_nonces(&mut self) {
self.binding.negate();
self.hiding.negate();
}
}

/// Published by each participant in the first round of the signing protocol.
Expand Down
53 changes: 39 additions & 14 deletions frost-core/src/round2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::fmt::{self, Debug};

use crate as frost;
use crate::{
challenge, Challenge, Ciphersuite, Error, Field, Group, {round1, *},
Challenge, Ciphersuite, Error, Field, Group, {round1, *},
};

#[cfg(feature = "serde")]
Expand Down Expand Up @@ -90,9 +90,23 @@ where
verifying_share: &frost::keys::VerifyingShare<C>,
lambda_i: Scalar<C>,
challenge: &Challenge<C>,
group_commitment: &frost::GroupCommitment<C>,
verifying_key: &frost::VerifyingKey<C>,
) -> Result<(), Error<C>> {
let mut commitment_share = group_commitment_share.0;
let mut vsh = verifying_share.0;
if <C>::is_need_tweaking() {
commitment_share = <C>::tweaked_group_commitment_share(
&group_commitment_share.0,
&group_commitment.0
);
vsh = <C>::tweaked_verifying_share(
&verifying_share.0,
&verifying_key.element
);
}
if (<C::Group>::generator() * self.share)
!= (group_commitment_share.0 + (verifying_share.0 * challenge.0 * lambda_i))
!= (commitment_share + (vsh * challenge.0 * lambda_i))
{
return Err(Error::InvalidSignatureShare {
culprit: identifier,
Expand Down Expand Up @@ -150,9 +164,7 @@ where
}

/// Compute the signature share for a signing operation.
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
fn compute_signature_share<C: Ciphersuite>(
pub fn compute_signature_share<C: Ciphersuite>(
signer_nonces: &round1::SigningNonces<C>,
binding_factor: BindingFactor<C>,
lambda_i: <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar,
Expand Down Expand Up @@ -214,20 +226,33 @@ pub fn sign<C: Ciphersuite>(
let lambda_i = frost::derive_interpolating_value(key_package.identifier(), signing_package)?;

// Compute the per-message challenge.
let challenge = challenge::<C>(
let challenge = <C>::challenge(
&group_commitment.0,
&key_package.verifying_key,
signing_package.message.as_slice(),
);

// Compute the Schnorr signature share.
let signature_share = compute_signature_share(
signer_nonces,
binding_factor,
lambda_i,
key_package,
challenge,
);
if <C>::is_need_tweaking() {
let signature_share = <C>::compute_tweaked_signature_share(
signer_nonces,
binding_factor,
group_commitment,
lambda_i,
key_package,
challenge,
);

Ok(signature_share)
Ok(signature_share)
} else {
let signature_share = compute_signature_share(
signer_nonces,
binding_factor,
lambda_i,
key_package,
challenge,
);

Ok(signature_share)
}
}
3 changes: 2 additions & 1 deletion frost-core/src/signature.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
//! Schnorr signatures over prime order groups (or subgroups)
use debugless_unwrap::DebuglessUnwrap;
use derive_getters::Getters;

use crate::{Ciphersuite, Element, Error, Field, Group, Scalar};

/// A Schnorr signature over some prime order group (or subgroup).
#[derive(Copy, Clone, Eq, PartialEq)]
#[derive(Copy, Clone, Eq, PartialEq, Getters)]
pub struct Signature<C: Ciphersuite> {
/// The commitment `R` to the signature nonce.
pub(crate) R: Element<C>,
Expand Down
17 changes: 12 additions & 5 deletions frost-core/src/signing_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use rand_core::{CryptoRng, RngCore};

use crate::{random_nonzero, Ciphersuite, Error, Field, Group, Scalar, Signature, VerifyingKey};
use crate::{random_nonzero, Ciphersuite, Error, Field, Group, Scalar, Signature, VerifyingKey, Challenge};

/// A signing key for a Schnorr signature on a FROST [`Ciphersuite::Group`].
#[derive(Copy, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -45,14 +45,21 @@ where

/// Create a signature `msg` using this `SigningKey`.
pub fn sign<R: RngCore + CryptoRng>(&self, mut rng: R, msg: &[u8]) -> Signature<C> {
let k = random_nonzero::<C, R>(&mut rng);

let public = VerifyingKey::<C>::from(*self);
let mut secret = self.scalar;
if <C>::is_need_tweaking() {
secret = <C>::tweaked_secret_key(secret, &public.element);
}
let mut k = random_nonzero::<C, R>(&mut rng);
let R = <C::Group>::generator() * k;
if <C>::is_need_tweaking() {
k = <C>::tweaked_nonce(k, &R);
}

// Generate Schnorr challenge
let c = crate::challenge::<C>(&R, &VerifyingKey::<C>::from(*self), msg);
let c: Challenge<C> = <C>::challenge(&R, &public, msg);

let z = k + (c.0 * self.scalar);
let z = k + (c.0 * secret);

Signature { R, z }
}
Expand Down
Loading

0 comments on commit 1f4b852

Please sign in to comment.