Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More concise share backups #182

Merged
merged 7 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion schnorr_fun/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ keywords = ["bitcoin", "schnorr"]

[dependencies]
secp256kfun = { path = "../secp256kfun", version = "0.10", default-features = false }
bech32 = { version = "0.9", optional = true, default-features = false }
bech32 = { version = "0.11", optional = true, default-features = false, features = ["alloc"] }

[dev-dependencies]
secp256kfun = { path = "../secp256kfun", version = "0.10", features = ["proptest"] }
Expand Down
46 changes: 24 additions & 22 deletions schnorr_fun/src/frost.rs → schnorr_fun/src/frost/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
//! // Generate nonces for this signing session.
//! // ⚠️ session_id MUST be different for every signing attempt to avoid nonce reuse (if using deterministic nonces).
//! let session_id = b"signing-ominous-message-about-banks-attempt-1".as_slice();
//! let mut nonce_rng: ChaCha20Rng = frost.seed_nonce_rng(&xonly_frost_key, &my_secret_share, session_id);
//! let mut nonce_rng: ChaCha20Rng = frost.seed_nonce_rng(&xonly_frost_key, &my_secret_share.secret, session_id);
//! let my_nonce = frost.gen_nonce(&mut nonce_rng);
//! # let nonce3 = NonceKeyPair::random(&mut rand::thread_rng());
//! // share your public nonce with the other signing participant(s) receive public nonces
Expand All @@ -99,8 +99,8 @@
//! // start a sign session with these nonces for a message
//! let session = frost.start_sign_session(&xonly_frost_key, nonces, message);
//! // create a partial signature using our secret share and secret nonce
//! let my_sig_share = frost.sign(&xonly_frost_key, &session, my_index, &my_secret_share, my_nonce);
//! # let sig_share3 = frost.sign(&xonly_frost_key, &session, party_index3, &secret_share3, nonce3);
//! let my_sig_share = frost.sign(&xonly_frost_key, &session, &my_secret_share, my_nonce);
//! # let sig_share3 = frost.sign(&xonly_frost_key, &session, &secret_share3, nonce3);
//! // receive the partial signature(s) from the other participant(s) and verify
//! assert!(frost.verify_signature_share(&xonly_frost_key, &session, party_index3, sig_share3));
//! // combine signature shares into a single signature that is valid under the FROST key
Expand Down Expand Up @@ -174,11 +174,14 @@
//! [Security of Multi- and Threshold Signatures]: <https://eprint.iacr.org/2021/1375.pdf>
//! [`musig`]: crate::musig
//! [`Scalar`]: crate::fun::Scalar
use core::num::NonZeroU32;

mod share;
pub use share::*;

pub use crate::binonce::{Nonce, NonceKeyPair};
use crate::{Message, Schnorr, Signature};
use alloc::{collections::BTreeMap, vec::Vec};
use core::num::NonZeroU32;
use secp256kfun::{
derive_nonce_rng,
digest::{generic_array::typenum::U32, Digest},
Expand All @@ -199,9 +202,6 @@ use secp256kfun::{
/// This index can be any non-zero [`Scalar`], but must be unique between parties.
/// In most cases it will make sense to use simple indicies `s!(1), s!(2), ...` for smaller backups.
/// Other applications may desire to use indicies corresponding to pre-existing keys or identifiers.
/// See [`share_backup`] for backup sizes.
///
/// [`share_backup`]: crate::share_backup
pub type PartyIndex = Scalar<Public, NonZero>;

/// The FROST context.
Expand Down Expand Up @@ -565,7 +565,7 @@ impl<H: Digest<OutputSize = U32> + Clone, NG: NonceGen> Frost<H, NG> {
pub fn seed_nonce_rng<R: SeedableRng<Seed = [u8; 32]>>(
&self,
frost_key: &FrostKey<impl Normalized>,
secret: &Scalar,
secret: &Scalar<Secret, impl ZeroChoice>,
session_id: &[u8],
) -> R {
let sid_len = (session_id.len() as u64).to_be_bytes();
Expand All @@ -591,7 +591,7 @@ impl<H: Digest<OutputSize = U32> + Clone, NG: NonceGen> Frost<H, NG> {
threshold: usize,
n_parties: usize,
rng: &mut impl RngCore,
) -> (FrostKey<Normal>, BTreeMap<PartyIndex, Scalar>) {
) -> (FrostKey<Normal>, Vec<SecretShare>) {
let scalar_polys = (0..n_parties)
.map(|i| {
(
Expand Down Expand Up @@ -649,7 +649,7 @@ impl<H: Digest<OutputSize = U32> + Clone, NG: NonceGen> Frost<H, NG> {
.unwrap();

frost_key = Some(_frost_key);
(party_index, secret_share)
secret_share
})
.collect();

Expand Down Expand Up @@ -793,7 +793,7 @@ impl<H: Digest<OutputSize = U32> + Clone, NG> Frost<H, NG> {
my_index: PartyIndex,
secret_shares: BTreeMap<PartyIndex, (Scalar<Secret, Zero>, Signature)>,
proof_of_possession_msg: Message,
) -> Result<(Scalar, FrostKey<Normal>), FinishKeyGenError> {
) -> Result<(SecretShare, FrostKey<Normal>), FinishKeyGenError> {
let mut total_secret_share = s!(0);

for (party_index, poly) in &keygen.point_polys {
Expand All @@ -816,11 +816,13 @@ impl<H: Digest<OutputSize = U32> + Clone, NG> Frost<H, NG> {
total_secret_share += secret_share;
}

let total_secret_share = total_secret_share.non_zero().expect(
"since verification shares are non-zero, the total secret share cannot be zero",
);

Ok((total_secret_share, keygen.frost_key))
Ok((
SecretShare {
index: my_index,
secret: total_secret_share,
},
keygen.frost_key,
))
}

/// Start a FROST signing session.
Expand Down Expand Up @@ -894,15 +896,15 @@ impl<H: Digest<OutputSize = U32> + Clone, NG> Frost<H, NG> {
&self,
frost_key: &FrostKey<EvenY>,
session: &SignSession,
my_index: PartyIndex,
secret_share: &Scalar,
secret_share: &SecretShare,
secret_nonce: NonceKeyPair,
) -> Scalar<Public, Zero> {
let mut lambda = poly::eval_basis_poly_at_0(my_index, session.nonces.keys());
let mut lambda =
poly::eval_basis_poly_at_0(secret_share.index, session.nonces.keys().cloned());
assert_eq!(
*session
.nonces
.get(&my_index)
.get(&secret_share.index)
.expect("my_index was not in session"),
secret_nonce.public(),
"secret nonce didn't match previously provided public nonce"
Expand All @@ -913,7 +915,7 @@ impl<H: Digest<OutputSize = U32> + Clone, NG> Frost<H, NG> {
r2.conditional_negate(session.nonces_need_negation);

let b = &session.binding_coeff;
let x = secret_share;
let x = &secret_share.secret;
let c = &session.challenge;
s!(r1 + (r2 * b) + lambda * x * c).public()
}
Expand All @@ -931,7 +933,7 @@ impl<H: Digest<OutputSize = U32> + Clone, NG> Frost<H, NG> {
signature_share: Scalar<Public, Zero>,
) -> bool {
let s = signature_share;
let mut lambda = poly::eval_basis_poly_at_0(index, session.nonces.keys());
let mut lambda = poly::eval_basis_poly_at_0(index, session.nonces.keys().cloned());
lambda.conditional_negate(frost_key.needs_negation);
let c = &session.challenge;
let b = &session.binding_coeff;
Expand Down
Loading
Loading