Skip to content

Commit 1f4b852

Browse files
committed
add frost-secp256k1-tr crate (BIP340/BIP341)
1 parent 4406e01 commit 1f4b852

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+4156
-32
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ Cargo.lock
44
*~
55
**/.DS_Store
66
.vscode/*
7+
*.swp

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ members = [
77
"frost-p256",
88
"frost-ristretto255",
99
"frost-secp256k1",
10+
"frost-secp256k1-tr",
1011
"frost-rerandomized",
1112
"gencode"
1213
]

frost-core/src/batch.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ where
3232
{
3333
fn from((vk, sig, msg): (VerifyingKey<C>, Signature<C>, &'msg M)) -> Self {
3434
// Compute c now to avoid dependency on the msg lifetime.
35-
let c = crate::challenge(&sig.R, &vk, msg.as_ref());
35+
let c = <C>::challenge(&sig.R, &vk, msg.as_ref());
3636

3737
Self { vk, sig, c }
3838
}
@@ -118,7 +118,12 @@ where
118118

119119
for item in self.signatures.iter() {
120120
let z = item.sig.z;
121-
let R = item.sig.R;
121+
let mut R = item.sig.R;
122+
let mut vk = item.vk.element;
123+
if <C>::is_need_tweaking() {
124+
R = <C>::tweaked_R(&item.sig.R);
125+
vk = <C>::tweaked_public_key(&item.vk.element);
126+
}
122127

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

@@ -129,7 +134,7 @@ where
129134
Rs.push(R);
130135

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

135140
let scalars = once(&P_coeff_acc)

frost-core/src/keys.rs

+10
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@ where
120120
pub(crate) fn from_coefficients(coefficients: &[Scalar<C>], peer: Identifier<C>) -> Self {
121121
Self(evaluate_polynomial(peer, coefficients))
122122
}
123+
124+
/// Returns negated SigningShare
125+
pub fn negate(&mut self) {
126+
self.0 = <<C::Group as Group>::Field>::negate(&self.0);
127+
}
123128
}
124129

125130
impl<C> Debug for SigningShare<C>
@@ -674,6 +679,11 @@ where
674679
min_signers,
675680
}
676681
}
682+
683+
/// Negate `SigningShare`.
684+
pub fn negate_signing_share(&mut self) {
685+
self.signing_share.negate();
686+
}
677687
}
678688

679689
#[cfg(feature = "serialization")]

frost-core/src/lib.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,13 @@ where
6969
C: Ciphersuite,
7070
{
7171
/// Creates a challenge from a scalar.
72-
#[cfg(feature = "internals")]
7372
pub fn from_scalar(
7473
scalar: <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar,
7574
) -> Self {
7675
Self(scalar)
7776
}
7877

7978
/// Return the underlying scalar.
80-
#[cfg(feature = "internals")]
8179
pub fn to_scalar(self) -> <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar {
8280
self.0
8381
}
@@ -465,6 +463,11 @@ where
465463
pub fn to_element(self) -> <C::Group as Group>::Element {
466464
self.0
467465
}
466+
467+
/// Check if group commitment is odd
468+
pub fn y_is_odd(&self) -> bool {
469+
<C::Group as Group>::y_is_odd(&self.0)
470+
}
468471
}
469472

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

591+
if <C>::is_need_tweaking() {
592+
let challenge = <C>::challenge(
593+
&group_commitment.0,
594+
&pubkeys.verifying_key,
595+
signing_package.message().as_slice(),
596+
);
597+
z = <C>::aggregate_tweak_z(z, &challenge, &pubkeys.verifying_key.element);
598+
}
599+
588600
let signature = Signature {
589601
R: group_commitment.0,
590602
z,
@@ -601,7 +613,7 @@ where
601613
#[cfg(feature = "cheater-detection")]
602614
if let Err(err) = verification_result {
603615
// Compute the per-message challenge.
604-
let challenge = crate::challenge::<C>(
616+
let challenge = <C>::challenge(
605617
&group_commitment.0,
606618
&pubkeys.verifying_key,
607619
signing_package.message().as_slice(),
@@ -636,6 +648,8 @@ where
636648
signer_pubkey,
637649
lambda_i,
638650
&challenge,
651+
&group_commitment,
652+
&pubkeys.verifying_key,
639653
)?;
640654
}
641655

frost-core/src/round1.rs

+11
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ where
5050
Self::nonce_generate_from_random_bytes(secret, random_bytes)
5151
}
5252

53+
/// Negate `Nonce`.
54+
pub fn negate(&mut self) {
55+
self.0 = <<C::Group as Group>::Field>::negate(&self.0);
56+
}
57+
5358
/// Generates a nonce from the given random bytes.
5459
/// This function allows testing and MUST NOT be made public.
5560
pub(crate) fn nonce_generate_from_random_bytes(
@@ -263,6 +268,12 @@ where
263268
pub fn binding(&self) -> &Nonce<C> {
264269
&self.binding
265270
}
271+
272+
/// Negate `SigningShare`.
273+
pub fn negate_nonces(&mut self) {
274+
self.binding.negate();
275+
self.hiding.negate();
276+
}
266277
}
267278

268279
/// Published by each participant in the first round of the signing protocol.

frost-core/src/round2.rs

+39-14
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::fmt::{self, Debug};
44

55
use crate as frost;
66
use crate::{
7-
challenge, Challenge, Ciphersuite, Error, Field, Group, {round1, *},
7+
Challenge, Ciphersuite, Error, Field, Group, {round1, *},
88
};
99

1010
#[cfg(feature = "serde")]
@@ -90,9 +90,23 @@ where
9090
verifying_share: &frost::keys::VerifyingShare<C>,
9191
lambda_i: Scalar<C>,
9292
challenge: &Challenge<C>,
93+
group_commitment: &frost::GroupCommitment<C>,
94+
verifying_key: &frost::VerifyingKey<C>,
9395
) -> Result<(), Error<C>> {
96+
let mut commitment_share = group_commitment_share.0;
97+
let mut vsh = verifying_share.0;
98+
if <C>::is_need_tweaking() {
99+
commitment_share = <C>::tweaked_group_commitment_share(
100+
&group_commitment_share.0,
101+
&group_commitment.0
102+
);
103+
vsh = <C>::tweaked_verifying_share(
104+
&verifying_share.0,
105+
&verifying_key.element
106+
);
107+
}
94108
if (<C::Group>::generator() * self.share)
95-
!= (group_commitment_share.0 + (verifying_share.0 * challenge.0 * lambda_i))
109+
!= (commitment_share + (vsh * challenge.0 * lambda_i))
96110
{
97111
return Err(Error::InvalidSignatureShare {
98112
culprit: identifier,
@@ -150,9 +164,7 @@ where
150164
}
151165

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

216228
// Compute the per-message challenge.
217-
let challenge = challenge::<C>(
229+
let challenge = <C>::challenge(
218230
&group_commitment.0,
219231
&key_package.verifying_key,
220232
signing_package.message.as_slice(),
221233
);
222234

223235
// Compute the Schnorr signature share.
224-
let signature_share = compute_signature_share(
225-
signer_nonces,
226-
binding_factor,
227-
lambda_i,
228-
key_package,
229-
challenge,
230-
);
236+
if <C>::is_need_tweaking() {
237+
let signature_share = <C>::compute_tweaked_signature_share(
238+
signer_nonces,
239+
binding_factor,
240+
group_commitment,
241+
lambda_i,
242+
key_package,
243+
challenge,
244+
);
231245

232-
Ok(signature_share)
246+
Ok(signature_share)
247+
} else {
248+
let signature_share = compute_signature_share(
249+
signer_nonces,
250+
binding_factor,
251+
lambda_i,
252+
key_package,
253+
challenge,
254+
);
255+
256+
Ok(signature_share)
257+
}
233258
}

frost-core/src/signature.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
//! Schnorr signatures over prime order groups (or subgroups)
22
33
use debugless_unwrap::DebuglessUnwrap;
4+
use derive_getters::Getters;
45

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

78
/// A Schnorr signature over some prime order group (or subgroup).
8-
#[derive(Copy, Clone, Eq, PartialEq)]
9+
#[derive(Copy, Clone, Eq, PartialEq, Getters)]
910
pub struct Signature<C: Ciphersuite> {
1011
/// The commitment `R` to the signature nonce.
1112
pub(crate) R: Element<C>,

frost-core/src/signing_key.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use rand_core::{CryptoRng, RngCore};
44

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

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

4646
/// Create a signature `msg` using this `SigningKey`.
4747
pub fn sign<R: RngCore + CryptoRng>(&self, mut rng: R, msg: &[u8]) -> Signature<C> {
48-
let k = random_nonzero::<C, R>(&mut rng);
49-
48+
let public = VerifyingKey::<C>::from(*self);
49+
let mut secret = self.scalar;
50+
if <C>::is_need_tweaking() {
51+
secret = <C>::tweaked_secret_key(secret, &public.element);
52+
}
53+
let mut k = random_nonzero::<C, R>(&mut rng);
5054
let R = <C::Group>::generator() * k;
55+
if <C>::is_need_tweaking() {
56+
k = <C>::tweaked_nonce(k, &R);
57+
}
5158

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

55-
let z = k + (c.0 * self.scalar);
62+
let z = k + (c.0 * secret);
5663

5764
Signature { R, z }
5865
}

0 commit comments

Comments
 (0)