Module frost

Module frost 

Source
Expand description

FROST: Flexible Round-Optimized Schnorr Threshold Signatures

FROST is a threshold signature scheme that produces standard Schnorr signatures with only 2 rounds of communication. It’s significantly more efficient than threshold ECDSA while maintaining strong security properties.

§Features

  • 2-round signing protocol: More efficient than threshold ECDSA (3+ rounds)
  • Standard Schnorr signatures: Output is indistinguishable from single-party Schnorr
  • Robust against rogue-key attacks: Using proof-of-possession
  • Supports any t-of-n threshold: Flexible threshold configurations
  • Dealer-free key generation: Based on Pedersen DKG

§Protocol Overview

  1. Key Generation Phase (one-time setup):

    • Run distributed key generation (DKG) to create shares
    • Each participant gets a secret share and the group public key
  2. Preprocessing Phase (can be done in advance):

    • Each signer generates commitment pairs (d, e) and sends commitments
    • Stores (d, e, D, E) for later use
  3. Signing Round 1:

    • Coordinator selects signing set and message
    • Each signer reveals one commitment pair (D_i, E_i)
  4. Signing Round 2:

    • Coordinator computes binding value and challenge
    • Each signer computes partial signature z_i
    • Coordinator aggregates into full signature (R, z)

§Example

use chie_crypto::frost::{FrostKeygen, FrostSigner, aggregate_frost_signatures, verify_frost_signature};

// Setup: 2-of-3 threshold
let threshold = 2;
let num_signers = 3;

// Key generation (one-time setup)
let mut keygen = FrostKeygen::new(threshold, num_signers);
let shares = keygen.generate_shares();

// Create signers
let mut signers: Vec<_> = shares.iter().enumerate()
    .map(|(i, share)| FrostSigner::new(i + 1, share.clone(), keygen.group_public_key()))
    .collect();

// Preprocessing: Generate nonce commitments
for signer in &mut signers {
    signer.preprocess();
}

let message = b"Transaction data";

// Signing Round 1: Collect nonce commitments from threshold signers
let signing_set = vec![1, 2]; // Use signers 1 and 2
let commitments: Vec<_> = signing_set.iter()
    .map(|&id| signers[id - 1].get_nonce_commitment())
    .collect();

// Signing Round 2: Generate partial signatures
let partial_sigs: Vec<_> = signing_set.iter()
    .map(|&id| signers[id - 1].sign(message, &signing_set, &commitments))
    .collect::<Result<Vec<_>, _>>()
    .unwrap();

// Aggregate into final signature
let signature = aggregate_frost_signatures(
    message,
    &signing_set,
    &commitments,
    &partial_sigs,
).unwrap();

// Verify with group public key
assert!(verify_frost_signature(&keygen.group_public_key(), message, &signature).is_ok());

Structs§

FrostKeygen
FROST key generation using Pedersen DKG
FrostNonceCommitment
Nonce commitment pair for FROST preprocessing
FrostSecretShare
Secret share for a FROST participant
FrostSigner
FROST signer instance
PartialSignature
Partial signature from a FROST signer

Enums§

FrostError

Functions§

aggregate_frost_signatures
Aggregate partial signatures into a full Schnorr signature
verify_frost_signature
Verify a FROST signature

Type Aliases§

FrostResult