Bitcoin Key Gen

This commit is contained in:
Luke Parker
2024-09-11 03:23:00 -04:00
parent b61ba9d1bb
commit a8159e9070
5 changed files with 51 additions and 20 deletions

2
Cargo.lock generated
View File

@@ -8128,6 +8128,7 @@ dependencies = [
"bitcoin-serai", "bitcoin-serai",
"borsh", "borsh",
"ciphersuite", "ciphersuite",
"dkg",
"env_logger", "env_logger",
"flexible-transcript", "flexible-transcript",
"log", "log",
@@ -8139,6 +8140,7 @@ dependencies = [
"serai-db", "serai-db",
"serai-env", "serai-env",
"serai-message-queue", "serai-message-queue",
"serai-processor-key-gen",
"serai-processor-messages", "serai-processor-messages",
"serai-processor-primitives", "serai-processor-primitives",
"serai-processor-scanner", "serai-processor-scanner",

View File

@@ -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"] } transcript = { package = "flexible-transcript", path = "../../crypto/transcript", default-features = false, features = ["std", "recommended"] }
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std", "secp256k1"] } 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 } frost = { package = "modular-frost", path = "../../crypto/frost", default-features = false }
secp256k1 = { version = "0.29", default-features = false, features = ["std", "global-context", "rand-std"] } 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"] } serai-client = { path = "../../substrate/client", default-features = false, features = ["bitcoin"] }
messages = { package = "serai-processor-messages", path = "../messages" } messages = { package = "serai-processor-messages", path = "../messages" }
key-gen = { package = "serai-processor-key-gen", path = "../key-gen" }
primitives = { package = "serai-processor-primitives", path = "../primitives" } primitives = { package = "serai-processor-primitives", path = "../primitives" }
scheduler = { package = "serai-processor-scheduler-primitives", path = "../scheduler/primitives" } scheduler = { package = "serai-processor-scheduler-primitives", path = "../scheduler/primitives" }

View File

@@ -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()
}
}

View File

@@ -13,6 +13,7 @@ pub(crate) use primitives::*;
mod scan; mod scan;
// App-logic trait satisfactions // App-logic trait satisfactions
mod key_gen;
mod rpc; mod rpc;
mod scheduler; mod scheduler;
@@ -224,12 +225,6 @@ impl Network for Bitcoin {
// aggregation TX // aggregation TX
const COST_TO_AGGREGATE: u64 = 800; 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)] #[cfg(test)]
async fn get_block_number(&self, id: &[u8; 32]) -> usize { async fn get_block_number(&self, id: &[u8; 32]) -> usize {
self.rpc.get_block_number(id).await.unwrap() self.rpc.get_block_number(id).await.unwrap()

View File

@@ -9,7 +9,7 @@ use dkg::{Participant, ThresholdCore, ThresholdKeys, evrf::EvrfCurve};
use serai_validator_sets_primitives::Session; use serai_validator_sets_primitives::Session;
use borsh::{BorshSerialize, BorshDeserialize}; use borsh::{BorshSerialize, BorshDeserialize};
use serai_db::{Get, DbTxn, create_db}; use serai_db::{Get, DbTxn};
use crate::KeyGenParams; use crate::KeyGenParams;
@@ -35,20 +35,26 @@ pub(crate) struct Participations {
pub(crate) network_participations: HashMap<Participant, Vec<u8>>, pub(crate) network_participations: HashMap<Participant, Vec<u8>>,
} }
mod _db {
use serai_validator_sets_primitives::Session;
use serai_db::{Get, DbTxn, create_db};
create_db!( create_db!(
KeyGen { KeyGen {
Params: (session: &Session) -> RawParams, Params: (session: &Session) -> super::RawParams,
Participations: (session: &Session) -> Participations, Participations: (session: &Session) -> super::Participations,
KeyShares: (session: &Session) -> Vec<u8>, KeyShares: (session: &Session) -> Vec<u8>,
} }
); );
}
pub(crate) struct KeyGenDb<P: KeyGenParams>(PhantomData<P>); pub(crate) struct KeyGenDb<P: KeyGenParams>(PhantomData<P>);
impl<P: KeyGenParams> KeyGenDb<P> { impl<P: KeyGenParams> KeyGenDb<P> {
pub(crate) fn set_params(txn: &mut impl DbTxn, session: Session, params: Params<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()); assert_eq!(params.substrate_evrf_public_keys.len(), params.network_evrf_public_keys.len());
Params::set( _db::Params::set(
txn, txn,
&session, &session,
&RawParams { &RawParams {
@@ -68,7 +74,7 @@ impl<P: KeyGenParams> KeyGenDb<P> {
} }
pub(crate) fn params(getter: &impl Get, session: Session) -> Option<Params<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, t: params.t,
n: params n: params
.network_evrf_public_keys .network_evrf_public_keys
@@ -101,10 +107,10 @@ impl<P: KeyGenParams> KeyGenDb<P> {
session: Session, session: Session,
participations: &Participations, participations: &Participations,
) { ) {
Participations::set(txn, &session, participations) _db::Participations::set(txn, &session, participations)
} }
pub(crate) fn participations(getter: &impl Get, session: Session) -> Option<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. // 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(substrate_keys.serialize().as_slice());
keys.extend(network_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)] #[allow(clippy::type_complexity)]
@@ -129,7 +135,7 @@ impl<P: KeyGenParams> KeyGenDb<P> {
getter: &impl Get, getter: &impl Get,
session: Session, session: Session,
) -> Option<(Vec<ThresholdKeys<Ristretto>>, Vec<ThresholdKeys<P::ExternalNetworkCurve>>)> { ) -> 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 keys: &[u8] = keys.as_ref();
let mut substrate_keys = vec![]; let mut substrate_keys = vec![];