1use frost::keys::{IdentifierList, KeyPackage, PublicKeyPackage};
2use frost::round1::{SigningCommitments, SigningNonces};
3use frost::round2::SignatureShare;
4use frost::{Identifier, SigningPackage};
5use frost_ed25519 as frost;
6pub mod dkg;
7pub mod refresh;
8
9use std::collections::BTreeMap;
10use thiserror::Error;
11
12#[derive(Debug, Error)]
13pub enum ThresholdError {
14 #[error("FROST error: {0}")]
15 Frost(#[from] frost::Error),
16 #[error("Invalid parameters: {0}")]
17 InvalidParams(&'static str),
18 #[error("Serialization error: {0}")]
19 Serialization(String),
20}
21
22pub fn dealer_generate(
24 threshold: u16,
25 max_signers: u16,
26) -> Result<(PublicKeyPackage, BTreeMap<Identifier, KeyPackage>), ThresholdError> {
27 if threshold == 0 || threshold > max_signers {
28 return Err(ThresholdError::InvalidParams(
29 "threshold must be >= 1 and <= max_signers",
30 ));
31 }
32
33 let rng = rand::rngs::OsRng;
34 let (shares, pubkey_package) =
35 frost::keys::generate_with_dealer(max_signers, threshold, IdentifierList::Default, rng)?;
36
37 let mut key_packages = BTreeMap::new();
38 for (id, secret_share) in shares {
39 let key_package = KeyPackage::try_from(secret_share)?;
40 key_packages.insert(id, key_package);
41 }
42
43 Ok((pubkey_package, key_packages))
44}
45
46pub fn threshold_sign_cert(
49 tbs: &[u8],
50 commitments_map: BTreeMap<Identifier, SigningCommitments>,
51 signers: Vec<(Identifier, &KeyPackage, SigningNonces)>,
52 pubkey_package: &PublicKeyPackage,
53) -> Result<[u8; 64], ThresholdError> {
54 let signing_package = SigningPackage::new(commitments_map, tbs);
55
56 let mut signature_shares = BTreeMap::new();
57 for (id, kp, nonces) in signers {
58 let share: SignatureShare = frost::round2::sign(&signing_package, &nonces, kp)?;
59 signature_shares.insert(id, share);
60 }
61
62 let signature = frost::aggregate(&signing_package, &signature_shares, pubkey_package)?;
63 let sig_bytes = signature.serialize()?;
64 let sig_array: [u8; 64] = sig_bytes
65 .try_into()
66 .map_err(|_| ThresholdError::Serialization("expected 64-byte signature".into()))?;
67
68 Ok(sig_array)
69}