From 98c3f75fa25610f7f14b1c333e5f9a4681323374 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Wed, 18 Sep 2024 01:09:42 -0400 Subject: [PATCH] Move the Ethereum Action machine to its own file --- Cargo.lock | 5 - Cargo.toml | 3 - processor/ethereum/src/primitives/machine.rs | 146 ++++++++++++++++ processor/ethereum/src/primitives/mod.rs | 1 + .../ethereum/src/primitives/transaction.rs | 158 +----------------- processor/ethereum/src/publisher.rs | 8 + 6 files changed, 163 insertions(+), 158 deletions(-) create mode 100644 processor/ethereum/src/primitives/machine.rs diff --git a/Cargo.lock b/Cargo.lock index a7f3792a..7e51ec8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11890,8 +11890,3 @@ dependencies = [ "cc", "pkg-config", ] - -[[patch.unused]] -name = "alloy-sol-type-parser" -version = "0.8.0" -source = "git+https://github.com/alloy-rs/core?rev=446b9d2fbce12b88456152170709a3eaac929af0#446b9d2fbce12b88456152170709a3eaac929af0" diff --git a/Cargo.toml b/Cargo.toml index 99a10be0..d0c91a30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -204,9 +204,6 @@ directories-next = { path = "patches/directories-next" } # The official pasta_curves repo doesn't support Zeroize pasta_curves = { git = "https://github.com/kayabaNerve/pasta_curves", rev = "a46b5be95cacbff54d06aad8d3bbcba42e05d616" } -# https://github.com/alloy-rs/core/issues/717 -alloy-sol-type-parser = { git = "https://github.com/alloy-rs/core", rev = "446b9d2fbce12b88456152170709a3eaac929af0" } - [workspace.lints.clippy] unwrap_or_default = "allow" borrow_as_ptr = "deny" diff --git a/processor/ethereum/src/primitives/machine.rs b/processor/ethereum/src/primitives/machine.rs new file mode 100644 index 00000000..f37fb440 --- /dev/null +++ b/processor/ethereum/src/primitives/machine.rs @@ -0,0 +1,146 @@ +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)) + }) + } +} diff --git a/processor/ethereum/src/primitives/mod.rs b/processor/ethereum/src/primitives/mod.rs index 8d2a9118..f0d31802 100644 --- a/processor/ethereum/src/primitives/mod.rs +++ b/processor/ethereum/src/primitives/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod output; pub(crate) mod transaction; +pub(crate) mod machine; pub(crate) mod block; pub(crate) const DAI: [u8; 20] = diff --git a/processor/ethereum/src/primitives/transaction.rs b/processor/ethereum/src/primitives/transaction.rs index eeba3180..52595375 100644 --- a/processor/ethereum/src/primitives/transaction.rs +++ b/processor/ethereum/src/primitives/transaction.rs @@ -1,14 +1,7 @@ -use std::{io, collections::HashMap}; +use std::io; -use rand_core::{RngCore, CryptoRng}; - -use ciphersuite::{Ciphersuite, Secp256k1}; -use frost::{ - dkg::{Participant, ThresholdKeys}, - FrostError, - algorithm::*, - sign::*, -}; +use ciphersuite::Secp256k1; +use frost::dkg::ThresholdKeys; use alloy_core::primitives::U256; @@ -20,7 +13,7 @@ use ethereum_primitives::keccak256; use ethereum_schnorr::{PublicKey, Signature}; use ethereum_router::{Coin, OutInstructions, Executed, Router}; -use crate::output::OutputId; +use crate::{output::OutputId, machine::ClonableTransctionMachine}; #[derive(Clone, PartialEq, Debug)] pub(crate) enum Action { @@ -32,13 +25,13 @@ pub(crate) enum Action { pub(crate) struct Eventuality(pub(crate) Executed); impl Action { - fn nonce(&self) -> u64 { + pub(crate) fn nonce(&self) -> u64 { match self { Action::SetKey { nonce, .. } | Action::Batch { nonce, .. } => *nonce, } } - fn message(&self) -> Vec { + pub(crate) fn message(&self) -> Vec { match self { Action::SetKey { chain_id, nonce, key } => { Router::update_serai_key_message(*chain_id, *nonce, key) @@ -67,155 +60,20 @@ impl Action { } #[derive(Clone, PartialEq, Debug)] -pub(crate) struct Transaction(Action, Signature); +pub(crate) struct Transaction(pub(crate) Action, pub(crate) Signature); impl scheduler::Transaction for Transaction { fn read(reader: &mut impl io::Read) -> io::Result { - /* - let buf: Vec = borsh::from_reader(reader)?; - // We can only read this from a &[u8], hence prior reading into a Vec - ::decode(&mut buf.as_slice()) - .map(Self) - .map_err(io::Error::other) - */ let action = Action::read(reader)?; let signature = Signature::read(reader)?; Ok(Transaction(action, signature)) } fn write(&self, writer: &mut impl io::Write) -> io::Result<()> { - /* - let mut buf = Vec::with_capacity(256); - ::encode(&self.0, &mut buf); - borsh::BorshSerialize::serialize(&buf, writer) - */ self.0.write(writer)?; self.1.write(writer)?; Ok(()) } } -/// 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) - } -} - -#[derive(Clone)] -pub(crate) struct ClonableTransctionMachine(ThresholdKeys, Action); - -type LiteralAlgorithmMachine = AlgorithmMachine>; -type LiteralAlgorithmSignMachine = - AlgorithmSignMachine>; - -pub(crate) struct ActionSignMachine(PublicKey, Action, LiteralAlgorithmSignMachine); - -type LiteralAlgorithmSignatureMachine = - AlgorithmSignatureMachine>; - -pub(crate) struct ActionSignatureMachine(PublicKey, Action, 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.0.clone()) - .preprocess(rng); - ( - ActionSignMachine( - PublicKey::new(self.0.group_key()).expect("signing with non-representable key"), - self.1, - 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.2.read_preprocess(reader) - } - fn sign( - self, - commitments: HashMap, - msg: &[u8], - ) -> Result<(Self::SignatureMachine, Self::SignatureShare), FrostError> { - assert!(msg.is_empty()); - self - .2 - .sign(commitments, &self.1.message()) - .map(|(machine, shares)| (ActionSignatureMachine(self.0, self.1, machine), shares)) - } -} - -impl SignatureMachine for ActionSignatureMachine { - type SignatureShare = ::Signature, - >>::SignatureShare; - - fn read_share(&self, reader: &mut R) -> io::Result { - self.2.read_share(reader) - } - - fn complete( - self, - shares: HashMap, - ) -> Result { - /* - match self.1 { - Action::SetKey { chain_id: _, nonce: _, key } => self.0.update_serai_key(key, signature), - Action::Batch { chain_id: _, nonce: _, outs } => self.0.execute(outs, signature), - } - */ - self.2.complete(shares).map(|signature| { - let s = signature.s; - let c = Signature::challenge(signature.R, &self.0, &self.1.message()); - Transaction(self.1, Signature::new(c, s)) - }) - } -} - impl SignableTransaction for Action { type Transaction = Transaction; type Ciphersuite = Secp256k1; @@ -296,7 +154,7 @@ impl SignableTransaction for Action { } fn sign(self, keys: ThresholdKeys) -> Self::PreprocessMachine { - ClonableTransctionMachine(keys, self) + ClonableTransctionMachine { keys, action: self } } } diff --git a/processor/ethereum/src/publisher.rs b/processor/ethereum/src/publisher.rs index ad8bd09d..1874e556 100644 --- a/processor/ethereum/src/publisher.rs +++ b/processor/ethereum/src/publisher.rs @@ -20,6 +20,14 @@ impl signers::TransactionPublisher for TransactionPublisher { &self, tx: Transaction, ) -> impl Send + Future> { + // Convert from an Action (an internal representation of a signable event) to a TxLegacy + /* TODO + match tx.0 { + Action::SetKey { chain_id: _, nonce: _, key } => self.router.update_serai_key(key, tx.1), + Action::Batch { chain_id: _, nonce: _, outs } => self.router.execute(outs, tx.1), + } + */ + async move { /* use tokio::{