Go to file
Deirdre Connolly 1d5740f8ec ci(Mergify): configuration update
Signed-off-by: Deirdre Connolly <null>
2022-06-15 20:13:45 -04:00
.github Bump codecov/codecov-action from 2.1.0 to 3 2022-04-08 17:21:43 -04:00
frost-core Merge pull request #50 from ZcashFoundation/frost-core 2022-05-16 16:53:17 -04:00
frost-redjubjub Fix typos 2022-02-08 18:52:02 -05:00
frost-ristretto255 Merge pull request #50 from ZcashFoundation/frost-core 2022-05-16 16:53:17 -04:00
rfcs add missing checks 2021-06-15 17:10:38 -04:00
.DS_Store A bunch of fixes 2022-03-03 12:55:45 -05:00
.gitignore Ignore .DS_Store 2022-03-08 14:11:41 -05:00
.mergify.yml ci(Mergify): configuration update 2022-06-15 20:13:45 -04:00
CHANGELOG.md Don't reject small-order verification keys (#137) 2021-11-18 15:53:35 -03:00
Cargo.toml Reorg for FROST 2021-12-13 07:26:52 -05:00
LICENCE Frost keygen with dealer (#47) 2021-02-25 09:06:54 -07:00
LICENCE.MIT Frost keygen with dealer (#47) 2021-02-25 09:06:54 -07:00
LICENSE.Apache-2.0 Frost keygen with dealer (#47) 2021-02-25 09:06:54 -07:00
README.md Add README.md for frost-core and update for root of repo (#52) 2022-04-08 09:02:49 -06:00
codecov.yml Add CodeCov config file (#51) 2021-01-19 20:16:54 -05:00

README.md

FROST (Flexible Round-Optimised Schnorr Threshold signatures)

Rust implementations of 'Two-Round Threshold Schnorr Signatures with FROST'.

Unlike signatures in a single-party setting, threshold signatures require cooperation among a threshold number of signers, each holding a share of a common private key. The security of threshold schemes in general assume that an adversary can corrupt strictly fewer than a threshold number of participants.

'Two-Round Threshold Schnorr Signatures with FROST' presents a variant of a Flexible Round-Optimized Schnorr Threshold (FROST) signature scheme originally defined in FROST20. FROST reduces network overhead during threshold signing operations while employing a novel technique to protect against forgery attacks applicable to prior Schnorr-based threshold signature constructions. This variant of FROST requires two rounds to compute a signature, and implements signing efficiency improvements described by Schnorr21. Single-round signing with FROST is not implemented here.

Status ⚠

The FROST specification is not yet finalized, and this codebase has not yet been audited or released. The APIs and types in frost-core are subject to change.

Usage

frost-core implements the base traits and types in a generic manner, to enable top-level implementations for different ciphersuites / curves without having to implement all of FROST from scratch. End-users should not use frost-core if they want to sign and verify signatures, they should use the crate specific to their ciphersuite/curve parameters that uses frost-core as a dependency.

Example

use std::{collections::HashMap, convert::TryFrom};

use rand::thread_rng;

use frost_ristretto255::frost;

let mut rng = thread_rng();
let numsigners = 5;
let threshold = 3;
let (shares, pubkeys) =
  frost::keys::keygen_with_dealer(numsigners, threshold, &mut rng).unwrap();

// Verifies the secret shares from the dealer
let key_packages: Vec<frost::keys::KeyPackage> = shares
  .into_iter()
  .map(|share| frost::keys::KeyPackage::try_from(share).unwrap())
  .collect();

let mut nonces: HashMap<u16, Vec<frost::round1::SigningNonces>> = HashMap::new();
let mut commitments: HashMap<u16, Vec<frost::round1::SigningCommitments>> = HashMap::new();

////////////////////////////////////////////////////////////////////////////
// Round 1: generating nonces and signing commitments for each participant
////////////////////////////////////////////////////////////////////////////

for participant_index in 1..(threshold + 1) {
  // Generate one (1) nonce and one SigningCommitments instance for each
  // participant, up to _threshold_.
  let (nonce, commitment) = frost::round1::preprocess(1, participant_index as u16, &mut rng);
  nonces.insert(participant_index as u16, nonce);
  commitments.insert(participant_index as u16, commitment);
}

// This is what the signature aggregator / coordinator needs to do:
// - decide what message to sign
// - take one (unused) commitment per signing participant
let mut signature_shares: Vec<frost::round2::SignatureShare> = Vec::new();
let message = "message to sign".as_bytes();
let comms = commitments.clone().into_values().flatten().collect();
let signing_package = frost::SigningPackage::new(comms, message.to_vec());

////////////////////////////////////////////////////////////////////////////
// Round 2: each participant generates their signature share
////////////////////////////////////////////////////////////////////////////

for participant_index in nonces.keys() {
  let key_package = key_packages
    .iter()
    .find(|key_package| *participant_index == key_package.index)
    .unwrap();

  let nonces_to_use = nonces.get(participant_index).unwrap()[0];

  // Each participant generates their signature share.
  let signature_share =
    frost::round2::sign(&signing_package, &nonces_to_use, key_package).unwrap();
  signature_shares.push(signature_share);
}

////////////////////////////////////////////////////////////////////////////
// Aggregation: collects the signing shares from all participants,
// generates the final signature.
////////////////////////////////////////////////////////////////////////////

// Aggregate (also verifies the signature shares)
let group_signature_res = frost::aggregate(&signing_package, &signature_shares[..], &pubkeys);

assert!(group_signature_res.is_ok());

let group_signature = group_signature_res.unwrap();

// Check that the threshold signature can be verified by the group public
// key (the verification key).
assert!(pubkeys
  .group_public
  .verify(message, &group_signature)
  .is_ok());

// Check that the threshold signature can be verified by the group public
// key (the verification key) from SharePackage.group_public
for (participant_index, _) in nonces.clone() {
  let key_package = key_packages.get(participant_index as usize).unwrap();

  assert!(key_package
    .group_public
    .verify(message, &group_signature)
    .is_ok());
}