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.