Skip to content

Commit

Permalink
[frost] updated frost proptest and minor fixups
Browse files Browse the repository at this point in the history
  • Loading branch information
nickfarrow committed Jul 3, 2024
1 parent a53473b commit 5d86d94
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 10 deletions.
File renamed without changes.
21 changes: 11 additions & 10 deletions schnorr_fun/src/frost/share.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use secp256kfun::{marker::*, poly, Scalar};
/// A *[Shamir secret share]*.
///
/// Each share is an `(x,y)` pair where `y = p(x)` for some polynomial `p`. With a sufficient
/// number of unique pairs you can recontruct `p` as a vector of `Scalar`s where each `Scalar` is a
/// number of unique pairs you can reconstruct `p` as a vector of `Scalar`s where each `Scalar` is a
/// coefficient `p`. This structure is useful for hiding a secret `y*` by having `p(0) = y*` until a
/// sufficient number of shares come together to resconstruct `y*`.
/// sufficient number of shares come together to reconstruct `y*`.
///
/// Signing keys in FROST are also shamir secert shares which is why this is here.
/// Signing keys in FROST are also shamir secret shares which is why this is here.
///
/// ## Backup format (bech32 chars)
///
Expand All @@ -15,10 +15,10 @@ use secp256kfun::{marker::*, poly, Scalar};
/// the payload.
///
/// We optionally have the index in the human readable part since users can more easily identify
/// shares that way. Share identification can help for keeping track of them and distinguishing them
/// there are only a small numbner of shares.
/// shares that way. Share identification can help for keeping track of them and distinguishing shares
/// when there are only a small number of them.
///
/// The backuip format is enabled with the `share_backup` feature and accessed with the `FromStr`
/// The backup format is enabled with the `share_backup` feature and accessed with the `FromStr`
/// and `Display`.
///
/// ### Index in human readable part
Expand All @@ -30,7 +30,7 @@ use secp256kfun::{marker::*, poly, Scalar};
///
/// The payload consists of:
///
/// - `secret_share` (`[u8;32]`): the 32 bytes that reperesents the secret share scalar in big-endian encoding
/// - `secret_share` (`[u8;32]`): the 32 bytes that represents the secret share scalar in big-endian encoding
///
/// ### Index in payload
///
Expand All @@ -42,7 +42,7 @@ use secp256kfun::{marker::*, poly, Scalar};
/// The payload consists of:
///
/// - `secret_share` (`[u8;32]`): the 32 bytes that reperesents the secret share scalar in big-endian encoding
/// - `share_index`: [u8;1..32] which is the index where the polynomial was evalulated to create the share. This is also a big-endian scalar except that the leading zero bytes are dropped so the smaller the index the smaller the encoding.
/// - `share_index`: [u8;1..32] which is the index where the polynomial was evaluated to create the share. This is also a big-endian scalar except that the leading zero bytes are dropped so the smaller the index the smaller the encoding.
///
/// [Shamir secret share]: https://en.wikipedia.org/wiki/Shamir%27s_secret_sharing
/// [`bech32m`]: https://bips.xyz/350
Expand Down Expand Up @@ -282,10 +282,11 @@ mod test {
};
proptest! {
#[test]
fn recover_secret(parties in 1usize..10, threshold in 1usize..5) {
fn recover_secret(
(parties, threshold) in (1usize..=10).prop_flat_map(|n| (Just(n), 1usize..=n)),
) {
use rand::seq::SliceRandom;
let frost = frost::new_with_deterministic_nonces::<sha2::Sha256>();
let parties = parties.max(threshold);

let mut rng = TestRng::deterministic_rng(RngAlgorithm::ChaCha);
let (frost_key, shares) = frost.simulate_keygen(threshold, parties, &mut rng);
Expand Down
102 changes: 102 additions & 0 deletions schnorr_fun/tests/frost_prop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#![cfg(feature = "alloc")]
use rand::seq::SliceRandom;
use rand_chacha::ChaCha20Rng;
use schnorr_fun::{
frost::*,
fun::{marker::*, Scalar},
Message,
};
use secp256kfun::proptest::{
arbitrary::any,
option, proptest,
strategy::{Just, Strategy},
test_runner::{RngAlgorithm, TestRng},
};
use sha2::Sha256;
use std::collections::BTreeMap;

proptest! {

#[test]
fn frost_prop_test(
(n_parties, threshold) in (2usize..=4).prop_flat_map(|n| (Just(n), 2usize..=n)),
plain_tweak in option::of(any::<Scalar<Public, Zero>>()),
xonly_tweak in option::of(any::<Scalar<Public, Zero>>())
) {
let proto = new_with_deterministic_nonces::<Sha256>();
assert!(threshold <= n_parties);

// // create some scalar polynomial for each party
let mut rng = TestRng::deterministic_rng(RngAlgorithm::ChaCha);
let (mut frost_key, secret_shares) = proto.simulate_keygen(threshold, n_parties, &mut rng);

if let Some(tweak) = plain_tweak {
frost_key = frost_key.tweak(tweak).unwrap();
}

let mut frost_key = frost_key.into_xonly_key();

if let Some(tweak) = xonly_tweak {
frost_key = frost_key.tweak(tweak).unwrap();
}

// use a boolean mask for which t participants are signers
let mut signer_mask = vec![true; threshold];
signer_mask.append(&mut vec![false; n_parties - threshold]);
// shuffle the mask for random signers
signer_mask.shuffle(&mut rng);

let secret_shares = signer_mask.into_iter().zip(secret_shares.into_iter()).filter(|(is_signer, _)| *is_signer)
.map(|(_, secret_share)| secret_share).collect::<Vec<_>>();


let sid = b"frost-prop-test".as_slice();
let message = Message::plain("test", b"test");

let mut secret_nonces: BTreeMap<_, _> = secret_shares.iter().map(|secret_share| {
(secret_share.index, proto.gen_nonce::<ChaCha20Rng>(
&mut proto.seed_nonce_rng(
&frost_key,
&secret_share.secret,
sid,
)))
}).collect();


let public_nonces = secret_nonces.iter().map(|(signer_index, sn)| (*signer_index, sn.public())).collect::<BTreeMap<_, _>>();
dbg!(&public_nonces);

let signing_session = proto.start_sign_session(
&frost_key,
public_nonces,
message
);

let mut signatures = vec![];
for secret_share in secret_shares {
let sig = proto.sign(
&frost_key,
&signing_session,
&secret_share,
secret_nonces.remove(&secret_share.index).unwrap()
);
assert!(proto.verify_signature_share(
&frost_key,
&signing_session,
secret_share.index,
sig)
);
signatures.push(sig);
}
let combined_sig = proto.combine_signature_shares(
&frost_key,
&signing_session,
signatures);

assert!(proto.schnorr.verify(
&frost_key.public_key(),
message,
&combined_sig
));
}
}

0 comments on commit 5d86d94

Please sign in to comment.