use crate::error::{Result, ThresholdError};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
#[cfg(feature = "frost-ed25519")]
use frost_ed25519 as frost;
#[cfg(all(feature = "frost-secp256k1", not(feature = "frost-ed25519")))]
use frost_secp256k1 as frost;
#[derive(Clone)]
pub struct SigningShare {
identifier: frost::Identifier,
share: frost::keys::SigningShare,
}
impl SigningShare {
pub fn from_frost(id: frost::Identifier, share: frost::keys::SigningShare) -> Self {
Self {
identifier: id,
share,
}
}
pub fn identifier(&self) -> frost::Identifier {
self.identifier
}
pub fn inner(&self) -> &frost::keys::SigningShare {
&self.share
}
}
impl std::fmt::Debug for SigningShare {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SigningShare(id={:?})", self.identifier)
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct VerifyingShare {
identifier_bytes: Vec<u8>,
bytes: Vec<u8>,
}
impl VerifyingShare {
pub fn from_frost(id: frost::Identifier, share: &frost::keys::VerifyingShare) -> Result<Self> {
Ok(Self {
identifier_bytes: id.serialize(),
bytes: share
.serialize()
.map_err(|e| ThresholdError::SerializationError(e.to_string()))?,
})
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
}
impl std::fmt::Debug for VerifyingShare {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "VerifyingShare({} bytes)", self.identifier_bytes.len())
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct GroupVerifyingKey {
bytes: Vec<u8>,
}
impl GroupVerifyingKey {
pub fn from_frost(key: &frost::VerifyingKey) -> Result<Self> {
Ok(Self {
bytes: key
.serialize()
.map_err(|e| ThresholdError::SerializationError(e.to_string()))?,
})
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn to_frost(&self) -> Result<frost::VerifyingKey> {
frost::VerifyingKey::deserialize(&self.bytes)
.map_err(|e| ThresholdError::InternalError(e.to_string()))
}
}
impl std::fmt::Debug for GroupVerifyingKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "GroupVerifyingKey({} bytes)", self.bytes.len())
}
}
pub struct FrostSigner {
key_package: frost::keys::KeyPackage,
}
impl FrostSigner {
pub fn new(key_package: frost::keys::KeyPackage) -> Self {
Self { key_package }
}
pub fn identifier(&self) -> frost::Identifier {
*self.key_package.identifier()
}
pub fn group_verifying_key(&self) -> Result<GroupVerifyingKey> {
GroupVerifyingKey::from_frost(self.key_package.verifying_key())
}
pub fn round1(&self) -> Result<(SigningNonces, SigningCommitments)> {
let mut rng = rand::rngs::OsRng;
let (nonces, commitments) =
frost::round1::commit(self.key_package.signing_share(), &mut rng);
Ok((
SigningNonces { inner: nonces },
SigningCommitments::from_frost(self.identifier(), &commitments)?,
))
}
pub fn round2(
&self,
_message: &[u8],
nonces: &SigningNonces,
signing_package: &SigningPackage,
) -> Result<SignatureShare> {
let sig_share =
frost::round2::sign(&signing_package.inner, &nonces.inner, &self.key_package)
.map_err(|e| ThresholdError::SigningError(e.to_string()))?;
Ok(SignatureShare::from_frost(self.identifier(), &sig_share))
}
}
pub struct SigningNonces {
inner: frost::round1::SigningNonces,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct SigningCommitments {
identifier_bytes: Vec<u8>,
bytes: Vec<u8>,
}
impl SigningCommitments {
fn from_frost(id: frost::Identifier, c: &frost::round1::SigningCommitments) -> Result<Self> {
Ok(Self {
identifier_bytes: id.serialize(),
bytes: c
.serialize()
.map_err(|e| ThresholdError::SerializationError(e.to_string()))?,
})
}
fn to_frost(&self) -> Result<(frost::Identifier, frost::round1::SigningCommitments)> {
let id = frost::Identifier::deserialize(&self.identifier_bytes)
.map_err(|e| ThresholdError::InternalError(e.to_string()))?;
let commitments = frost::round1::SigningCommitments::deserialize(&self.bytes)
.map_err(|e| ThresholdError::InternalError(e.to_string()))?;
Ok((id, commitments))
}
}
pub struct SigningPackage {
inner: frost::SigningPackage,
}
impl SigningPackage {
pub fn new(commitments: &[SigningCommitments], message: &[u8]) -> Result<Self> {
let mut commitment_map = BTreeMap::new();
for c in commitments {
let (id, frost_c) = c.to_frost()?;
commitment_map.insert(id, frost_c);
}
let inner = frost::SigningPackage::new(commitment_map, message);
Ok(Self { inner })
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct SignatureShare {
identifier_bytes: Vec<u8>,
bytes: Vec<u8>,
}
impl SignatureShare {
fn from_frost(id: frost::Identifier, share: &frost::round2::SignatureShare) -> Self {
Self {
identifier_bytes: id.serialize(),
bytes: share.serialize(),
}
}
fn to_frost(&self) -> Result<(frost::Identifier, frost::round2::SignatureShare)> {
let id = frost::Identifier::deserialize(&self.identifier_bytes)
.map_err(|e| ThresholdError::InternalError(e.to_string()))?;
let share = frost::round2::SignatureShare::deserialize(&self.bytes)
.map_err(|e| ThresholdError::InternalError(e.to_string()))?;
Ok((id, share))
}
}
pub struct FrostVerifier {
verifying_key: frost::VerifyingKey,
}
impl FrostVerifier {
pub fn new(key: &GroupVerifyingKey) -> Result<Self> {
Ok(Self {
verifying_key: key.to_frost()?,
})
}
pub fn aggregate(
&self,
signing_package: &SigningPackage,
signature_shares: &[SignatureShare],
pubkey_package: &PublicKeyPackage,
) -> Result<Signature> {
let mut share_map = BTreeMap::new();
for share in signature_shares {
let (id, frost_share) = share.to_frost()?;
share_map.insert(id, frost_share);
}
let signature = frost::aggregate(&signing_package.inner, &share_map, &pubkey_package.inner)
.map_err(|e| ThresholdError::SigningError(e.to_string()))?;
Ok(Signature {
bytes: signature
.serialize()
.map_err(|e| ThresholdError::SerializationError(e.to_string()))?,
})
}
#[must_use = "signature verification must be checked - ignoring bypasses authentication"]
pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<bool> {
let sig = frost::Signature::deserialize(&signature.bytes)
.map_err(|_| ThresholdError::InvalidSignature)?;
self.verifying_key
.verify(message, &sig)
.map(|_| true)
.map_err(|_| ThresholdError::InvalidSignature)
}
}
#[derive(Clone)]
pub struct PublicKeyPackage {
inner: frost::keys::PublicKeyPackage,
}
impl PublicKeyPackage {
pub fn from_frost(pkg: frost::keys::PublicKeyPackage) -> Self {
Self { inner: pkg }
}
pub fn group_verifying_key(&self) -> Result<GroupVerifyingKey> {
GroupVerifyingKey::from_frost(self.inner.verifying_key())
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct Signature {
bytes: Vec<u8>,
}
impl Signature {
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn len(&self) -> usize {
self.bytes.len()
}
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
}
impl std::fmt::Debug for Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Signature({} bytes)", self.bytes.len())
}
}
pub fn trusted_dealer_keygen(
threshold: u16,
total: u16,
) -> Result<(Vec<frost::keys::SecretShare>, frost::keys::PublicKeyPackage)> {
let mut rng = rand::rngs::OsRng;
let (shares, pubkeys) = frost::keys::generate_with_dealer(
total,
threshold,
frost::keys::IdentifierList::Default,
&mut rng,
)
.map_err(|e| ThresholdError::InternalError(e.to_string()))?;
Ok((shares.into_values().collect(), pubkeys))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_frost_trusted_dealer() {
let threshold = 2u16;
let total = 3u16;
let (shares, _pubkey_package) = trusted_dealer_keygen(threshold, total).unwrap();
assert_eq!(shares.len(), total as usize);
for share in &shares {
let key_package = frost::keys::KeyPackage::try_from(share.clone()).unwrap();
let _ = FrostSigner::new(key_package);
}
}
#[test]
fn test_frost_signing_flow() {
let threshold = 2u16;
let total = 3u16;
let message = b"Test message for FROST signing";
let (shares, pubkey_package) = trusted_dealer_keygen(threshold, total).unwrap();
let key_packages: Vec<_> = shares
.iter()
.take(threshold as usize)
.map(|s| frost::keys::KeyPackage::try_from(s.clone()).unwrap())
.collect();
let signers: Vec<_> = key_packages
.iter()
.map(|kp| FrostSigner::new(kp.clone()))
.collect();
let mut all_nonces = Vec::new();
let mut all_commitments = Vec::new();
for signer in &signers {
let (nonces, commitments) = signer.round1().unwrap();
all_nonces.push(nonces);
all_commitments.push(commitments);
}
let signing_package = SigningPackage::new(&all_commitments, message).unwrap();
let mut signature_shares = Vec::new();
for (i, signer) in signers.iter().enumerate() {
let share = signer
.round2(message, &all_nonces[i], &signing_package)
.unwrap();
signature_shares.push(share);
}
let group_key = GroupVerifyingKey::from_frost(pubkey_package.verifying_key()).unwrap();
let verifier = FrostVerifier::new(&group_key).unwrap();
let pkg = PublicKeyPackage::from_frost(pubkey_package);
let signature = verifier
.aggregate(&signing_package, &signature_shares, &pkg)
.unwrap();
assert!(verifier.verify(message, &signature).unwrap());
}
#[test]
fn test_frost_wrong_message_fails() {
let threshold = 2u16;
let total = 3u16;
let message = b"Original message";
let wrong_message = b"Wrong message";
let (shares, pubkey_package) = trusted_dealer_keygen(threshold, total).unwrap();
let key_packages: Vec<_> = shares
.iter()
.take(threshold as usize)
.map(|s| frost::keys::KeyPackage::try_from(s.clone()).unwrap())
.collect();
let signers: Vec<_> = key_packages
.iter()
.map(|kp| FrostSigner::new(kp.clone()))
.collect();
let mut all_nonces = Vec::new();
let mut all_commitments = Vec::new();
for signer in &signers {
let (nonces, commitments) = signer.round1().unwrap();
all_nonces.push(nonces);
all_commitments.push(commitments);
}
let signing_package = SigningPackage::new(&all_commitments, message).unwrap();
let mut signature_shares = Vec::new();
for (i, signer) in signers.iter().enumerate() {
let share = signer
.round2(message, &all_nonces[i], &signing_package)
.unwrap();
signature_shares.push(share);
}
let group_key = GroupVerifyingKey::from_frost(pubkey_package.verifying_key()).unwrap();
let verifier = FrostVerifier::new(&group_key).unwrap();
let pkg = PublicKeyPackage::from_frost(pubkey_package);
let signature = verifier
.aggregate(&signing_package, &signature_shares, &pkg)
.unwrap();
assert!(verifier.verify(wrong_message, &signature).is_err());
}
}