From a8159e90703cc28cad3db9606f5ae4a1604c136a Mon Sep 17 00:00:00 2001 From: Luke Parker <lukeparker5132@gmail.com> Date: Wed, 11 Sep 2024 03:23:00 -0400 Subject: [PATCH] Bitcoin Key Gen --- Cargo.lock | 2 ++ processor/bitcoin/Cargo.toml | 2 ++ processor/bitcoin/src/key_gen.rs | 26 ++++++++++++++++++++++++ processor/bitcoin/src/main.rs | 7 +------ processor/key-gen/src/db.rs | 34 +++++++++++++++++++------------- 5 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 processor/bitcoin/src/key_gen.rs diff --git a/Cargo.lock b/Cargo.lock index 1839cc98..8c0c3dd5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8128,6 +8128,7 @@ dependencies = [ "bitcoin-serai", "borsh", "ciphersuite", + "dkg", "env_logger", "flexible-transcript", "log", @@ -8139,6 +8140,7 @@ dependencies = [ "serai-db", "serai-env", "serai-message-queue", + "serai-processor-key-gen", "serai-processor-messages", "serai-processor-primitives", "serai-processor-scanner", diff --git a/processor/bitcoin/Cargo.toml b/processor/bitcoin/Cargo.toml index 54ace26f..c92e1384 100644 --- a/processor/bitcoin/Cargo.toml +++ b/processor/bitcoin/Cargo.toml @@ -25,6 +25,7 @@ borsh = { version = "1", default-features = false, features = ["std", "derive", transcript = { package = "flexible-transcript", path = "../../crypto/transcript", default-features = false, features = ["std", "recommended"] } ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std", "secp256k1"] } +dkg = { path = "../../crypto/dkg", default-features = false, features = ["std", "evrf-secp256k1"] } frost = { package = "modular-frost", path = "../../crypto/frost", default-features = false } secp256k1 = { version = "0.29", default-features = false, features = ["std", "global-context", "rand-std"] } @@ -41,6 +42,7 @@ serai-env = { path = "../../common/env" } serai-client = { path = "../../substrate/client", default-features = false, features = ["bitcoin"] } messages = { package = "serai-processor-messages", path = "../messages" } +key-gen = { package = "serai-processor-key-gen", path = "../key-gen" } primitives = { package = "serai-processor-primitives", path = "../primitives" } scheduler = { package = "serai-processor-scheduler-primitives", path = "../scheduler/primitives" } diff --git a/processor/bitcoin/src/key_gen.rs b/processor/bitcoin/src/key_gen.rs new file mode 100644 index 00000000..16183231 --- /dev/null +++ b/processor/bitcoin/src/key_gen.rs @@ -0,0 +1,26 @@ +use ciphersuite::{group::GroupEncoding, Ciphersuite, Secp256k1}; +use frost::ThresholdKeys; + +use key_gen::KeyGenParams; + +use crate::scan::scanner; + +pub(crate) struct KeyGen; +impl KeyGenParams for KeyGen { + const ID: &'static str = "Bitcoin"; + + type ExternalNetworkCurve = Secp256k1; + + fn tweak_keys(keys: &mut ThresholdKeys<Self::ExternalNetworkCurve>) { + *keys = bitcoin_serai::wallet::tweak_keys(keys); + // Also create a scanner to assert these keys, and all expected paths, are usable + scanner(keys.group_key()); + } + + fn encode_key(key: <Self::ExternalNetworkCurve as Ciphersuite>::G) -> Vec<u8> { + let key = key.to_bytes(); + let key: &[u8] = key.as_ref(); + // Skip the parity encoding as we know this key is even + key[1 ..].to_vec() + } +} diff --git a/processor/bitcoin/src/main.rs b/processor/bitcoin/src/main.rs index 2ff072b4..d86a4ba1 100644 --- a/processor/bitcoin/src/main.rs +++ b/processor/bitcoin/src/main.rs @@ -13,6 +13,7 @@ pub(crate) use primitives::*; mod scan; // App-logic trait satisfactions +mod key_gen; mod rpc; mod scheduler; @@ -224,12 +225,6 @@ impl Network for Bitcoin { // aggregation TX const COST_TO_AGGREGATE: u64 = 800; - fn tweak_keys(keys: &mut ThresholdKeys<Self::Curve>) { - *keys = tweak_keys(keys); - // Also create a scanner to assert these keys, and all expected paths, are usable - scanner(keys.group_key()); - } - #[cfg(test)] async fn get_block_number(&self, id: &[u8; 32]) -> usize { self.rpc.get_block_number(id).await.unwrap() diff --git a/processor/key-gen/src/db.rs b/processor/key-gen/src/db.rs index e82b84a5..676fd2aa 100644 --- a/processor/key-gen/src/db.rs +++ b/processor/key-gen/src/db.rs @@ -9,7 +9,7 @@ use dkg::{Participant, ThresholdCore, ThresholdKeys, evrf::EvrfCurve}; use serai_validator_sets_primitives::Session; use borsh::{BorshSerialize, BorshDeserialize}; -use serai_db::{Get, DbTxn, create_db}; +use serai_db::{Get, DbTxn}; use crate::KeyGenParams; @@ -35,20 +35,26 @@ pub(crate) struct Participations { pub(crate) network_participations: HashMap<Participant, Vec<u8>>, } -create_db!( - KeyGen { - Params: (session: &Session) -> RawParams, - Participations: (session: &Session) -> Participations, - KeyShares: (session: &Session) -> Vec<u8>, - } -); +mod _db { + use serai_validator_sets_primitives::Session; + + use serai_db::{Get, DbTxn, create_db}; + + create_db!( + KeyGen { + Params: (session: &Session) -> super::RawParams, + Participations: (session: &Session) -> super::Participations, + KeyShares: (session: &Session) -> Vec<u8>, + } + ); +} pub(crate) struct KeyGenDb<P: KeyGenParams>(PhantomData<P>); impl<P: KeyGenParams> KeyGenDb<P> { pub(crate) fn set_params(txn: &mut impl DbTxn, session: Session, params: Params<P>) { assert_eq!(params.substrate_evrf_public_keys.len(), params.network_evrf_public_keys.len()); - Params::set( + _db::Params::set( txn, &session, &RawParams { @@ -68,7 +74,7 @@ impl<P: KeyGenParams> KeyGenDb<P> { } pub(crate) fn params(getter: &impl Get, session: Session) -> Option<Params<P>> { - Params::get(getter, &session).map(|params| Params { + _db::Params::get(getter, &session).map(|params| Params { t: params.t, n: params .network_evrf_public_keys @@ -101,10 +107,10 @@ impl<P: KeyGenParams> KeyGenDb<P> { session: Session, participations: &Participations, ) { - Participations::set(txn, &session, participations) + _db::Participations::set(txn, &session, participations) } pub(crate) fn participations(getter: &impl Get, session: Session) -> Option<Participations> { - Participations::get(getter, &session) + _db::Participations::get(getter, &session) } // Set the key shares for a session. @@ -121,7 +127,7 @@ impl<P: KeyGenParams> KeyGenDb<P> { keys.extend(substrate_keys.serialize().as_slice()); keys.extend(network_keys.serialize().as_slice()); } - KeyShares::set(txn, &session, &keys); + _db::KeyShares::set(txn, &session, &keys); } #[allow(clippy::type_complexity)] @@ -129,7 +135,7 @@ impl<P: KeyGenParams> KeyGenDb<P> { getter: &impl Get, session: Session, ) -> Option<(Vec<ThresholdKeys<Ristretto>>, Vec<ThresholdKeys<P::ExternalNetworkCurve>>)> { - let keys = KeyShares::get(getter, &session)?; + let keys = _db::KeyShares::get(getter, &session)?; let mut keys: &[u8] = keys.as_ref(); let mut substrate_keys = vec![];