From a337f6778e1b4f0969b8e8b0d849cc8263ae7bcf Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Tue, 4 Feb 2025 15:29:46 +0300 Subject: [PATCH 01/13] Calculate BitVM with dummy winternitz at init --- Cargo.lock | 210 +++++++++++++++++++++++++++++++-------- Cargo.toml | 16 ++- core/Cargo.toml | 1 + core/src/rpc/verifier.rs | 32 +----- core/src/utils.rs | 132 +++++++++++++++++++++++- 5 files changed, 310 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3bf24ef4..5e44abc3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,9 +106,9 @@ version = "0.4.0" source = "git+https://github.com/chainwayxyz/algebra/?branch=new-ate-loop#ac23fde284ca4d7ede298018f7866ce8ce64467f" dependencies = [ "ark-ec", - "ark-ff", + "ark-ff 0.4.2", "ark-r1cs-std", - "ark-std", + "ark-std 0.4.0", ] [[package]] @@ -119,11 +119,11 @@ dependencies = [ "ahash", "ark-crypto-primitives-macros", "ark-ec", - "ark-ff", - "ark-relations", - "ark-serialize", + "ark-ff 0.4.2", + "ark-relations 0.4.0", + "ark-serialize 0.4.2", "ark-snark", - "ark-std", + "ark-std 0.4.0", "blake2", "derivative", "digest", @@ -149,10 +149,10 @@ version = "0.4.2" source = "git+https://github.com/chainwayxyz/algebra/?branch=new-ate-loop#ac23fde284ca4d7ede298018f7866ce8ce64467f" dependencies = [ "ahash", - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", + "ark-ff 0.4.2", + "ark-poly 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "educe", "fnv", "hashbrown 0.15.2", @@ -169,10 +169,10 @@ name = "ark-ff" version = "0.4.2" source = "git+https://github.com/chainwayxyz/algebra/?branch=new-ate-loop#ac23fde284ca4d7ede298018f7866ce8ce64467f" dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "arrayvec", "digest", "educe", @@ -184,6 +184,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest", + "educe", + "itertools", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.4.2" @@ -193,6 +213,16 @@ dependencies = [ "syn 2.0.94", ] +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.94", +] + [[package]] name = "ark-ff-macros" version = "0.4.2" @@ -205,6 +235,19 @@ dependencies = [ "syn 2.0.94", ] +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.94", +] + [[package]] name = "ark-groth16" version = "0.4.0" @@ -212,11 +255,11 @@ source = "git+https://github.com/arkworks-rs/groth16#16ac1dd387fe5dc89b6fc1a1cf8 dependencies = [ "ark-crypto-primitives", "ark-ec", - "ark-ff", - "ark-poly", - "ark-relations", - "ark-serialize", - "ark-std", + "ark-ff 0.4.2", + "ark-poly 0.4.2", + "ark-relations 0.4.0", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "rayon", ] @@ -226,24 +269,39 @@ version = "0.4.2" source = "git+https://github.com/chainwayxyz/algebra/?branch=new-ate-loop#ac23fde284ca4d7ede298018f7866ce8ce64467f" dependencies = [ "ahash", - "ark-ff", - "ark-serialize", - "ark-std", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "educe", "fnv", "hashbrown 0.15.2", "rayon", ] +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.2", +] + [[package]] name = "ark-r1cs-std" version = "0.4.0" source = "git+https://github.com/arkworks-rs/r1cs-std/#dfdad2b729ebc7e8104931b683f3799246252adc" dependencies = [ "ark-ec", - "ark-ff", - "ark-relations", - "ark-std", + "ark-ff 0.4.2", + "ark-relations 0.4.0", + "ark-std 0.4.0", "educe", "num-bigint", "num-integer", @@ -254,27 +312,53 @@ dependencies = [ [[package]] name = "ark-relations" version = "0.4.0" -source = "git+https://github.com/arkworks-rs/snark/#748c0ba24a824fced676b634f9b9189be6efa790" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0" dependencies = [ - "ark-ff", - "ark-std", + "ark-ff 0.4.2", + "ark-std 0.4.0", "tracing", "tracing-subscriber 0.2.25", ] +[[package]] +name = "ark-relations" +version = "0.5.1" +source = "git+https://github.com/arkworks-rs/snark/#9c528529763f1a0a2e0cba83528f93d32247d621" +dependencies = [ + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "tracing", +] + [[package]] name = "ark-serialize" version = "0.4.2" source = "git+https://github.com/chainwayxyz/algebra/?branch=new-ate-loop#ac23fde284ca4d7ede298018f7866ce8ce64467f" dependencies = [ - "ark-serialize-derive", - "ark-std", + "ark-serialize-derive 0.4.2", + "ark-std 0.4.0", "arrayvec", "digest", "num-bigint", "rayon", ] +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest", + "num-bigint", +] + [[package]] name = "ark-serialize-derive" version = "0.4.2" @@ -285,15 +369,27 @@ dependencies = [ "syn 2.0.94", ] +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", +] + [[package]] name = "ark-snark" version = "0.4.0" -source = "git+https://github.com/arkworks-rs/snark/#202b9e02b808d1d15823298b8ac16f5c54ae4ef6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63" dependencies = [ - "ark-ff", - "ark-relations", - "ark-serialize", - "ark-std", + "ark-ff 0.4.2", + "ark-relations 0.4.0", + "ark-serialize 0.4.2", + "ark-std 0.4.0", ] [[package]] @@ -308,6 +404,16 @@ dependencies = [ "rayon", ] +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -528,7 +634,7 @@ checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" [[package]] name = "bitcoin-script" version = "0.3.0" -source = "git+https://github.com/BitVM/rust-bitcoin-script?branch=StructuredScript#bea92021800fb89bd1fc54d4cb45f3027129953c" +source = "git+https://github.com/BitVM/rust-bitcoin-script#a057e1408fa9e291383ca545c2f0a0b5be2b4aa6" dependencies = [ "bitcoin", "lazy_static", @@ -539,7 +645,7 @@ dependencies = [ [[package]] name = "bitcoin-script-stack" version = "0.0.1" -source = "git+https://github.com/BitVM/rust-bitcoin-script-stack?branch=bitvm#5a9aa6eb6616cb1ff1b822f8d6c38cf1063cc34f" +source = "git+https://github.com/BitVM/rust-bitcoin-script-stack#bb397b6023b149aa2031306620b079f9b70adc92" dependencies = [ "bitcoin", "bitcoin-script", @@ -633,16 +739,16 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitvm" version = "0.1.0" -source = "git+https://github.com/BitVM/BitVM?rev=02157f6#02157f615d00691be53671ca52636aafdb029f33" +source = "git+https://github.com/BitVM/BitVM?rev=89558b3a50e7d08a5eb42aa7de266e7912df3f98#89558b3a50e7d08a5eb42aa7de266e7912df3f98" dependencies = [ "ark-bn254", "ark-crypto-primitives", "ark-ec", - "ark-ff", + "ark-ff 0.4.2", "ark-groth16", - "ark-relations", - "ark-serialize", - "ark-std", + "ark-relations 0.5.1", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "bitcoin", "bitcoin-script", "bitcoin-script-stack", @@ -882,6 +988,7 @@ dependencies = [ "borsh", "clap", "crypto-bigint", + "ctor", "futures", "futures-core", "futures-util", @@ -1075,6 +1182,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn 2.0.94", +] + [[package]] name = "derivative" version = "2.2.0" @@ -2851,7 +2968,7 @@ dependencies = [ "ark-bn254", "ark-ec", "ark-groth16", - "ark-serialize", + "ark-serialize 0.4.2", "bytemuck", "hex", "num-bigint", @@ -3093,7 +3210,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "script-macro" version = "0.3.0" -source = "git+https://github.com/BitVM/rust-bitcoin-script?branch=StructuredScript#bea92021800fb89bd1fc54d4cb45f3027129953c" +source = "git+https://github.com/BitVM/rust-bitcoin-script#a057e1408fa9e291383ca545c2f0a0b5be2b4aa6" dependencies = [ "bitcoin", "hex", @@ -4550,3 +4667,8 @@ dependencies = [ "quote", "syn 2.0.94", ] + +[[patch.unused]] +name = "ark-snark" +version = "0.5.1" +source = "git+https://github.com/arkworks-rs/snark/#9c528529763f1a0a2e0cba83528f93d32247d621" diff --git a/Cargo.toml b/Cargo.toml index 2531d9ee..ac61701d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ clap = "4.5.20" toml = "0.8.19" sqlx = { version = "0.7.4", default-features = false } serial_test = "3.2.0" +ctor = "0.2.9" # bitcoin bitcoin = { version = "0.32.5", features = ["serde"] } @@ -26,7 +27,7 @@ secp256k1 = { version = "0.30.0", features = [ "std", "global-context", ] } -bitcoin-script = { git = "https://github.com/BitVM/rust-bitcoin-script", branch = "StructuredScript" } +bitcoin-script = { git = "https://github.com/BitVM/rust-bitcoin-script" } # async + gRPC tonic = { version = "0.12.3", features = ["tls"] } @@ -46,27 +47,24 @@ k256 = { version = "=0.13.3", default-features = false } risc0-build = "1.2" risc0-zkvm = { version = "1.2" } header-chain = { git = "https://github.com/chainwayxyz/risc0-to-bitvm2", rev = "a233e27" } -bitvm = { git = "https://github.com/BitVM/BitVM", rev = "02157f6" } +bitvm = { git = "https://github.com/BitVM/BitVM", rev = "89558b3a50e7d08a5eb42aa7de266e7912df3f98" } [patch.crates-io] bitcoincore-rpc = { version = "0.18.0", git = "https://github.com/chainwayxyz/rust-bitcoincore-rpc.git", rev = "ca3cfa2" } +secp256k1 = { git = "https://github.com/jlest01/rust-secp256k1", rev = "1cc7410df436b73d06db3c8ff7cbb29a78916b06" } + + ark-ff = { git = "https://github.com/chainwayxyz/algebra/", branch = "new-ate-loop" } ark-ec = { git = "https://github.com/chainwayxyz/algebra/", branch = "new-ate-loop" } ark-poly = { git = "https://github.com/chainwayxyz/algebra/", branch = "new-ate-loop" } ark-serialize = { git = "https://github.com/chainwayxyz/algebra/", branch = "new-ate-loop" } -ark-bn254 = { git = "https://github.com/chainwayxyz/algebra/", branch = "new-ate-loop", features = [ - "curve", -], default-features = false } - +ark-bn254 = { git = "https://github.com/chainwayxyz/algebra/", branch = "new-ate-loop", features = ["curve"], default-features = false } ark-r1cs-std = { git = "https://github.com/arkworks-rs/r1cs-std/" } ark-crypto-primitives = { git = "https://github.com/arkworks-rs/crypto-primitives/" } - ark-relations = { git = "https://github.com/arkworks-rs/snark/" } ark-snark = { git = "https://github.com/arkworks-rs/snark/" } ark-groth16 = { git = "https://github.com/arkworks-rs/groth16" } -secp256k1 = { git = "https://github.com/jlest01/rust-secp256k1", rev = "1cc7410df436b73d06db3c8ff7cbb29a78916b06" } - [profile.release] lto = true strip = true diff --git a/core/Cargo.toml b/core/Cargo.toml index 9e4b1b46..16312d42 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -36,6 +36,7 @@ async-stream = { workspace = true } futures-util = { workspace = true } futures-core = { workspace = true } bitvm = { workspace = true } +ctor = { workspace = true } [dev-dependencies] serial_test = { workspace = true } diff --git a/core/src/rpc/verifier.rs b/core/src/rpc/verifier.rs index da2a965a..5fce640b 100644 --- a/core/src/rpc/verifier.rs +++ b/core/src/rpc/verifier.rs @@ -297,29 +297,6 @@ impl ClementineVerifier for Verifier { chunk_idx / self.config.num_kickoffs_per_sequential_collateral_tx; let kickoff_idx = chunk_idx % self.config.num_kickoffs_per_sequential_collateral_tx; - let mut public_input_wots = vec![]; - // Generate precalculated BitVM Setups - let _commits_publickeys = utils::ALL_BITVM_INTERMEDIATE_VARIABLES - .iter() - .enumerate() - .map(|(idx, (intermediate_step, intermediate_step_size))| { - let winternitz_pk: WinternitzPublicKey = WinternitzPublicKey { - public_key: winternitz_public_keys[idx].clone(), - parameters: winternitz::Parameters::new( - *intermediate_step_size as u32 * 2, - 4, - ), - }; - - if intermediate_step == "scalar_1" { - // scalar_1 is the public input. - public_input_wots = winternitz_pk.public_key.clone(); - } - - Ok((intermediate_step.clone(), winternitz_pk)) - }) - .collect::, BridgeError>>()?; - let assert_tx_addrs = utils::ALL_BITVM_INTERMEDIATE_VARIABLES .iter() .enumerate() @@ -346,6 +323,7 @@ impl ClementineVerifier for Verifier { // TODO: Use correct verification key and along with a dummy proof. let scripts: Vec = { + utils::replace_disprove_scripts(&winternitz_public_keys) // let mut bridge_assigner = BridgeAssigner::new_watcher(commits_publickeys); // let proof = RawProof::default(); // let segments = groth16_verify_to_segments( @@ -359,9 +337,9 @@ impl ClementineVerifier for Verifier { // .iter() // .map(|s| s.script.clone().compile()) // .collect() - vec![bitcoin::script::Builder::new() - .push_opcode(bitcoin::opcodes::all::OP_PUSHNUM_1) - .into_script()] + // vec![bitcoin::script::Builder::new() + // .push_opcode(bitcoin::opcodes::all::OP_PUSHNUM_1) + // .into_script()] }; let taproot_builder = taproot_builder_with_scripts(&scripts); @@ -380,7 +358,7 @@ impl ClementineVerifier for Verifier { kickoff_idx as i32, assert_tx_addrs, &root_hash_bytes, - public_input_wots, + vec![], ) .await?; } diff --git a/core/src/utils.rs b/core/src/utils.rs index 4ced5b5f..4c40a680 100644 --- a/core/src/utils.rs +++ b/core/src/utils.rs @@ -3,14 +3,23 @@ use crate::cli::Args; use crate::config::BridgeConfig; use crate::errors::BridgeError; use bitcoin::taproot::{self, LeafVersion}; -use bitcoin::XOnlyPublicKey; use bitcoin::{self, Witness}; +use bitcoin::{ScriptBuf, XOnlyPublicKey}; +use bitvm::chunker::assigner::BridgeAssigner; +use bitvm::chunker::chunk_groth16_verifier::groth16_verify_to_segments; +use bitvm::chunker::disprove_execution::RawProof; +use bitvm::signatures::signing_winternitz::WinternitzPublicKey; +use bitvm::signatures::winternitz; use tracing::Level; //use bitvm::chunker::assigner::BridgeAssigner; +use ctor::ctor; use std::borrow::BorrowMut; use std::collections::BTreeMap; +use std::collections::HashMap; use std::process::exit; use std::str::FromStr; +use std::sync::OnceLock; +use std::time::Instant; use tracing::level_filters::LevelFilter; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::{fmt, EnvFilter, Registry}; @@ -44,6 +53,127 @@ lazy_static::lazy_static! { // pub static ref ALL_BITVM_INTERMEDIATE_VARIABLES: BTreeMap = BridgeAssigner::default().all_intermediate_variable(); // } +static ALL_BITVM_INTERMEDIATE_VARIABLES_LOCK: OnceLock> = OnceLock::new(); +static ALL_BITVM_DISPROVE_PROOF_LOCK: OnceLock> = OnceLock::new(); + +#[ctor] +fn init_all_bitvm_intermediate_variables() { + let start = Instant::now(); + + let map = BridgeAssigner::default().all_intermediate_variables(); + ALL_BITVM_INTERMEDIATE_VARIABLES_LOCK + .set(map.clone()) + .unwrap(); + + // Now create a dummy winternitz with random parameters + let commits_publickeys = map + .iter() + .enumerate() + .map(|(idx, (intermediate_step, intermediate_step_size))| { + let mut dummy_pk = [31u8; 20]; + dummy_pk[..8].copy_from_slice(&idx.to_le_bytes()); + let parameters = winternitz::Parameters::new(*intermediate_step_size as u32 * 2, 4); + + // Pre-allocate vector with correct capacity + let digit_count = parameters.total_digit_count() as usize; + let mut winternitz_pk = Vec::with_capacity(digit_count); + + // Generate unique public keys for each digit + for i in 0..digit_count { + let mut new_pk = dummy_pk; + new_pk[12..20].copy_from_slice(&i.to_le_bytes()); // Use last 8 bytes for digit index + winternitz_pk.push(new_pk); + } + + let winternitz_pk = WinternitzPublicKey { + public_key: winternitz_pk, + parameters, + }; + Ok((intermediate_step.clone(), winternitz_pk)) + }) + .collect::, BridgeError>>() + .unwrap(); + + let mut bridge_assigner = BridgeAssigner::new_watcher(commits_publickeys); + let proof = RawProof::default(); + let segments = + groth16_verify_to_segments(&mut bridge_assigner, &proof.public, &proof.proof, &proof.vk); + + let scripts = segments + .iter() + .map(|s| s.script.clone().compile()) + .collect::>(); + ALL_BITVM_DISPROVE_PROOF_LOCK.set(scripts).unwrap(); + + println!("BitVM initialization took: {:?}", start.elapsed()); +} + +pub fn replace_disprove_scripts(winternitz_pk: &[Vec<[u8; 20]>]) -> Vec { + let start = Instant::now(); + + // Get the initial scripts. + let mut disprove_scripts = ALL_BITVM_DISPROVE_PROOF_LOCK + .get() + .expect("failed to get disprove scripts") + .to_vec(); + let all_bitvm_intermediate_variables = ALL_BITVM_INTERMEDIATE_VARIABLES_LOCK + .get() + .expect("failed to get intermediate variables"); + + // Process each intermediate variable one at a time. + for (idx, (_intermediate_step, intermediate_step_size)) in + all_bitvm_intermediate_variables.iter().enumerate() + { + // Build a dummy base public key. + // Start with 20 bytes set to 31, then overwrite the first 8 bytes with idx. + let mut dummy_base = [31u8; 20]; + dummy_base[..8].copy_from_slice(&idx.to_le_bytes()); + + // Compute the parameters and determine the number of digits. + let parameters = winternitz::Parameters::new((*intermediate_step_size as u32) * 2, 4); + let digit_count = parameters.total_digit_count() as usize; + + // Build a mapping of dummy key -> actual replacement key. + let mut mapping = HashMap::<[u8; 20], [u8; 20]>::with_capacity(digit_count); + for digit in 0..digit_count { + let mut dummy = dummy_base; + // Overwrite the last 8 bytes with the little-endian representation of the digit. + dummy[12..20].copy_from_slice(&digit.to_le_bytes()); + // winternitz_pk[idx][digit] is the actual replacement value. + mapping.insert(dummy, winternitz_pk[idx][digit]); + } + + // For each script, scan through the bytes and do a one‐pass replacement. + // At each position, if the next 20 bytes match a dummy key, replace them; + // otherwise, copy one byte. + for script in disprove_scripts.iter_mut() { + let script_bytes = script.as_bytes(); + let mut new_bytes = Vec::with_capacity(script_bytes.len()); + let mut pos = 0; + while pos < script_bytes.len() { + // If there are at least 20 bytes remaining, check for a dummy key. + if pos + 20 <= script_bytes.len() { + // Convert the 20‐byte window into an array. + if let Ok(candidate_arr) = <[u8; 20]>::try_from(&script_bytes[pos..pos + 20]) { + if let Some(&replacement) = mapping.get(&candidate_arr) { + new_bytes.extend_from_slice(&replacement); + pos += 20; + continue; + } + } + } + // Otherwise, just copy the byte. + new_bytes.push(script_bytes[pos]); + pos += 1; + } + *script = ScriptBuf::from_bytes(new_bytes); + } + } + + println!("BitVM script replacement took: {:?}", start.elapsed()); + disprove_scripts +} + lazy_static::lazy_static! { pub static ref ALL_BITVM_INTERMEDIATE_VARIABLES: BTreeMap = { let mut map = BTreeMap::new(); From 0c2939101c877c9bb04904190f0400789c49d166 Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Tue, 4 Feb 2025 16:53:58 +0300 Subject: [PATCH 02/13] Add bitvm caching --- core/src/builder/sighash.rs | 3 +- core/src/operator.rs | 4 +- core/src/rpc/verifier.rs | 11 ++- core/src/utils.rs | 153 +++++++++++++++++++++++------------- 4 files changed, 108 insertions(+), 63 deletions(-) diff --git a/core/src/builder/sighash.rs b/core/src/builder/sighash.rs index 68018ba8..56a69ab7 100644 --- a/core/src/builder/sighash.rs +++ b/core/src/builder/sighash.rs @@ -460,6 +460,7 @@ mod tests { use crate::builder::sighash::create_nofn_sighash_stream; use crate::extended_rpc::ExtendedRpc; use crate::operator::Operator; + use crate::utils::BITVM_CACHE_LOCK; use crate::watchtower::Watchtower; use crate::{builder, create_test_config_with_thread_name, utils}; use crate::{ @@ -543,7 +544,7 @@ mod tests { .unwrap(); } } - let assert_len = utils::ALL_BITVM_INTERMEDIATE_VARIABLES.len(); + let assert_len = BITVM_CACHE_LOCK.get().unwrap().intermediate_variables.len(); for o in 0..config.num_operators { for t in 0..config.num_sequential_collateral_txs { for k in 0..config.num_kickoffs_per_sequential_collateral_tx { diff --git a/core/src/operator.rs b/core/src/operator.rs index 59e7e848..3919f211 100644 --- a/core/src/operator.rs +++ b/core/src/operator.rs @@ -4,8 +4,8 @@ use crate::database::Database; use crate::errors::BridgeError; use crate::extended_rpc::ExtendedRpc; use crate::musig2::AggregateFromPublicKeys; -use crate::utils::ALL_BITVM_INTERMEDIATE_VARIABLES; use bitcoin::{Amount, OutPoint, Txid, XOnlyPublicKey}; +use bitvm::bn254::utils; use bitvm::signatures::winternitz; use jsonrpsee::core::client::ClientT; use jsonrpsee::http_client::HttpClientBuilder; @@ -723,7 +723,7 @@ impl Operator { for kickoff_idx in 0..self.config.num_kickoffs_per_sequential_collateral_tx as u32 { // ALL_BITVM_INTERMEDIATE_VARIABLES is a global variable that contains the intermediate variables for the BitVM in BTreeMap for (intermediate_step, intermediate_step_size) in - ALL_BITVM_INTERMEDIATE_VARIABLES.iter() + crate::utils::BITVM_CACHE_LOCK.get().unwrap().intermediate_variables.iter() { let step_name = intermediate_step.as_str(); let path = WinternitzDerivationPath { diff --git a/core/src/rpc/verifier.rs b/core/src/rpc/verifier.rs index c37fdacc..d93cb87c 100644 --- a/core/src/rpc/verifier.rs +++ b/core/src/rpc/verifier.rs @@ -16,7 +16,7 @@ use crate::{ }, errors::BridgeError, musig2::{self}, - utils, + utils::{self, BITVM_CACHE_LOCK}, verifier::{NofN, NonceSession, Verifier}, EVMAddress, }; @@ -200,7 +200,7 @@ impl ClementineVerifier for Verifier { let mut operator_winternitz_public_keys = Vec::new(); for _ in 0..self.config.num_kickoffs_per_sequential_collateral_tx * self.config.num_sequential_collateral_txs - * utils::ALL_BITVM_INTERMEDIATE_VARIABLES.len() + * BITVM_CACHE_LOCK.get().unwrap().intermediate_variables.len() { let operator_params = in_stream .message() @@ -287,7 +287,7 @@ impl ClementineVerifier for Verifier { } // Split the winternitz public keys into chunks for every sequential collateral tx and kickoff index. // This is done because we need to generate a separate BitVM setup for each collateral tx and kickoff index. - let chunk_size = utils::ALL_BITVM_INTERMEDIATE_VARIABLES.len(); + let chunk_size = BITVM_CACHE_LOCK.get().unwrap().intermediate_variables.len(); let winternitz_public_keys_chunks = operator_winternitz_public_keys.chunks_exact(chunk_size); @@ -297,7 +297,10 @@ impl ClementineVerifier for Verifier { chunk_idx / self.config.num_kickoffs_per_sequential_collateral_tx; let kickoff_idx = chunk_idx % self.config.num_kickoffs_per_sequential_collateral_tx; - let assert_tx_addrs = utils::ALL_BITVM_INTERMEDIATE_VARIABLES + let assert_tx_addrs = BITVM_CACHE_LOCK + .get() + .unwrap() + .intermediate_variables .iter() .enumerate() .map(|(idx, (_intermediate_step, intermediate_step_size))| { diff --git a/core/src/utils.rs b/core/src/utils.rs index 2919ad6d..2688b390 100644 --- a/core/src/utils.rs +++ b/core/src/utils.rs @@ -8,11 +8,14 @@ use bitvm::chunker::chunk_groth16_verifier::groth16_verify_to_segments; use bitvm::chunker::disprove_execution::RawProof; use bitvm::signatures::signing_winternitz::WinternitzPublicKey; use bitvm::signatures::winternitz; +use sha2::digest::consts::U8; use tracing::Level; //use bitvm::chunker::assigner::BridgeAssigner; +use borsh::{BorshDeserialize, BorshSerialize}; use ctor::ctor; use std::collections::BTreeMap; use std::collections::HashMap; +use std::fs; use std::process::exit; use std::str::FromStr; use std::sync::OnceLock; @@ -50,19 +53,73 @@ lazy_static::lazy_static! { // pub static ref ALL_BITVM_INTERMEDIATE_VARIABLES: BTreeMap = BridgeAssigner::default().all_intermediate_variable(); // } -static ALL_BITVM_INTERMEDIATE_VARIABLES_LOCK: OnceLock> = OnceLock::new(); -static ALL_BITVM_DISPROVE_PROOF_LOCK: OnceLock> = OnceLock::new(); +pub static BITVM_CACHE_LOCK: OnceLock = OnceLock::new(); + +#[derive(BorshSerialize, BorshDeserialize, Debug)] +pub struct BitvmCache { + pub intermediate_variables: BTreeMap, + pub disprove_scripts: Vec>, +} + +impl BitvmCache { + fn save_to_file(&self, path: &str) -> bool { + match borsh::to_vec(self) { + Ok(serialized) => match fs::write(path, serialized) { + Ok(_) => { + println!("Saved BitVM cache to file"); + true + } + Err(e) => { + println!("Failed to save BitVM cache: {}", e); + false + } + }, + Err(e) => { + println!("Failed to serialize BitVM cache: {}", e); + false + } + } + } + + fn load_from_file(path: &str) -> Option { + match fs::read(path) { + Ok(bytes) => match Self::try_from_slice(&bytes) { + Ok(cache) => { + println!("Loaded BitVM cache from file"); + Some(cache) + } + Err(e) => { + println!("Failed to deserialize BitVM cache: {}", e); + None + } + }, + Err(_) => { + println!("No BitVM cache found"); + None + } + } + } +} #[ctor] fn init_all_bitvm_intermediate_variables() { let start = Instant::now(); + let cache_path = "bitvm_cache.bin"; + + let bitvm_cache = BitvmCache::load_from_file(cache_path).unwrap_or_else(|| { + let fresh_data = generate_fresh_data(); + fresh_data.save_to_file(cache_path); + fresh_data + }); + BITVM_CACHE_LOCK.set(bitvm_cache).unwrap(); + println!("BitVM initialization took: {:?}", start.elapsed()); +} + +fn generate_fresh_data() -> BitvmCache { + println!("Generating fresh BitVM data..."); let map = BridgeAssigner::default().all_intermediate_variables(); - ALL_BITVM_INTERMEDIATE_VARIABLES_LOCK - .set(map.clone()) - .unwrap(); - // Now create a dummy winternitz with random parameters let commits_publickeys = map .iter() .enumerate() @@ -71,14 +128,12 @@ fn init_all_bitvm_intermediate_variables() { dummy_pk[..8].copy_from_slice(&idx.to_le_bytes()); let parameters = winternitz::Parameters::new(*intermediate_step_size as u32 * 2, 4); - // Pre-allocate vector with correct capacity let digit_count = parameters.total_digit_count() as usize; let mut winternitz_pk = Vec::with_capacity(digit_count); - // Generate unique public keys for each digit for i in 0..digit_count { let mut new_pk = dummy_pk; - new_pk[12..20].copy_from_slice(&i.to_le_bytes()); // Use last 8 bytes for digit index + new_pk[12..20].copy_from_slice(&i.to_le_bytes()); winternitz_pk.push(new_pk); } @@ -98,31 +153,35 @@ fn init_all_bitvm_intermediate_variables() { let scripts = segments .iter() - .map(|s| s.script.clone().compile()) - .collect::>(); - ALL_BITVM_DISPROVE_PROOF_LOCK.set(scripts).unwrap(); + .map(|s| s.script.clone().compile().to_bytes()) + .collect(); - println!("BitVM initialization took: {:?}", start.elapsed()); + BitvmCache { + intermediate_variables: map, + disprove_scripts: scripts, + } } pub fn replace_disprove_scripts(winternitz_pk: &[Vec<[u8; 20]>]) -> Vec { let start = Instant::now(); // Get the initial scripts. - let mut disprove_scripts = ALL_BITVM_DISPROVE_PROOF_LOCK - .get() - .expect("failed to get disprove scripts") - .to_vec(); - let all_bitvm_intermediate_variables = ALL_BITVM_INTERMEDIATE_VARIABLES_LOCK - .get() - .expect("failed to get intermediate variables"); - + let cache = BITVM_CACHE_LOCK.get().expect("BitVM cache not initialized"); + let mut disprove_scripts = cache.disprove_scripts.clone(); // Process each intermediate variable one at a time. for (idx, (_intermediate_step, intermediate_step_size)) in - all_bitvm_intermediate_variables.iter().enumerate() + cache.intermediate_variables.iter().enumerate() { + if idx >= winternitz_pk.len() { + panic!( + "idx out of bounds, this should never happen, winternitz_pk.len() = {}, idx = {}", + winternitz_pk.len(), + idx + ); + break; + } + // Build a dummy base public key. - // Start with 20 bytes set to 31, then overwrite the first 8 bytes with idx. let mut dummy_base = [31u8; 20]; dummy_base[..8].copy_from_slice(&idx.to_le_bytes()); @@ -133,25 +192,22 @@ pub fn replace_disprove_scripts(winternitz_pk: &[Vec<[u8; 20]>]) -> Vec actual replacement key. let mut mapping = HashMap::<[u8; 20], [u8; 20]>::with_capacity(digit_count); for digit in 0..digit_count { + if digit >= winternitz_pk[idx].len() { + panic!("digit out of bounds, this should never happen, winternitz_pk[idx].len() = {}, digit = {}", winternitz_pk[idx].len(), digit); + break; + } let mut dummy = dummy_base; - // Overwrite the last 8 bytes with the little-endian representation of the digit. dummy[12..20].copy_from_slice(&digit.to_le_bytes()); - // winternitz_pk[idx][digit] is the actual replacement value. mapping.insert(dummy, winternitz_pk[idx][digit]); } // For each script, scan through the bytes and do a one‐pass replacement. - // At each position, if the next 20 bytes match a dummy key, replace them; - // otherwise, copy one byte. for script in disprove_scripts.iter_mut() { - let script_bytes = script.as_bytes(); - let mut new_bytes = Vec::with_capacity(script_bytes.len()); + let mut new_bytes = Vec::with_capacity(script.len()); let mut pos = 0; - while pos < script_bytes.len() { - // If there are at least 20 bytes remaining, check for a dummy key. - if pos + 20 <= script_bytes.len() { - // Convert the 20‐byte window into an array. - if let Ok(candidate_arr) = <[u8; 20]>::try_from(&script_bytes[pos..pos + 20]) { + while pos < script.len() { + if pos + 20 <= script.len() { + if let Ok(candidate_arr) = <[u8; 20]>::try_from(&script[pos..pos + 20]) { if let Some(&replacement) = mapping.get(&candidate_arr) { new_bytes.extend_from_slice(&replacement); pos += 20; @@ -159,33 +215,18 @@ pub fn replace_disprove_scripts(winternitz_pk: &[Vec<[u8; 20]>]) -> Vec = { - let mut map = BTreeMap::new(); - map.insert("scalar_1".to_string(), 20); - map.insert("scalar_2".to_string(), 20); - map.insert("scalar_3".to_string(), 20); - map.insert("scalar_4".to_string(), 20); - map.insert("scalar_5".to_string(), 20); - map.insert("scalar_6".to_string(), 20); - map.insert("scalar_7".to_string(), 20); - map.insert("scalar_8".to_string(), 20); - map.insert("scalar_9".to_string(), 20); - map.insert("scalar_10".to_string(), 20); - map - }; + let mut new_disprove_scripts = Vec::with_capacity(disprove_scripts.len()); + for script in disprove_scripts { + new_disprove_scripts.push(ScriptBuf::from_bytes(script)); + } + new_disprove_scripts } /// Gets configuration from CLI, for binaries. If there are any errors, print From c06d80d82ec04593649b5600df76b5c62f69031e Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Wed, 5 Feb 2025 11:58:01 +0300 Subject: [PATCH 03/13] Use lazy static --- core/Cargo.toml | 1 - core/src/builder/sighash.rs | 4 +- core/src/operator.rs | 3 +- core/src/rpc/aggregator.rs | 45 ++++++++------ core/src/rpc/verifier.rs | 11 ++-- core/src/utils.rs | 120 +++++++++++++++++------------------- 6 files changed, 90 insertions(+), 94 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index 16312d42..9e4b1b46 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -36,7 +36,6 @@ async-stream = { workspace = true } futures-util = { workspace = true } futures-core = { workspace = true } bitvm = { workspace = true } -ctor = { workspace = true } [dev-dependencies] serial_test = { workspace = true } diff --git a/core/src/builder/sighash.rs b/core/src/builder/sighash.rs index 56a69ab7..b3c1d816 100644 --- a/core/src/builder/sighash.rs +++ b/core/src/builder/sighash.rs @@ -460,7 +460,7 @@ mod tests { use crate::builder::sighash::create_nofn_sighash_stream; use crate::extended_rpc::ExtendedRpc; use crate::operator::Operator; - use crate::utils::BITVM_CACHE_LOCK; + use crate::utils::BITVM_CACHE; use crate::watchtower::Watchtower; use crate::{builder, create_test_config_with_thread_name, utils}; use crate::{ @@ -544,7 +544,7 @@ mod tests { .unwrap(); } } - let assert_len = BITVM_CACHE_LOCK.get().unwrap().intermediate_variables.len(); + let assert_len = BITVM_CACHE.intermediate_variables.len(); for o in 0..config.num_operators { for t in 0..config.num_sequential_collateral_txs { for k in 0..config.num_kickoffs_per_sequential_collateral_tx { diff --git a/core/src/operator.rs b/core/src/operator.rs index 3919f211..988b7518 100644 --- a/core/src/operator.rs +++ b/core/src/operator.rs @@ -5,7 +5,6 @@ use crate::errors::BridgeError; use crate::extended_rpc::ExtendedRpc; use crate::musig2::AggregateFromPublicKeys; use bitcoin::{Amount, OutPoint, Txid, XOnlyPublicKey}; -use bitvm::bn254::utils; use bitvm::signatures::winternitz; use jsonrpsee::core::client::ClientT; use jsonrpsee::http_client::HttpClientBuilder; @@ -723,7 +722,7 @@ impl Operator { for kickoff_idx in 0..self.config.num_kickoffs_per_sequential_collateral_tx as u32 { // ALL_BITVM_INTERMEDIATE_VARIABLES is a global variable that contains the intermediate variables for the BitVM in BTreeMap for (intermediate_step, intermediate_step_size) in - crate::utils::BITVM_CACHE_LOCK.get().unwrap().intermediate_variables.iter() + crate::utils::BITVM_CACHE.intermediate_variables.iter() { let step_name = intermediate_step.as_str(); let path = WinternitzDerivationPath { diff --git a/core/src/rpc/aggregator.rs b/core/src/rpc/aggregator.rs index 27b5ba6e..e8622608 100644 --- a/core/src/rpc/aggregator.rs +++ b/core/src/rpc/aggregator.rs @@ -974,6 +974,7 @@ mod tests { #[tokio::test] #[serial_test::serial] async fn aggregator_setup_and_deposit() { + println!("Starting test"); let config = create_test_config_with_thread_name!(None); let aggregator = create_actors!(config).2; @@ -982,29 +983,35 @@ mod tests { .await .unwrap(); + tracing::info!("Setting up aggregator"); + println!("Setting up aggregator"); + aggregator_client .setup(tonic::Request::new(clementine::Empty {})) .await .unwrap(); - aggregator_client - .new_deposit(DepositParams { - deposit_outpoint: Some( - bitcoin::OutPoint { - txid: Txid::from_str( - "17e3fc7aae1035e77a91e96d1ba27f91a40a912cf669b367eb32c13a8f82bb02", - ) - .unwrap(), - vout: 0, - } - .into(), - ), - evm_address: [1u8; 20].to_vec(), - recovery_taproot_address: - "tb1pk8vus63mx5zwlmmmglq554kwu0zm9uhswqskxg99k66h8m3arguqfrvywa".to_string(), - user_takes_after: 5, - }) - .await - .unwrap(); + // tracing::info!("Depositing"); + // println!("Depositing"); + + // aggregator_client + // .new_deposit(DepositParams { + // deposit_outpoint: Some( + // bitcoin::OutPoint { + // txid: Txid::from_str( + // "17e3fc7aae1035e77a91e96d1ba27f91a40a912cf669b367eb32c13a8f82bb02", + // ) + // .unwrap(), + // vout: 0, + // } + // .into(), + // ), + // evm_address: [1u8; 20].to_vec(), + // recovery_taproot_address: + // "tb1pk8vus63mx5zwlmmmglq554kwu0zm9uhswqskxg99k66h8m3arguqfrvywa".to_string(), + // user_takes_after: 5, + // }) + // .await + // .unwrap(); } } diff --git a/core/src/rpc/verifier.rs b/core/src/rpc/verifier.rs index d93cb87c..959d9012 100644 --- a/core/src/rpc/verifier.rs +++ b/core/src/rpc/verifier.rs @@ -16,7 +16,7 @@ use crate::{ }, errors::BridgeError, musig2::{self}, - utils::{self, BITVM_CACHE_LOCK}, + utils::{self, BITVM_CACHE}, verifier::{NofN, NonceSession, Verifier}, EVMAddress, }; @@ -200,7 +200,7 @@ impl ClementineVerifier for Verifier { let mut operator_winternitz_public_keys = Vec::new(); for _ in 0..self.config.num_kickoffs_per_sequential_collateral_tx * self.config.num_sequential_collateral_txs - * BITVM_CACHE_LOCK.get().unwrap().intermediate_variables.len() + * BITVM_CACHE.intermediate_variables.len() { let operator_params = in_stream .message() @@ -287,7 +287,7 @@ impl ClementineVerifier for Verifier { } // Split the winternitz public keys into chunks for every sequential collateral tx and kickoff index. // This is done because we need to generate a separate BitVM setup for each collateral tx and kickoff index. - let chunk_size = BITVM_CACHE_LOCK.get().unwrap().intermediate_variables.len(); + let chunk_size = BITVM_CACHE.intermediate_variables.len(); let winternitz_public_keys_chunks = operator_winternitz_public_keys.chunks_exact(chunk_size); @@ -297,9 +297,7 @@ impl ClementineVerifier for Verifier { chunk_idx / self.config.num_kickoffs_per_sequential_collateral_tx; let kickoff_idx = chunk_idx % self.config.num_kickoffs_per_sequential_collateral_tx; - let assert_tx_addrs = BITVM_CACHE_LOCK - .get() - .unwrap() + let assert_tx_addrs = BITVM_CACHE .intermediate_variables .iter() .enumerate() @@ -326,6 +324,7 @@ impl ClementineVerifier for Verifier { // TODO: Use correct verification key and along with a dummy proof. let scripts: Vec = { + tracing::info!("Replacing disprove scripts"); utils::replace_disprove_scripts(&winternitz_public_keys) // let mut bridge_assigner = BridgeAssigner::new_watcher(commits_publickeys); // let proof = RawProof::default(); diff --git a/core/src/utils.rs b/core/src/utils.rs index 2688b390..edf0985a 100644 --- a/core/src/utils.rs +++ b/core/src/utils.rs @@ -8,17 +8,14 @@ use bitvm::chunker::chunk_groth16_verifier::groth16_verify_to_segments; use bitvm::chunker::disprove_execution::RawProof; use bitvm::signatures::signing_winternitz::WinternitzPublicKey; use bitvm::signatures::winternitz; -use sha2::digest::consts::U8; use tracing::Level; //use bitvm::chunker::assigner::BridgeAssigner; use borsh::{BorshDeserialize, BorshSerialize}; -use ctor::ctor; use std::collections::BTreeMap; use std::collections::HashMap; use std::fs; use std::process::exit; use std::str::FromStr; -use std::sync::OnceLock; use std::time::Instant; use tracing::level_filters::LevelFilter; use tracing_subscriber::layer::SubscriberExt; @@ -52,8 +49,21 @@ lazy_static::lazy_static! { // lazy_static::lazy_static! { // pub static ref ALL_BITVM_INTERMEDIATE_VARIABLES: BTreeMap = BridgeAssigner::default().all_intermediate_variable(); // } - -pub static BITVM_CACHE_LOCK: OnceLock = OnceLock::new(); +lazy_static::lazy_static! { + pub static ref BITVM_CACHE: BitvmCache = { + let start = Instant::now(); + let cache_path = "bitvm_cache.bin"; + + let bitvm_cache = BitvmCache::load_from_file(cache_path).unwrap_or_else(|| { + let fresh_data = generate_fresh_data(); + fresh_data.save_to_file(cache_path); + fresh_data + }); + + println!("BitVM initialization took: {:?}", start.elapsed()); + bitvm_cache + }; +} #[derive(BorshSerialize, BorshDeserialize, Debug)] pub struct BitvmCache { @@ -101,21 +111,6 @@ impl BitvmCache { } } -#[ctor] -fn init_all_bitvm_intermediate_variables() { - let start = Instant::now(); - let cache_path = "bitvm_cache.bin"; - - let bitvm_cache = BitvmCache::load_from_file(cache_path).unwrap_or_else(|| { - let fresh_data = generate_fresh_data(); - fresh_data.save_to_file(cache_path); - fresh_data - }); - - BITVM_CACHE_LOCK.set(bitvm_cache).unwrap(); - println!("BitVM initialization took: {:?}", start.elapsed()); -} - fn generate_fresh_data() -> BitvmCache { println!("Generating fresh BitVM data..."); let map = BridgeAssigner::default().all_intermediate_variables(); @@ -164,69 +159,66 @@ fn generate_fresh_data() -> BitvmCache { pub fn replace_disprove_scripts(winternitz_pk: &[Vec<[u8; 20]>]) -> Vec { let start = Instant::now(); + tracing::info!("Starting script replacement with {} keys", winternitz_pk.len()); + + let cache = &*BITVM_CACHE; + let mut result = Vec::with_capacity(cache.disprove_scripts.len()); - // Get the initial scripts. - let cache = BITVM_CACHE_LOCK.get().expect("BitVM cache not initialized"); - let mut disprove_scripts = cache.disprove_scripts.clone(); - // Process each intermediate variable one at a time. - for (idx, (_intermediate_step, intermediate_step_size)) in - cache.intermediate_variables.iter().enumerate() - { + // Pre-build all mappings at once + let mut all_mappings = Vec::with_capacity(cache.intermediate_variables.len()); + for (idx, (_step, size)) in cache.intermediate_variables.iter().enumerate() { if idx >= winternitz_pk.len() { - panic!( - "idx out of bounds, this should never happen, winternitz_pk.len() = {}, idx = {}", - winternitz_pk.len(), - idx - ); break; } - // Build a dummy base public key. + let mut mapping = HashMap::with_capacity(winternitz_pk[idx].len()); let mut dummy_base = [31u8; 20]; dummy_base[..8].copy_from_slice(&idx.to_le_bytes()); - // Compute the parameters and determine the number of digits. - let parameters = winternitz::Parameters::new((*intermediate_step_size as u32) * 2, 4); - let digit_count = parameters.total_digit_count() as usize; - - // Build a mapping of dummy key -> actual replacement key. - let mut mapping = HashMap::<[u8; 20], [u8; 20]>::with_capacity(digit_count); - for digit in 0..digit_count { - if digit >= winternitz_pk[idx].len() { - panic!("digit out of bounds, this should never happen, winternitz_pk[idx].len() = {}, digit = {}", winternitz_pk[idx].len(), digit); - break; - } + for (digit, &real_key) in winternitz_pk[idx].iter().enumerate() { let mut dummy = dummy_base; dummy[12..20].copy_from_slice(&digit.to_le_bytes()); - mapping.insert(dummy, winternitz_pk[idx][digit]); + mapping.insert(dummy, real_key); + } + all_mappings.push(mapping); + } + + tracing::info!("Built {} key mappings", all_mappings.len()); + + // Process each script + for (script_idx, script) in cache.disprove_scripts.iter().enumerate() { + if script_idx % 100 == 0 { + tracing::info!("Processing script {}/{}", script_idx + 1, cache.disprove_scripts.len()); } - // For each script, scan through the bytes and do a one‐pass replacement. - for script in disprove_scripts.iter_mut() { - let mut new_bytes = Vec::with_capacity(script.len()); - let mut pos = 0; - while pos < script.len() { - if pos + 20 <= script.len() { - if let Ok(candidate_arr) = <[u8; 20]>::try_from(&script[pos..pos + 20]) { - if let Some(&replacement) = mapping.get(&candidate_arr) { - new_bytes.extend_from_slice(&replacement); + let mut new_script = Vec::with_capacity(script.len()); + let mut pos = 0; + + 'outer: while pos < script.len() { + if pos + 20 <= script.len() { + if let Ok(window) = <[u8; 20]>::try_from(&script[pos..pos + 20]) { + // Try each mapping + for mapping in &all_mappings { + if let Some(&replacement) = mapping.get(&window) { + new_script.extend_from_slice(&replacement); pos += 20; - continue; + continue 'outer; } } } - new_bytes.push(script[pos]); - pos += 1; } - *script = new_bytes + new_script.push(script[pos]); + pos += 1; } + + result.push(ScriptBuf::from_bytes(new_script)); } - println!("BitVM script replacement took: {:?}", start.elapsed()); - let mut new_disprove_scripts = Vec::with_capacity(disprove_scripts.len()); - for script in disprove_scripts { - new_disprove_scripts.push(ScriptBuf::from_bytes(script)); - } - new_disprove_scripts + + let elapsed = start.elapsed(); + tracing::info!("Script replacement completed in {:?}", elapsed); + println!("Script replacement completed in {:?}", elapsed); + + result } /// Gets configuration from CLI, for binaries. If there are any errors, print From f661cf3cd7b05c5c633475ec9433280bfcf2d112 Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Wed, 5 Feb 2025 14:59:24 +0300 Subject: [PATCH 04/13] Remove ctor --- Cargo.lock | 11 ----------- Cargo.toml | 1 - 2 files changed, 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e44abc3..6891bf7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -988,7 +988,6 @@ dependencies = [ "borsh", "clap", "crypto-bigint", - "ctor", "futures", "futures-core", "futures-util", @@ -1182,16 +1181,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "ctor" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" -dependencies = [ - "quote", - "syn 2.0.94", -] - [[package]] name = "derivative" version = "2.2.0" diff --git a/Cargo.toml b/Cargo.toml index ac61701d..10f11e57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,6 @@ clap = "4.5.20" toml = "0.8.19" sqlx = { version = "0.7.4", default-features = false } serial_test = "3.2.0" -ctor = "0.2.9" # bitcoin bitcoin = { version = "0.32.5", features = ["serde"] } From f49df3cff7fc10084492529b9bf2dbfbab334044 Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Wed, 5 Feb 2025 17:36:48 +0300 Subject: [PATCH 05/13] Add dummy bitvm creation in debug mde --- core/src/rpc/aggregator.rs | 3 + core/src/utils.rs | 140 ++++++++++++++++++++++++------------- 2 files changed, 93 insertions(+), 50 deletions(-) diff --git a/core/src/rpc/aggregator.rs b/core/src/rpc/aggregator.rs index e8622608..99aa5d81 100644 --- a/core/src/rpc/aggregator.rs +++ b/core/src/rpc/aggregator.rs @@ -985,12 +985,15 @@ mod tests { tracing::info!("Setting up aggregator"); println!("Setting up aggregator"); + let start = std::time::Instant::now(); aggregator_client .setup(tonic::Request::new(clementine::Empty {})) .await .unwrap(); + println!("Setup completed in {:?}", start.elapsed()); + // tracing::info!("Depositing"); // println!("Depositing"); diff --git a/core/src/utils.rs b/core/src/utils.rs index edf0985a..89d25e66 100644 --- a/core/src/utils.rs +++ b/core/src/utils.rs @@ -54,6 +54,32 @@ lazy_static::lazy_static! { let start = Instant::now(); let cache_path = "bitvm_cache.bin"; + #[cfg(debug_assertions)] + let bitvm_cache = { + println!("Debug mode: Using dummy BitVM cache"); + // Create minimal dummy data for faster development + BitvmCache { + intermediate_variables: { + let mut map = BTreeMap::new(); + map.insert("dummy_var_1".to_string(), 4); + map.insert("dummy_var_2".to_string(), 4); + map + }, + disprove_scripts: vec![ + vec![31u8; 1000], // Dummy script 1 + vec![31u8; 1000], // Dummy script 2 + ], + replacement_places: { + let mut map = HashMap::new(); + // Add some dummy replacement places + map.insert((0, 0), vec![(0, 0)]); + map.insert((0, 1), vec![(1, 0)]); + map + }, + } + }; + + #[cfg(not(debug_assertions))] let bitvm_cache = BitvmCache::load_from_file(cache_path).unwrap_or_else(|| { let fresh_data = generate_fresh_data(); fresh_data.save_to_file(cache_path); @@ -69,6 +95,7 @@ lazy_static::lazy_static! { pub struct BitvmCache { pub intermediate_variables: BTreeMap, pub disprove_scripts: Vec>, + pub replacement_places: HashMap<(usize, usize), Vec<(usize, usize)>>, } impl BitvmCache { @@ -113,9 +140,9 @@ impl BitvmCache { fn generate_fresh_data() -> BitvmCache { println!("Generating fresh BitVM data..."); - let map = BridgeAssigner::default().all_intermediate_variables(); + let intermediate_variables = BridgeAssigner::default().all_intermediate_variables(); - let commits_publickeys = map + let commits_publickeys = intermediate_variables .iter() .enumerate() .map(|(idx, (intermediate_step, intermediate_step_size))| { @@ -146,78 +173,91 @@ fn generate_fresh_data() -> BitvmCache { let segments = groth16_verify_to_segments(&mut bridge_assigner, &proof.public, &proof.proof, &proof.vk); - let scripts = segments + let scripts: Vec> = segments .iter() .map(|s| s.script.clone().compile().to_bytes()) .collect(); + // Build mapping of dummy keys to their positions + let mut replacement_places: HashMap<(usize, usize), Vec<(usize, usize)>> = HashMap::new(); + + // For each script + for (script_idx, script) in scripts.iter().enumerate() { + let mut pos = 0; + while pos + 20 <= script.len() { + // Check if this window matches our pattern (31u8 in middle bytes) + if &script[pos + 8..pos + 12] == &[31u8; 4] { + // Try to extract the index and digit from the window + let window = &script[pos..pos + 20]; + if let Ok(window_arr) = <[u8; 20]>::try_from(window) { + // Extract idx from first 8 bytes + let mut idx_bytes = [0u8; 8]; + idx_bytes.copy_from_slice(&window_arr[..8]); + let idx = usize::from_le_bytes(idx_bytes); + + // Extract digit from last 8 bytes + let mut digit_bytes = [0u8; 8]; + digit_bytes.copy_from_slice(&window_arr[12..20]); + let digit = usize::from_le_bytes(digit_bytes); + + // If this is a valid index for our intermediate variables + if idx < intermediate_variables.len() { + let entry = replacement_places.entry((idx, digit)).or_default(); + entry.push((script_idx, pos)); + } + } + } + pos += 1; + } + } + + println!( + "Found {} unique replacement patterns", + replacement_places.len() + ); + BitvmCache { - intermediate_variables: map, + intermediate_variables, disprove_scripts: scripts, + replacement_places, } } pub fn replace_disprove_scripts(winternitz_pk: &[Vec<[u8; 20]>]) -> Vec { let start = Instant::now(); - tracing::info!("Starting script replacement with {} keys", winternitz_pk.len()); + tracing::info!( + "Starting script replacement with {} keys", + winternitz_pk.len() + ); let cache = &*BITVM_CACHE; - let mut result = Vec::with_capacity(cache.disprove_scripts.len()); - - // Pre-build all mappings at once - let mut all_mappings = Vec::with_capacity(cache.intermediate_variables.len()); - for (idx, (_step, size)) in cache.intermediate_variables.iter().enumerate() { - if idx >= winternitz_pk.len() { - break; - } - - let mut mapping = HashMap::with_capacity(winternitz_pk[idx].len()); - let mut dummy_base = [31u8; 20]; - dummy_base[..8].copy_from_slice(&idx.to_le_bytes()); - for (digit, &real_key) in winternitz_pk[idx].iter().enumerate() { - let mut dummy = dummy_base; - dummy[12..20].copy_from_slice(&digit.to_le_bytes()); - mapping.insert(dummy, real_key); - } - all_mappings.push(mapping); - } + // Clone scripts first as we'll modify them + let mut result: Vec> = cache.disprove_scripts.clone(); - tracing::info!("Built {} key mappings", all_mappings.len()); + // For each intermediate variable and its digits + for idx in 0..winternitz_pk.len() { + for digit in 0..winternitz_pk[idx].len() { + // Get all places where this (idx, digit) pattern needs to be replaced + if let Some(places) = cache.replacement_places.get(&(idx, digit)) { + let replacement = &winternitz_pk[idx][digit]; - // Process each script - for (script_idx, script) in cache.disprove_scripts.iter().enumerate() { - if script_idx % 100 == 0 { - tracing::info!("Processing script {}/{}", script_idx + 1, cache.disprove_scripts.len()); - } - - let mut new_script = Vec::with_capacity(script.len()); - let mut pos = 0; - - 'outer: while pos < script.len() { - if pos + 20 <= script.len() { - if let Ok(window) = <[u8; 20]>::try_from(&script[pos..pos + 20]) { - // Try each mapping - for mapping in &all_mappings { - if let Some(&replacement) = mapping.get(&window) { - new_script.extend_from_slice(&replacement); - pos += 20; - continue 'outer; - } - } + // For each occurrence of this pattern + for &(script_idx, pos) in places { + // Replace the pattern with the actual Winternitz key + result[script_idx][pos..pos + 20].copy_from_slice(replacement); } } - new_script.push(script[pos]); - pos += 1; } - - result.push(ScriptBuf::from_bytes(new_script)); } + // Convert all scripts to ScriptBuf + let result: Vec = result.into_iter().map(ScriptBuf::from_bytes).collect(); + let elapsed = start.elapsed(); tracing::info!("Script replacement completed in {:?}", elapsed); println!("Script replacement completed in {:?}", elapsed); - + result } From 35035748ac27fdabee2ebf53b0d38832f70f1905 Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Wed, 5 Feb 2025 17:40:46 +0300 Subject: [PATCH 06/13] Fix merge bug --- core/src/rpc/verifier.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/rpc/verifier.rs b/core/src/rpc/verifier.rs index 823dd423..0c1ef692 100644 --- a/core/src/rpc/verifier.rs +++ b/core/src/rpc/verifier.rs @@ -34,7 +34,6 @@ use bitvm::signatures::{ }; use futures::StreamExt; use secp256k1::musig::{MusigAggNonce, MusigPubNonce, MusigSecNonce}; -use std::collections::BTreeMap; use std::pin::pin; use tokio::sync::mpsc::{self, error::SendError}; use tokio_stream::wrappers::ReceiverStream; @@ -102,7 +101,7 @@ impl ClementineVerifier for Verifier { let mut operator_winternitz_public_keys = Vec::new(); for _ in 0..self.config.num_kickoffs_per_sequential_collateral_tx * self.config.num_sequential_collateral_txs - * BITVM_CACHE.len() + * BITVM_CACHE.intermediate_variables.len() { operator_winternitz_public_keys .push(parser::operator::parse_winternitz_public_keys(&mut in_stream).await?); From 1b6d8477d9e366694937bcf0f9e7081361445408 Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Wed, 5 Feb 2025 17:40:54 +0300 Subject: [PATCH 07/13] fmt --- core/src/rpc/verifier.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/rpc/verifier.rs b/core/src/rpc/verifier.rs index 0c1ef692..095c21a5 100644 --- a/core/src/rpc/verifier.rs +++ b/core/src/rpc/verifier.rs @@ -19,8 +19,8 @@ use crate::{ errors::BridgeError, fetch_next_message_from_stream, musig2::{self}, - utils::{self, BITVM_CACHE}, rpc::parser::{self}, + utils::{self, BITVM_CACHE}, verifier::{NofN, NonceSession, Verifier}, }; use bitcoin::{hashes::Hash, Amount, TapTweakHash, Txid}; From f5c4bb687db14509446d5e3ef284c507a1561af8 Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Wed, 5 Feb 2025 18:05:42 +0300 Subject: [PATCH 08/13] remove printlns, re-enable deposit test --- core/src/rpc/aggregator.rs | 50 ++++++++++++++++++-------------------- core/src/utils.rs | 19 +++++---------- 2 files changed, 30 insertions(+), 39 deletions(-) diff --git a/core/src/rpc/aggregator.rs b/core/src/rpc/aggregator.rs index 7a63413a..d72c5727 100644 --- a/core/src/rpc/aggregator.rs +++ b/core/src/rpc/aggregator.rs @@ -929,7 +929,6 @@ mod tests { #[tokio::test] #[serial_test::serial] async fn aggregator_setup_and_deposit() { - println!("Starting test"); let config = create_test_config_with_thread_name!(None); let aggregator = create_actors!(config).2; @@ -939,7 +938,6 @@ mod tests { .unwrap(); tracing::info!("Setting up aggregator"); - println!("Setting up aggregator"); let start = std::time::Instant::now(); aggregator_client @@ -947,29 +945,29 @@ mod tests { .await .unwrap(); - println!("Setup completed in {:?}", start.elapsed()); - - // tracing::info!("Depositing"); - // println!("Depositing"); - - // aggregator_client - // .new_deposit(DepositParams { - // deposit_outpoint: Some( - // bitcoin::OutPoint { - // txid: Txid::from_str( - // "17e3fc7aae1035e77a91e96d1ba27f91a40a912cf669b367eb32c13a8f82bb02", - // ) - // .unwrap(), - // vout: 0, - // } - // .into(), - // ), - // evm_address: [1u8; 20].to_vec(), - // recovery_taproot_address: - // "tb1pk8vus63mx5zwlmmmglq554kwu0zm9uhswqskxg99k66h8m3arguqfrvywa".to_string(), - // user_takes_after: 5, - // }) - // .await - // .unwrap(); + + tracing::info!("Setup completed in {:?}", start.elapsed()); + tracing::info!("Depositing"); + let deposit_start = std::time::Instant::now(); + aggregator_client + .new_deposit(DepositParams { + deposit_outpoint: Some( + bitcoin::OutPoint { + txid: Txid::from_str( + "17e3fc7aae1035e77a91e96d1ba27f91a40a912cf669b367eb32c13a8f82bb02", + ) + .unwrap(), + vout: 0, + } + .into(), + ), + evm_address: [1u8; 20].to_vec(), + recovery_taproot_address: + "tb1pk8vus63mx5zwlmmmglq554kwu0zm9uhswqskxg99k66h8m3arguqfrvywa".to_string(), + user_takes_after: 5, + }) + .await + .unwrap(); + tracing::info!("Deposit completed in {:?}", deposit_start.elapsed()); } } diff --git a/core/src/utils.rs b/core/src/utils.rs index 2926d404..41381ab5 100644 --- a/core/src/utils.rs +++ b/core/src/utils.rs @@ -104,16 +104,16 @@ impl BitvmCache { match borsh::to_vec(self) { Ok(serialized) => match fs::write(path, serialized) { Ok(_) => { - println!("Saved BitVM cache to file"); + tracing::info!("Saved BitVM cache to file"); true } Err(e) => { - println!("Failed to save BitVM cache: {}", e); + tracing::error!("Failed to save BitVM cache: {}", e); false } }, Err(e) => { - println!("Failed to serialize BitVM cache: {}", e); + tracing::error!("Failed to serialize BitVM cache: {}", e); false } } @@ -123,16 +123,16 @@ impl BitvmCache { match fs::read(path) { Ok(bytes) => match Self::try_from_slice(&bytes) { Ok(cache) => { - println!("Loaded BitVM cache from file"); + tracing::info!("Loaded BitVM cache from file"); Some(cache) } Err(e) => { - println!("Failed to deserialize BitVM cache: {}", e); + tracing::error!("Failed to deserialize BitVM cache: {}", e); None } }, Err(_) => { - println!("No BitVM cache found"); + tracing::error!("No BitVM cache found"); None } } @@ -140,7 +140,6 @@ impl BitvmCache { } fn generate_fresh_data() -> BitvmCache { - println!("Generating fresh BitVM data..."); let intermediate_variables = BridgeAssigner::default().all_intermediate_variables(); let commits_publickeys = intermediate_variables @@ -212,11 +211,6 @@ fn generate_fresh_data() -> BitvmCache { } } - println!( - "Found {} unique replacement patterns", - replacement_places.len() - ); - BitvmCache { intermediate_variables, disprove_scripts: scripts, @@ -257,7 +251,6 @@ pub fn replace_disprove_scripts(winternitz_pk: &[Vec<[u8; 20]>]) -> Vec Date: Wed, 5 Feb 2025 18:06:01 +0300 Subject: [PATCH 09/13] fmt --- core/src/rpc/aggregator.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/rpc/aggregator.rs b/core/src/rpc/aggregator.rs index d72c5727..600f5476 100644 --- a/core/src/rpc/aggregator.rs +++ b/core/src/rpc/aggregator.rs @@ -945,7 +945,6 @@ mod tests { .await .unwrap(); - tracing::info!("Setup completed in {:?}", start.elapsed()); tracing::info!("Depositing"); let deposit_start = std::time::Instant::now(); From e1ee6a7506b5b38fd9bb8648d538beab7aa62fb2 Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Wed, 5 Feb 2025 18:35:15 +0300 Subject: [PATCH 10/13] Fix bug with debug mode, remove lints --- core/src/builder/sighash.rs | 2 +- core/src/utils.rs | 45 ++++++++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/core/src/builder/sighash.rs b/core/src/builder/sighash.rs index c413a5d4..b54f1ef1 100644 --- a/core/src/builder/sighash.rs +++ b/core/src/builder/sighash.rs @@ -460,7 +460,7 @@ mod tests { use crate::operator::Operator; use crate::utils::BITVM_CACHE; use crate::watchtower::Watchtower; - use crate::{builder, create_test_config_with_thread_name, utils}; + use crate::{builder, create_test_config_with_thread_name}; use crate::{ config::BridgeConfig, database::Database, initialize_database, utils::initialize_logger, }; diff --git a/core/src/utils.rs b/core/src/utils.rs index 41381ab5..1a545233 100644 --- a/core/src/utils.rs +++ b/core/src/utils.rs @@ -4,16 +4,21 @@ use crate::errors::BridgeError; use bitcoin::key::Parity; use bitcoin::{self}; use bitcoin::{ScriptBuf, XOnlyPublicKey}; -use bitvm::chunker::assigner::BridgeAssigner; -use bitvm::chunker::chunk_groth16_verifier::groth16_verify_to_segments; -use bitvm::chunker::disprove_execution::RawProof; -use bitvm::signatures::signing_winternitz::WinternitzPublicKey; -use bitvm::signatures::winternitz; + use tracing::Level; //use bitvm::chunker::assigner::BridgeAssigner; +#[cfg(not(debug_assertions))] +use bitvm::{ + chunker::{ + assigner::BridgeAssigner, chunk_groth16_verifier::groth16_verify_to_segments, + disprove_execution::RawProof, + }, + signatures::{signing_winternitz::WinternitzPublicKey, winternitz}, +}; use borsh::{BorshDeserialize, BorshSerialize}; use std::collections::BTreeMap; use std::collections::HashMap; +#[cfg(not(debug_assertions))] use std::fs; use std::process::exit; use std::str::FromStr; @@ -53,7 +58,6 @@ lazy_static::lazy_static! { lazy_static::lazy_static! { pub static ref BITVM_CACHE: BitvmCache = { let start = Instant::now(); - let cache_path = "bitvm_cache.bin"; #[cfg(debug_assertions)] let bitvm_cache = { @@ -64,6 +68,20 @@ lazy_static::lazy_static! { let mut map = BTreeMap::new(); map.insert("dummy_var_1".to_string(), 4); map.insert("dummy_var_2".to_string(), 4); + map.insert("dummy_var_3".to_string(), 4); + map.insert("dummy_var_4".to_string(), 4); + map.insert("dummy_var_5".to_string(), 4); + map.insert("dummy_var_6".to_string(), 4); + map.insert("dummy_var_7".to_string(), 4); + map.insert("dummy_var_8".to_string(), 4); + map.insert("dummy_var_9".to_string(), 4); + map.insert("dummy_var_10".to_string(), 4); + map.insert("dummy_var_11".to_string(), 4); + map.insert("dummy_var_12".to_string(), 4); + map.insert("dummy_var_13".to_string(), 4); + map.insert("dummy_var_14".to_string(), 4); + map.insert("dummy_var_15".to_string(), 4); + map.insert("dummy_var_16".to_string(), 4); map }, disprove_scripts: vec![ @@ -81,11 +99,14 @@ lazy_static::lazy_static! { }; #[cfg(not(debug_assertions))] - let bitvm_cache = BitvmCache::load_from_file(cache_path).unwrap_or_else(|| { - let fresh_data = generate_fresh_data(); - fresh_data.save_to_file(cache_path); - fresh_data - }); + let bitvm_cache = { + let cache_path = "bitvm_cache.bin"; + BitvmCache::load_from_file(cache_path).unwrap_or_else(|| { + let fresh_data = generate_fresh_data(); + fresh_data.save_to_file(cache_path); + fresh_data + }) + }; println!("BitVM initialization took: {:?}", start.elapsed()); bitvm_cache @@ -99,6 +120,7 @@ pub struct BitvmCache { pub replacement_places: HashMap<(usize, usize), Vec<(usize, usize)>>, } +#[cfg(not(debug_assertions))] impl BitvmCache { fn save_to_file(&self, path: &str) -> bool { match borsh::to_vec(self) { @@ -139,6 +161,7 @@ impl BitvmCache { } } +#[cfg(not(debug_assertions))] fn generate_fresh_data() -> BitvmCache { let intermediate_variables = BridgeAssigner::default().all_intermediate_variables(); From 221f99f0f4b585d07e54a4d96cf3957d0a027cf7 Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Wed, 5 Feb 2025 18:41:58 +0300 Subject: [PATCH 11/13] fmt and clippy --- core/src/rpc/verifier.rs | 2 +- core/src/utils.rs | 17 ++++------------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/core/src/rpc/verifier.rs b/core/src/rpc/verifier.rs index 095c21a5..bfa6cac9 100644 --- a/core/src/rpc/verifier.rs +++ b/core/src/rpc/verifier.rs @@ -182,7 +182,7 @@ impl ClementineVerifier for Verifier { // TODO: Use correct verification key and along with a dummy proof. let scripts: Vec = { tracing::info!("Replacing disprove scripts"); - utils::replace_disprove_scripts(&winternitz_public_keys) + utils::replace_disprove_scripts(winternitz_public_keys) // let mut bridge_assigner = BridgeAssigner::new_watcher(commits_publickeys); // let proof = RawProof::default(); // let segments = groth16_verify_to_segments( diff --git a/core/src/utils.rs b/core/src/utils.rs index 1a545233..b16b4fbc 100644 --- a/core/src/utils.rs +++ b/core/src/utils.rs @@ -249,27 +249,18 @@ pub fn replace_disprove_scripts(winternitz_pk: &[Vec<[u8; 20]>]) -> Vec> = cache.disprove_scripts.clone(); - // For each intermediate variable and its digits - for idx in 0..winternitz_pk.len() { - for digit in 0..winternitz_pk[idx].len() { - // Get all places where this (idx, digit) pattern needs to be replaced + winternitz_pk.iter().enumerate().for_each(|(idx, digits)| { + digits.iter().enumerate().for_each(|(digit, replacement)| { if let Some(places) = cache.replacement_places.get(&(idx, digit)) { - let replacement = &winternitz_pk[idx][digit]; - - // For each occurrence of this pattern for &(script_idx, pos) in places { - // Replace the pattern with the actual Winternitz key result[script_idx][pos..pos + 20].copy_from_slice(replacement); } } - } - } + }); + }); - // Convert all scripts to ScriptBuf let result: Vec = result.into_iter().map(ScriptBuf::from_bytes).collect(); let elapsed = start.elapsed(); From 472d1085b3b31c99572535a7e9a434bc280bb5e8 Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Wed, 5 Feb 2025 21:34:57 +0300 Subject: [PATCH 12/13] Fix unwraps, return Result when needed --- core/src/utils.rs | 77 +++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/core/src/utils.rs b/core/src/utils.rs index b16b4fbc..a8263206 100644 --- a/core/src/utils.rs +++ b/core/src/utils.rs @@ -65,7 +65,7 @@ lazy_static::lazy_static! { // Create minimal dummy data for faster development BitvmCache { intermediate_variables: { - let mut map = BTreeMap::new(); + let mut map = BTreeMap::new(); map.insert("dummy_var_1".to_string(), 4); map.insert("dummy_var_2".to_string(), 4); map.insert("dummy_var_3".to_string(), 4); @@ -101,11 +101,17 @@ lazy_static::lazy_static! { #[cfg(not(debug_assertions))] let bitvm_cache = { let cache_path = "bitvm_cache.bin"; - BitvmCache::load_from_file(cache_path).unwrap_or_else(|| { - let fresh_data = generate_fresh_data(); - fresh_data.save_to_file(cache_path); - fresh_data - }) + match BitvmCache::load_from_file(cache_path) { + Ok(cache) => { + tracing::info!("Loaded BitVM cache from file"); + cache + } + Err(_) => { + let fresh_data = generate_fresh_data(); + fresh_data.save_to_file(cache_path); + fresh_data + } + } }; println!("BitVM initialization took: {:?}", start.elapsed()); @@ -122,42 +128,28 @@ pub struct BitvmCache { #[cfg(not(debug_assertions))] impl BitvmCache { - fn save_to_file(&self, path: &str) -> bool { - match borsh::to_vec(self) { - Ok(serialized) => match fs::write(path, serialized) { - Ok(_) => { - tracing::info!("Saved BitVM cache to file"); - true - } - Err(e) => { - tracing::error!("Failed to save BitVM cache: {}", e); - false - } - }, - Err(e) => { - tracing::error!("Failed to serialize BitVM cache: {}", e); - false - } - } + fn save_to_file(&self, path: &str) -> Result<(), BridgeError> { + let serialized = borsh::to_vec(self).map_err(|e| { + tracing::error!("Failed to serialize BitVM cache: {}", e); + BridgeError::ConfigError("Failed to serialize BitVM cache".to_string()) + })?; + + fs::write(path, serialized).map_err(|e| { + tracing::error!("Failed to save BitVM cache: {}", e); + BridgeError::ConfigError("Failed to save BitVM cache".to_string()) + }) } - fn load_from_file(path: &str) -> Option { - match fs::read(path) { - Ok(bytes) => match Self::try_from_slice(&bytes) { - Ok(cache) => { - tracing::info!("Loaded BitVM cache from file"); - Some(cache) - } - Err(e) => { - tracing::error!("Failed to deserialize BitVM cache: {}", e); - None - } - }, - Err(_) => { - tracing::error!("No BitVM cache found"); - None - } - } + fn load_from_file(path: &str) -> Result { + let bytes = fs::read(path).map_err(|e| { + tracing::error!("Failed to read BitVM cache: {}", e); + BridgeError::ConfigError("No BitVM cache found".to_string()) + })?; + + Self::try_from_slice(&bytes).map_err(|e| { + tracing::error!("Failed to deserialize BitVM cache: {}", e); + BridgeError::ConfigError("Failed to deserialize BitVM cache".to_string()) + }) } } @@ -186,10 +178,9 @@ fn generate_fresh_data() -> BitvmCache { public_key: winternitz_pk, parameters, }; - Ok((intermediate_step.clone(), winternitz_pk)) + (intermediate_step.clone(), winternitz_pk) }) - .collect::, BridgeError>>() - .unwrap(); + .collect::, BridgeError>(); let mut bridge_assigner = BridgeAssigner::new_watcher(commits_publickeys); let proof = RawProof::default(); From edf29563b0277a1974ce2ba825f8e9aaadbd1764 Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Wed, 5 Feb 2025 21:51:44 +0300 Subject: [PATCH 13/13] Fix error in release mode --- core/src/utils.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/utils.rs b/core/src/utils.rs index a8263206..c8088ed9 100644 --- a/core/src/utils.rs +++ b/core/src/utils.rs @@ -108,7 +108,9 @@ lazy_static::lazy_static! { } Err(_) => { let fresh_data = generate_fresh_data(); - fresh_data.save_to_file(cache_path); + if let Err(e) = fresh_data.save_to_file(cache_path) { + tracing::error!("Failed to save BitVM cache to file: {}", e); + } fresh_data } } @@ -180,7 +182,7 @@ fn generate_fresh_data() -> BitvmCache { }; (intermediate_step.clone(), winternitz_pk) }) - .collect::, BridgeError>(); + .collect::>(); let mut bridge_assigner = BridgeAssigner::new_watcher(commits_publickeys); let proof = RawProof::default();