Expand description
The FROST threshold multisignature scheme.
§Synopsis
use schnorr_fun::binonce::NonceKeyPair;
use schnorr_fun::fun::{s, poly};
use schnorr_fun::{
frost::{self, chilldkg::simplepedpop},
Message,
};
use std::collections::BTreeMap;
use rand_chacha::ChaCha20Rng;
use sha2::Sha256;
let frost = frost::new_with_deterministic_nonces::<Sha256>();
// This runs a 2-of-3 key generation on a single computer which means it's a trusted party.
// See the documentation/API of the protocols in `chilldkg` to see how to distrubute the key generation properly.
let (shared_key, secret_shares) = simplepedpop::simulate_keygen(&frost.schnorr, 2, 3,3, &mut rand::thread_rng());
let my_secret_share = secret_shares[0];
let my_index = my_secret_share.index();
// With signing we'll have at least one party be the "coordinator" (steps marked with 🐙)
// In this example we'll be the coordinator (but it doesn't have to be one of the signing parties)
let xonly_shared_key = shared_key.into_xonly(); // this is the key signatures will be valid under
let xonly_my_secret_share = my_secret_share.into_xonly();
let message = Message::plain("my-app", b"chancellor on brink of second bailout for banks");
// Generate nonces for this signing session (and send them to coordinator somehow)
// ⚠ 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(my_secret_share, session_id);
let my_nonce = frost.gen_nonce(&mut nonce_rng);
// share your public nonce with the other signing participant(s) receive public nonces
// 🐙 the coordinator has received the nonces
let nonces = BTreeMap::from_iter([(my_index, my_nonce.public()), (party_index3, received_nonce3)]);
let coord_session = frost.coordinator_sign_session(&xonly_shared_key, nonces, message);
// Parties receive the agg_nonce from the coordiantor and the list of perties
let agg_binonce = coord_session.agg_binonce();
let parties = coord_session.parties();
// start a sign session with these nonces for a message
let sign_session = frost.party_sign_session(xonly_my_secret_share.public_key(),parties, agg_binonce, message);
// create a partial signature using our secret share and secret nonce
let my_sig_share = sign_session.sign(&xonly_my_secret_share, my_nonce);
// 🐙 receive the partial signature(s) from the other participant(s).
// 🐙 combine signature shares into a single signature that is valid under the FROST key
let combined_sig = coord_session.verify_and_combine_signature_shares(
&xonly_shared_key,
[(my_index, my_sig_share), (party_index3, sig_share3)].into()
)?;
assert!(frost.schnorr.verify(
&xonly_shared_key.public_key(),
message,
&combined_sig
));
§Description
In FROST, multiple parties cooperatively generate a single joint public key (SharedKey
) for
creating Schnorr signatures. Unlike in musig
, only some threshold t
of the n
signers are
required to generate a signature under the key (rather than all n
).
This implementation is not yet compatible with other existing FROST implementations (notably secp256k1-zkp).
The original scheme was introduced in FROST: Flexible Round-Optimized Schnorr Threshold Signatures. A more satisfying security proof was provided in Security of Multi- and Threshold Signatures. This implementation follows most closely Practical Schnorr Threshold Signatures Without the Algebraic Group Model.
⚠ CAUTION ⚠: We think that this follows the scheme in the “Practical” paper which is proven secure but we haven’t put a lot of effort into verifying this yet.
Re-exports§
pub use crate::binonce::Nonce;
pub use crate::binonce::NonceKeyPair;
Modules§
- chilldkg
- Our take on the WIP ChillDKG: Distributed Key Generation for FROST spec
Structs§
- Coordinator
Sign Session - A FROST signing session used to verify signatures.
- Frost
- The FROST context.
- Paired
Secret Share - A secret share paired with the image of the secret for which it is a share of.
- Party
Sign Session - The session that is used to sign a message.
- Secret
Share - A Shamir secret share.
- Shared
Key - A polynomial where the first coefficient (constant term) is the image of a secret
Scalar
that has been shared in a Shamir’s secret sharing structure. - Signature
Share Invalid - Error for a signature share being invalid
- Verification
Share - This is the public image of a
SecretShare
. You can’t sign with it but you can verify signature shares created by the secret share.
Enums§
- Backup
Decode Error - An error encountered when decoding a Frostsnap backup.
- Verify
Signature Shares Error - Error returned by
CoordinatorSignSession::verify_and_combine_signature_shares
Functions§
- new_
with_ deterministic_ nonces - Constructor for a Frost instance using deterministic nonce generation.
- new_
with_ synthetic_ nonces - Constructor for a Frost instance using synthetic nonce generation.
- new_
without_ nonce_ generation - Create a Frost instance which does not handle nonce generation.
Type Aliases§
- Party
Index - The index of a party’s secret share.
- Signature
Share - A Frost signature share.