From 958826b1de76d65ee2ac03a6dd615a67b83daaef Mon Sep 17 00:00:00 2001 From: Runchao Han Date: Thu, 5 Sep 2024 16:12:00 +1000 Subject: [PATCH] move schnorr sig verification to bitcoin lib --- Cargo.lock | 5 ++++ packages/bitcoin/Cargo.toml | 4 ++++ packages/bitcoin/src/error.rs | 9 ++++++++ packages/bitcoin/src/lib.rs | 4 ++++ .../src/schnorr.rs} | 23 ++++++++++++++++++- packages/btcstaking/Cargo.toml | 17 +++++++------- packages/btcstaking/src/error.rs | 2 ++ packages/btcstaking/src/lib.rs | 1 - packages/btcstaking/src/sig_verify.rs | 11 ++------- 9 files changed, 57 insertions(+), 19 deletions(-) create mode 100644 packages/bitcoin/src/error.rs rename packages/{btcstaking/src/identity_digest.rs => bitcoin/src/schnorr.rs} (62%) diff --git a/Cargo.lock b/Cargo.lock index 20fcbc07..05ba7aa4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,15 +120,20 @@ version = "0.9.0" dependencies = [ "bitcoin", "cosmwasm-std", + "digest 0.10.7", "hex", + "k256", "schemars", "serde", + "sha2 0.10.8", + "thiserror", ] [[package]] name = "babylon-btcstaking" version = "0.9.0" dependencies = [ + "babylon-bitcoin", "babylon-proto", "bitcoin", "digest 0.10.7", diff --git a/packages/bitcoin/Cargo.toml b/packages/bitcoin/Cargo.toml index 003aadf0..d98d70fe 100644 --- a/packages/bitcoin/Cargo.toml +++ b/packages/bitcoin/Cargo.toml @@ -6,9 +6,13 @@ edition.workspace = true [dependencies] bitcoin = { workspace = true } +digest = { workspace = true } +sha2 = { workspace = true } serde = { workspace = true } schemars = { workspace = true } cosmwasm-std = { workspace = true } +k256 = { workspace = true } +thiserror = { workspace = true } [dev-dependencies] hex = { workspace = true } diff --git a/packages/bitcoin/src/error.rs b/packages/bitcoin/src/error.rs new file mode 100644 index 00000000..0466ddff --- /dev/null +++ b/packages/bitcoin/src/error.rs @@ -0,0 +1,9 @@ +use thiserror::Error; + +#[derive(Error, Debug, PartialEq)] +pub enum Error { + #[error("Failed to parse public key")] + FailedToParsePublicKey(String), + #[error("Invalid schnorr signature")] + InvalidSchnorrSignature(String), +} diff --git a/packages/bitcoin/src/lib.rs b/packages/bitcoin/src/lib.rs index 892f5107..9dcc12d9 100644 --- a/packages/bitcoin/src/lib.rs +++ b/packages/bitcoin/src/lib.rs @@ -10,9 +10,13 @@ pub use bitcoin::{ pub use cosmwasm_std::Uint256; pub mod chain_params; +pub mod error; pub mod merkle; pub mod op_return; pub mod pow; +pub mod schnorr; + +pub type Result = std::result::Result; #[cfg(test)] mod tests { diff --git a/packages/btcstaking/src/identity_digest.rs b/packages/bitcoin/src/schnorr.rs similarity index 62% rename from packages/btcstaking/src/identity_digest.rs rename to packages/bitcoin/src/schnorr.rs index 6cef6137..81d1b5ae 100644 --- a/packages/btcstaking/src/identity_digest.rs +++ b/packages/bitcoin/src/schnorr.rs @@ -4,9 +4,14 @@ //! //! Adapted from `sha2` [sha256.rs](https://github.com/RustCrypto/hashes/blob/master/sha2/src/sha256.rs) //! and https://github.com/CosmWasm/cosmwasm/blob/main/packages/crypto/src/identity_digest.rs +use crate::error::Error; +use crate::Result; use digest::consts::U32; use digest::generic_array::GenericArray; use digest::{FixedOutput, HashMarker, Output, OutputSizeUser, Reset, Update}; +use k256::schnorr::signature::DigestVerifier; +use k256::schnorr::Signature as SchnorrSignature; +use k256::schnorr::VerifyingKey; use sha2::Digest; /// The 256-bits identity container @@ -40,6 +45,22 @@ impl Reset for Identity256 { } } -pub fn new_digest(msg_hash: [u8; 32]) -> Identity256 { +pub fn new_digest(msg_hash: &[u8; 32]) -> Identity256 { Identity256::new().chain(msg_hash) } + +pub fn verify_digest( + pub_key: &[u8], + msg_hash: &[u8; 32], + signature: &SchnorrSignature, +) -> Result<()> { + let digest = new_digest(msg_hash); + + // verify the signature w.r.t. the signature, the sig hash, and the public key + let verifying_key = VerifyingKey::from_bytes(pub_key) + .map_err(|e| Error::FailedToParsePublicKey(e.to_string()))?; + + verifying_key + .verify_digest(digest, signature) + .map_err(|e| Error::InvalidSchnorrSignature(e.to_string())) +} diff --git a/packages/btcstaking/Cargo.toml b/packages/btcstaking/Cargo.toml index a56a5988..2999d517 100644 --- a/packages/btcstaking/Cargo.toml +++ b/packages/btcstaking/Cargo.toml @@ -5,14 +5,15 @@ version.workspace = true edition.workspace = true [dependencies] -bitcoin = { workspace = true } -digest = { workspace = true } -rust_decimal = { workspace = true } -hex = { workspace = true } -sha2 = { workspace = true } -k256 = { workspace = true } -thiserror = { workspace = true } -eots = { path = "../eots" } +babylon-bitcoin = { workspace = true } +bitcoin = { workspace = true } +digest = { workspace = true } +rust_decimal = { workspace = true } +hex = { workspace = true } +sha2 = { workspace = true } +k256 = { workspace = true } +thiserror = { workspace = true } +eots = { path = "../eots" } [dev-dependencies] test-utils = { path = "../test-utils" } diff --git a/packages/btcstaking/src/error.rs b/packages/btcstaking/src/error.rs index c06a7a4b..7bef9e94 100644 --- a/packages/btcstaking/src/error.rs +++ b/packages/btcstaking/src/error.rs @@ -2,6 +2,8 @@ use thiserror::Error; #[derive(Error, Debug, PartialEq)] pub enum Error { + #[error("Bitcoin error: {0}")] + BitcoinError(#[from] babylon_bitcoin::error::Error), #[error("Failed to decompress bytes to a projective point")] DecompressPointFailed {}, #[error("Point {0} is at infinity")] diff --git a/packages/btcstaking/src/lib.rs b/packages/btcstaking/src/lib.rs index 8116633a..eb9026e4 100644 --- a/packages/btcstaking/src/lib.rs +++ b/packages/btcstaking/src/lib.rs @@ -1,6 +1,5 @@ mod adaptor_sig; pub mod error; -mod identity_digest; pub mod scripts_utils; pub mod sig_verify; pub mod tx_verify; diff --git a/packages/btcstaking/src/sig_verify.rs b/packages/btcstaking/src/sig_verify.rs index 4c3fdfe3..71bb7476 100644 --- a/packages/btcstaking/src/sig_verify.rs +++ b/packages/btcstaking/src/sig_verify.rs @@ -1,7 +1,7 @@ use crate::adaptor_sig::AdaptorSignature; use crate::error::Error; -use crate::identity_digest::new_digest; use crate::Result; +use babylon_bitcoin::schnorr; use bitcoin::hashes::Hash; use bitcoin::sighash::{Prevouts, SighashCache}; use bitcoin::Transaction; @@ -47,15 +47,8 @@ pub fn verify_transaction_sig_with_output( ) -> Result<()> { // calculate the sig hash of the tx for the given spending path let sighash = calc_sighash(transaction, funding_output, path_script)?; - let sighash_digest = new_digest(sighash); - // verify the signature w.r.t. the signature, the sig hash, and the public key - let verifying_key = VerifyingKey::from_bytes(&pub_key.serialize()) - .map_err(|e| Error::FailedToParsePublicKey(e.to_string()))?; - - verifying_key - .verify_digest(sighash_digest, signature) - .map_err(|e| Error::InvalidSchnorrSignature(e.to_string())) + schnorr::verify_digest(&pub_key.serialize(), &sighash, signature).map_err(Error::BitcoinError) } /// enc_verify_transaction_sig_with_output verifies the validity of a Schnorr adaptor signature for a given transaction