use std::{io, collections::HashMap}; use rand_core::{RngCore, CryptoRng}; use ciphersuite::{Ciphersuite, Secp256k1}; use frost::{ dkg::{Participant, ThresholdKeys}, FrostError, algorithm::*, sign::*, }; use ethereum_schnorr::{PublicKey, Signature}; use crate::transaction::{Action, Transaction}; /// The HRAm to use for the Schnorr Solidity library. /// /// This will panic if the public key being signed for is not representable within the Schnorr /// Solidity library. #[derive(Clone, Default, Debug)] pub struct EthereumHram; impl Hram for EthereumHram { #[allow(non_snake_case)] fn hram( R: &::G, A: &::G, m: &[u8], ) -> ::F { Signature::challenge(*R, &PublicKey::new(*A).unwrap(), m) } } /// A clonable machine to sign an action. /// /// This will panic if the public key being signed with is not representable within the Schnorr /// Solidity library. #[derive(Clone)] pub(crate) struct ClonableTransctionMachine { pub(crate) keys: ThresholdKeys, pub(crate) action: Action, } type LiteralAlgorithmMachine = AlgorithmMachine>; type LiteralAlgorithmSignMachine = AlgorithmSignMachine>; pub(crate) struct ActionSignMachine { key: PublicKey, action: Action, machine: LiteralAlgorithmSignMachine, } type LiteralAlgorithmSignatureMachine = AlgorithmSignatureMachine>; pub(crate) struct ActionSignatureMachine { key: PublicKey, action: Action, machine: LiteralAlgorithmSignatureMachine, } impl PreprocessMachine for ClonableTransctionMachine { type Preprocess = ::Preprocess; type Signature = Transaction; type SignMachine = ActionSignMachine; fn preprocess( self, rng: &mut R, ) -> (Self::SignMachine, Self::Preprocess) { let (machine, preprocess) = AlgorithmMachine::new(IetfSchnorr::::ietf(), self.keys.clone()) .preprocess(rng); ( ActionSignMachine { key: PublicKey::new(self.keys.group_key()).expect("signing with non-representable key"), action: self.action, machine, }, preprocess, ) } } impl SignMachine for ActionSignMachine { type Params = ::Signature, >>::Params; type Keys = ::Signature, >>::Keys; type Preprocess = ::Signature, >>::Preprocess; type SignatureShare = ::Signature, >>::SignatureShare; type SignatureMachine = ActionSignatureMachine; fn cache(self) -> CachedPreprocess { unimplemented!() } fn from_cache( params: Self::Params, keys: Self::Keys, cache: CachedPreprocess, ) -> (Self, Self::Preprocess) { unimplemented!() } fn read_preprocess(&self, reader: &mut R) -> io::Result { self.machine.read_preprocess(reader) } fn sign( self, commitments: HashMap, msg: &[u8], ) -> Result<(Self::SignatureMachine, Self::SignatureShare), FrostError> { assert!(msg.is_empty()); self.machine.sign(commitments, &self.action.message()).map(|(machine, shares)| { (ActionSignatureMachine { key: self.key, action: self.action, machine }, shares) }) } } impl SignatureMachine for ActionSignatureMachine { type SignatureShare = ::Signature, >>::SignatureShare; fn read_share(&self, reader: &mut R) -> io::Result { self.machine.read_share(reader) } fn complete( self, shares: HashMap, ) -> Result { self.machine.complete(shares).map(|signature| { let s = signature.s; let c = Signature::challenge(signature.R, &self.key, &self.action.message()); Transaction(self.action, Signature::new(c, s)) }) } }