From c3a2ed2cfb11d4be138cd338897930fe7442b817 Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Thu, 6 Feb 2025 14:23:48 +0300 Subject: [PATCH] Calculate BitVM with dummy winternitz at init (#498) * Calculate BitVM with dummy winternitz at init * Add bitvm caching * Use lazy static * Remove ctor * Add dummy bitvm creation in debug mde * Fix merge bug * fmt * remove printlns, re-enable deposit test * fmt * Fix bug with debug mode, remove lints * fmt and clippy * Fix unwraps, return Result when needed * Fix error in release mode --- Cargo.lock | 199 ++++++++++++++++++++++++------- Cargo.toml | 15 +-- core/src/builder/sighash.rs | 5 +- core/src/operator.rs | 3 +- core/src/rpc/aggregator.rs | 7 ++ core/src/rpc/verifier.rs | 43 ++----- core/src/utils.rs | 231 +++++++++++++++++++++++++++++++++--- 7 files changed, 400 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3bf24ef4..6891bf7f 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", @@ -2851,7 +2957,7 @@ dependencies = [ "ark-bn254", "ark-ec", "ark-groth16", - "ark-serialize", + "ark-serialize 0.4.2", "bytemuck", "hex", "num-bigint", @@ -3093,7 +3199,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 +4656,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..10f11e57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,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 +46,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/src/builder/sighash.rs b/core/src/builder/sighash.rs index 03de726b..b54f1ef1 100644 --- a/core/src/builder/sighash.rs +++ b/core/src/builder/sighash.rs @@ -458,8 +458,9 @@ mod tests { use crate::builder::sighash::create_nofn_sighash_stream; use crate::extended_rpc::ExtendedRpc; 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, }; @@ -541,7 +542,7 @@ mod tests { .unwrap(); } } - let assert_len = utils::ALL_BITVM_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 59e7e848..988b7518 100644 --- a/core/src/operator.rs +++ b/core/src/operator.rs @@ -4,7 +4,6 @@ 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::signatures::winternitz; use jsonrpsee::core::client::ClientT; @@ -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 - ALL_BITVM_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 af3e2328..600f5476 100644 --- a/core/src/rpc/aggregator.rs +++ b/core/src/rpc/aggregator.rs @@ -937,11 +937,17 @@ mod tests { .await .unwrap(); + tracing::info!("Setting up aggregator"); + let start = std::time::Instant::now(); + aggregator_client .setup(tonic::Request::new(clementine::Empty {})) .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( @@ -961,5 +967,6 @@ mod tests { }) .await .unwrap(); + tracing::info!("Deposit completed in {:?}", deposit_start.elapsed()); } } diff --git a/core/src/rpc/verifier.rs b/core/src/rpc/verifier.rs index 28281528..bfa6cac9 100644 --- a/core/src/rpc/verifier.rs +++ b/core/src/rpc/verifier.rs @@ -20,7 +20,7 @@ use crate::{ fetch_next_message_from_stream, musig2::{self}, rpc::parser::{self}, - utils, + utils::{self, BITVM_CACHE}, verifier::{NofN, NonceSession, Verifier}, }; use bitcoin::{hashes::Hash, Amount, TapTweakHash, Txid}; @@ -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 - * utils::ALL_BITVM_INTERMEDIATE_VARIABLES.len() + * BITVM_CACHE.intermediate_variables.len() { operator_winternitz_public_keys .push(parser::operator::parse_winternitz_public_keys(&mut in_stream).await?); @@ -145,7 +144,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.intermediate_variables.len(); let winternitz_public_keys_chunks = operator_winternitz_public_keys.chunks_exact(chunk_size); @@ -155,30 +154,8 @@ 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 { - 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 + let assert_tx_addrs = BITVM_CACHE + .intermediate_variables .iter() .enumerate() .map(|(idx, (_intermediate_step, intermediate_step_size))| { @@ -204,6 +181,8 @@ 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(); // let segments = groth16_verify_to_segments( @@ -217,9 +196,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); @@ -238,7 +217,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 bde78654..c8088ed9 100644 --- a/core/src/utils.rs +++ b/core/src/utils.rs @@ -2,13 +2,27 @@ use crate::cli::Args; use crate::config::BridgeConfig; use crate::errors::BridgeError; use bitcoin::key::Parity; -use bitcoin::XOnlyPublicKey; use bitcoin::{self}; +use bitcoin::{ScriptBuf, XOnlyPublicKey}; + 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; +use std::time::Instant; use tracing::level_filters::LevelFilter; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::{fmt, EnvFilter, Registry}; @@ -41,24 +55,213 @@ lazy_static::lazy_static! { // lazy_static::lazy_static! { // pub static ref ALL_BITVM_INTERMEDIATE_VARIABLES: BTreeMap = BridgeAssigner::default().all_intermediate_variable(); // } - lazy_static::lazy_static! { - pub static ref ALL_BITVM_INTERMEDIATE_VARIABLES: BTreeMap = { + pub static ref BITVM_CACHE: BitvmCache = { + let start = Instant::now(); + + #[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("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 + 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![ + 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 = { + let cache_path = "bitvm_cache.bin"; + match BitvmCache::load_from_file(cache_path) { + Ok(cache) => { + tracing::info!("Loaded BitVM cache from file"); + cache + } + Err(_) => { + let fresh_data = generate_fresh_data(); + if let Err(e) = fresh_data.save_to_file(cache_path) { + tracing::error!("Failed to save BitVM cache to file: {}", e); + } + fresh_data + } + } + }; + + println!("BitVM initialization took: {:?}", start.elapsed()); + bitvm_cache }; } +#[derive(BorshSerialize, BorshDeserialize, Debug)] +pub struct BitvmCache { + pub intermediate_variables: BTreeMap, + pub disprove_scripts: Vec>, + pub replacement_places: HashMap<(usize, usize), Vec<(usize, usize)>>, +} + +#[cfg(not(debug_assertions))] +impl BitvmCache { + 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) -> 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()) + }) + } +} + +#[cfg(not(debug_assertions))] +fn generate_fresh_data() -> BitvmCache { + let intermediate_variables = BridgeAssigner::default().all_intermediate_variables(); + + let commits_publickeys = intermediate_variables + .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); + + let digit_count = parameters.total_digit_count() as usize; + let mut winternitz_pk = Vec::with_capacity(digit_count); + + for i in 0..digit_count { + let mut new_pk = dummy_pk; + new_pk[12..20].copy_from_slice(&i.to_le_bytes()); + winternitz_pk.push(new_pk); + } + + let winternitz_pk = WinternitzPublicKey { + public_key: winternitz_pk, + parameters, + }; + (intermediate_step.clone(), winternitz_pk) + }) + .collect::>(); + + 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: 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; + } + } + + BitvmCache { + 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() + ); + + let cache = &*BITVM_CACHE; + let mut result: Vec> = cache.disprove_scripts.clone(); + + 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)) { + for &(script_idx, pos) in places { + result[script_idx][pos..pos + 20].copy_from_slice(replacement); + } + } + }); + }); + + let result: Vec = result.into_iter().map(ScriptBuf::from_bytes).collect(); + + let elapsed = start.elapsed(); + tracing::info!("Script replacement completed in {:?}", elapsed); + + result +} + /// Gets configuration from CLI, for binaries. If there are any errors, print /// error to stderr and exit program. ///