From 3ff3d2a22b5684072d85537967bd84d3e6b46398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Fri, 6 Dec 2024 10:59:47 +0300 Subject: [PATCH] actor: Add new winternitz secret key. --- core/src/actor.rs | 44 ++++++++++++++++++++++++------------ core/src/errors.rs | 3 +++ core/src/operator.rs | 6 ++++- core/src/user.rs | 2 +- core/src/verifier.rs | 18 +++++++++++---- core/tests/common/deposit.rs | 24 +++++++++++++------- core/tests/deposit.rs | 12 ++++++---- core/tests/taproot.rs | 6 ++++- 8 files changed, 81 insertions(+), 34 deletions(-) diff --git a/core/src/actor.rs b/core/src/actor.rs index 3559205b..a87de4a6 100644 --- a/core/src/actor.rs +++ b/core/src/actor.rs @@ -47,7 +47,8 @@ impl WinternitzDerivationPath { #[derive(Debug, Clone)] pub struct Actor { pub keypair: Keypair, - secret_key: SecretKey, + _secret_key: SecretKey, + winternitz_secret_key: Option, pub xonly_public_key: XOnlyPublicKey, pub public_key: secp256k1::PublicKey, pub address: Address, @@ -55,26 +56,35 @@ pub struct Actor { impl Actor { #[tracing::instrument(ret(level = tracing::Level::TRACE))] - pub fn new(sk: SecretKey, network: bitcoin::Network) -> Self { + pub fn new( + sk: SecretKey, + winternitz_secret_key: Option, + network: bitcoin::Network, + ) -> Self { let keypair = Keypair::from_secret_key(&utils::SECP, &sk); let (xonly, _parity) = XOnlyPublicKey::from_keypair(&keypair); let address = Address::p2tr(&utils::SECP, xonly, None, network); Actor { keypair, - secret_key: keypair.secret_key(), + _secret_key: keypair.secret_key(), + winternitz_secret_key, xonly_public_key: xonly, public_key: keypair.public_key(), address, } } - /// Generates a Winternitz public key for given path. + /// Generates a Winternitz public key for the given path. pub fn derive_winternitz_pk( &self, path: WinternitzDerivationPath, ) -> Result { - let altered_secret_key = [self.secret_key.as_ref().to_vec(), path.to_vec()].concat(); + let wsk = self + .winternitz_secret_key + .clone() + .ok_or(BridgeError::NoWinternitzSecretKey)?; + let altered_secret_key = [wsk.as_bytes().to_vec(), path.to_vec()].concat(); let winternitz_params = winternitz::Parameters::new(path.message_length, path.log_d); @@ -267,7 +277,9 @@ impl Actor { #[cfg(test)] mod tests { use super::Actor; - use crate::builder::transaction::TxHandler; + use crate::{ + builder::transaction::TxHandler, mock::database::create_test_config_with_thread_name, + }; use bitcoin::{ absolute::Height, transaction::Version, Amount, Network, OutPoint, Transaction, TxIn, TxOut, }; @@ -334,9 +346,9 @@ mod tests { let sk = SecretKey::new(&mut rand::thread_rng()); let network = Network::Regtest; - let actor = Actor::new(sk, network); + let actor = Actor::new(sk, None, network); - assert_eq!(sk, actor.secret_key); + assert_eq!(sk, actor._secret_key); assert_eq!(sk.public_key(&secp), actor.public_key); assert_eq!(sk.x_only_public_key(&secp).0, actor.xonly_public_key); } @@ -345,7 +357,7 @@ mod tests { fn sign_taproot_pubkey_spend() { let sk = SecretKey::new(&mut rand::thread_rng()); let network = Network::Regtest; - let actor = Actor::new(sk, network); + let actor = Actor::new(sk, None, network); // Trying to sign with an invalid transaction will result with an error. let mut tx_handler = create_invalid_mock_tx_handler(&actor); @@ -373,7 +385,7 @@ mod tests { fn sign_taproot_pubkey_spend_tx_with_sighash() { let sk = SecretKey::new(&mut rand::thread_rng()); let network = Network::Regtest; - let actor = Actor::new(sk, network); + let actor = Actor::new(sk, None, network); // Trying to sign with an invalid transaction will result with an error. let mut tx_handler = create_invalid_mock_tx_handler(&actor); @@ -399,10 +411,14 @@ mod tests { .unwrap(); } - #[test] - fn derive_winternitz_pk() { - let sk = SecretKey::new(&mut rand::thread_rng()); - let actor = Actor::new(sk, Network::Regtest); + #[tokio::test] + async fn derive_winternitz_pk() { + let config = create_test_config_with_thread_name("test_config.toml", None).await; + let actor = Actor::new( + config.secret_key, + config.winternitz_secret_key, + Network::Regtest, + ); actor .derive_winternitz_pk(super::WinternitzDerivationPath { diff --git a/core/src/errors.rs b/core/src/errors.rs index 282be40a..00f3f117 100644 --- a/core/src/errors.rs +++ b/core/src/errors.rs @@ -199,6 +199,9 @@ pub enum BridgeError { #[error("RPC endpoint returned an error: {0}")] TonicError(#[from] tonic::Status), + + #[error("No root Winternitz secret key is provided in configuration file")] + NoWinternitzSecretKey, } impl From for ErrorObject<'static> { diff --git a/core/src/operator.rs b/core/src/operator.rs index 0e30b41a..3438d0b4 100644 --- a/core/src/operator.rs +++ b/core/src/operator.rs @@ -40,7 +40,11 @@ impl Operator { pub async fn new(config: BridgeConfig, rpc: ExtendedRpc) -> Result { // let num_verifiers = config.verifiers_public_keys.len(); - let signer = Actor::new(config.secret_key, config.network); + let signer = Actor::new( + config.secret_key, + config.winternitz_secret_key.clone(), + config.network, + ); let db = Database::new(&config).await?; diff --git a/core/src/user.rs b/core/src/user.rs index 00291e3a..a1fa846a 100644 --- a/core/src/user.rs +++ b/core/src/user.rs @@ -24,7 +24,7 @@ pub struct User { impl User { /// Creates a new `User`. pub fn new(rpc: ExtendedRpc, sk: SecretKey, config: BridgeConfig) -> Self { - let signer = Actor::new(sk, config.network); + let signer = Actor::new(sk, config.winternitz_secret_key.clone(), config.network); let nofn_xonly_pk = secp256k1::XOnlyPublicKey::from_musig2_pks( config.verifiers_public_keys.clone(), diff --git a/core/src/verifier.rs b/core/src/verifier.rs index 6849a7ab..96d59fe0 100644 --- a/core/src/verifier.rs +++ b/core/src/verifier.rs @@ -69,7 +69,11 @@ pub struct Verifier { impl Verifier { pub async fn new(rpc: ExtendedRpc, config: BridgeConfig) -> Result { - let signer = Actor::new(config.secret_key, config.network); + let signer = Actor::new( + config.secret_key, + config.winternitz_secret_key.clone(), + config.network, + ); // let pk: secp256k1::PublicKey = config.secret_key.public_key(&utils::SECP); @@ -677,10 +681,14 @@ mod tests { let evm_address = EVMAddress([1u8; 20]); let deposit_address = user.get_deposit_address(evm_address).unwrap(); - let signer_address = Actor::new(config.secret_key, config.network) - .address - .as_unchecked() - .clone(); + let signer_address = Actor::new( + config.secret_key, + config.winternitz_secret_key, + config.network, + ) + .address + .as_unchecked() + .clone(); let required_nonce_count = 2 * config.operators_xonly_pks.len() + 1; diff --git a/core/tests/common/deposit.rs b/core/tests/common/deposit.rs index fa4df28f..02ace8a5 100644 --- a/core/tests/common/deposit.rs +++ b/core/tests/common/deposit.rs @@ -39,10 +39,14 @@ pub async fn run_multiple_deposits(test_config_name: &str) { let secret_key = secp256k1::SecretKey::new(&mut secp256k1::rand::thread_rng()); - let signer_address = Actor::new(secret_key, config.network) - .address - .as_unchecked() - .clone(); + let signer_address = Actor::new( + secret_key, + config.winternitz_secret_key.clone(), + config.network, + ) + .address + .as_unchecked() + .clone(); let user = User::new(rpc.clone(), secret_key, config.clone()); let evm_address = EVMAddress([1u8; 20]); @@ -264,10 +268,14 @@ pub async fn run_single_deposit( .await; let secret_key = secp256k1::SecretKey::new(&mut secp256k1::rand::thread_rng()); - let signer_address = Actor::new(secret_key, config.network) - .address - .as_unchecked() - .clone(); + let signer_address = Actor::new( + secret_key, + config.winternitz_secret_key.clone(), + config.network, + ) + .address + .as_unchecked() + .clone(); let user = User::new(rpc.clone(), secret_key, config.clone()); diff --git a/core/tests/deposit.rs b/core/tests/deposit.rs index 918ed6b7..67aa5452 100644 --- a/core/tests/deposit.rs +++ b/core/tests/deposit.rs @@ -26,10 +26,14 @@ async fn deposit_with_retry_checks() { .await; let secret_key = secp256k1::SecretKey::new(&mut secp256k1::rand::thread_rng()); - let signer_address = Actor::new(secret_key, config.network) - .address - .as_unchecked() - .clone(); + let signer_address = Actor::new( + secret_key, + config.winternitz_secret_key.clone(), + config.network, + ) + .address + .as_unchecked() + .clone(); let user = User::new(rpc.clone(), secret_key, config.clone()); let evm_address: EVMAddress = EVMAddress([1u8; 20]); diff --git a/core/tests/taproot.rs b/core/tests/taproot.rs index 9831c6ed..15e57bc0 100644 --- a/core/tests/taproot.rs +++ b/core/tests/taproot.rs @@ -69,7 +69,11 @@ async fn create_address_and_transaction_then_sign_transaction() { }; // Signer should be able to sign the new transaction. - let signer = Actor::new(config.secret_key, config.network); + let signer = Actor::new( + config.secret_key, + config.winternitz_secret_key, + config.network, + ); let sig = signer .sign_taproot_script_spend_tx_new_tweaked(&mut tx_details, 0, 0) .unwrap();