FROST threshold signatures for ed25519.
FROST enables threshold signatures where a minimum number of participants (T) from a larger group (N) can collaboratively sign messages without any single party ever possessing the complete private key.
This library supports multiple key generation methods:
- DKG (Distributed Key Generation): Participants collaboratively generate key shares without any trusted party
- Trusted Dealer (planned): A single trusted party generates and distributes shares
Before using this library, participants must coordinate to establish:
- Unique participant IDs (non-zero u16 values, 1-65535)
- Threshold parameters (max_signers, min_signers)
This coordination happens outside the library and is application-specific. Common approaches:
- Centralized coordinator assigns sequential IDs
- Deterministic ordering based on public keys
- Smart contract or blockchain registration
- Manual out-of-band agreement
[dependencies]
frosty = "0.1"
rand = "0.8"Each participant executes three rounds independently, exchanging packages with others at each step:
use frosty::{keygen::Dkg, *};
use rand::rngs::OsRng;
use std::collections::BTreeMap;
// After ID coordination, each participant creates their DKG instance
let mut alice = Dkg::new(1, 3, 2)?; // participant 1, max 3, min 2
// Commit: Generate and broadcast commitment
let alice_commitment = alice.commit(&mut OsRng)?;
// ... broadcast to other participants ...
// Share: Process received commitments
let alice_shares = alice.share(&received_commitments)?;
// ... send targeted shares to recipients ...
// Complete: Generate key share
let (key_share, pubkey) = alice.complete(&received_commitments, &received_shares)?;FROST signing uses a two-phase protocol for optimal performance:
Phase 1: Preprocessing (offline/async)
// Generate signing nonces (can be done before knowing the message)
let alice_nonces = preprocess(&alice_key_share, &mut OsRng)?;
let bob_nonces = preprocess(&bob_key_share, &mut OsRng)?;
// Exchange commitments with other participants
// (In a real system, send these over the network)Phase 2: Signing (online, single round)
let message = b"Hello, FROST!";
let signature = sign(
message,
&[alice_nonces, bob_nonces],
&[alice_key_share, bob_key_share],
&pubkey,
)?;
// Verify using standard ed25519
let ed25519_key = pubkey.to_ed25519_key()?;
verify_signature(&signature, message, &ed25519_key)?;Convenience API (combines both phases):
let message = b"Hello, FROST!";
let signature = threshold_sign(message, &key_shares, &pubkey, &mut OsRng)?;See examples/simple.rs for a complete working example:
cargo run --example simpleKey Generation (keygen module):
Dkg- Coordinates DKG protocol for one participantCommitmentPackage,SharePackage- DKG coordination messages
Core Types:
KeyShare- Secret key share (keep secure)PublicKeyPackage- Shared public keySignature- Threshold signatureParticipantId- Participant identifier
Signing Types:
SigningNonces- Nonces generated during preprocessing (use exactly once)
Signing Functions:
preprocess()- Generate signing nonces (offline/async phase)sign()- Create signature using nonces (online phase)threshold_sign()- Convenience API (combines preprocess + sign)verify_signature()- Verify using ed25519
- Use
OsRngor another cryptographically secure RNG - Never reuse signing nonces - reusing nonces can leak the secret key share
- Never reuse key shares across different DKG ceremonies
- Keep key shares secure - they contain secret material
- Authenticate participants before DKG in production
- Ensure secure communication channels for package exchange
cargo test -p frostyserde- Enable serialization support for all types
MIT OR Apache-2.0
Built on FROST by the Zcash Foundation.