diff --git a/Cargo.lock b/Cargo.lock index 7392b8b47..ebe450dd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1325,7 +1325,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1336,7 +1336,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -3005,7 +3005,7 @@ dependencies = [ [[package]] name = "bitvm" version = "0.1.0" -source = "git+https://github.com/GOATNetwork/BitVM.git?branch=gc-v2#e369b2a59d86dad2bdc52daeb5fc6b890e9dc812" +source = "git+https://github.com/GOATNetwork/BitVM.git?branch=gc-v2#bab46c2336ad98513bcb8cbaff21b5506a4dcd9a" dependencies = [ "ark-bn254", "ark-crypto-primitives", @@ -3050,6 +3050,7 @@ dependencies = [ "bitvm 0.1.0 (git+https://github.com/GOATNetwork/BitVM.git?branch=gc-v2)", "chacha20poly1305", "clap", + "esplora-client", "garbled-snark-verifier", "goat", "hex", @@ -3058,6 +3059,8 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rayon", + "reqwest 0.11.27", + "reqwest 0.12.28", "secp256k1 0.29.1", "serde", "serde-big-array", @@ -3065,6 +3068,7 @@ dependencies = [ "sha2 0.10.9", "soldering-host", "strum 0.26.3", + "tokio", "tracing", "uuid 1.23.0", "verifiable-circuit-babe", @@ -4827,7 +4831,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -5740,7 +5744,7 @@ dependencies = [ [[package]] name = "goat" version = "0.1.0" -source = "git+https://github.com/GOATNetwork/BitVM.git?branch=gc-v2#e369b2a59d86dad2bdc52daeb5fc6b890e9dc812" +source = "git+https://github.com/GOATNetwork/BitVM.git?branch=gc-v2#bab46c2336ad98513bcb8cbaff21b5506a4dcd9a" dependencies = [ "ark-bn254", "ark-crypto-primitives", @@ -5756,6 +5760,7 @@ dependencies = [ "bitcoin-script", "bitcoin-scriptexec", "bitvm 0.1.0 (git+https://github.com/GOATNetwork/BitVM.git?branch=gc-v2)", + "blake3", "clap", "colored", "hex", @@ -8188,7 +8193,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -11315,7 +11320,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -11418,7 +11423,7 @@ dependencies = [ "security-framework 3.7.0", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -12175,7 +12180,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -12863,7 +12868,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix 1.1.4", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -14283,7 +14288,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 54b874f45..4fc54ca9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ members = [ "crates/header-chain", "crates/commit-chain", "crates/state-chain", - #"crates/mara-slipstream-client", "crates/bitcoin-light-client-circuit", "crates/verifier", "circuits/header-chain-proof/host", diff --git a/crates/bitvm-gc/Cargo.toml b/crates/bitvm-gc/Cargo.toml index d6e9e3795..50ae4e378 100644 --- a/crates/bitvm-gc/Cargo.toml +++ b/crates/bitvm-gc/Cargo.toml @@ -37,7 +37,11 @@ strum = { workspace = true, features = ["derive"] } [dev-dependencies] ark-crypto-primitives = { workspace = true } ark-ec = { workspace = true } +esplora-client = { workspace = true } rand_chacha = { workspace = true } +reqwest = { workspace = true } +reqwest-0-11 = { package = "reqwest", version = "0.11.27", default-features = false, features = ["json", "rustls-tls"] } +tokio = { workspace = true, features = ["macros", "time"] } [features] default = [] diff --git a/crates/bitvm-gc/src/verifier/api.rs b/crates/bitvm-gc/src/verifier/api.rs index c9b4b7c06..53deee6d2 100644 --- a/crates/bitvm-gc/src/verifier/api.rs +++ b/crates/bitvm-gc/src/verifier/api.rs @@ -362,3 +362,107 @@ pub fn disprove_timelock(network: Network) -> u32 { pub fn disprove_timelock_with_config(network: Network, timelock_config: &TimelockConfig) -> u32 { disprove_timelock_blocks(network, timelock_config) } + +#[cfg(test)] +mod tests { + use super::*; + use bitcoin::{ + OutPoint, TxOut, XOnlyPublicKey, + secp256k1::{Keypair, SECP256K1, SecretKey}, + }; + use goat::{ + connectors::{ + base::TaprootConnector, + connector_d::{CONNECTOR_D_PUBIN_DISPROVE_LEAF_INDEX, ConnectorD}, + }, + scripts::{generate_opreturn_script, p2a_output}, + transactions::base::{Input, pubin_disprove_input_amount}, + }; + + #[test] + fn pubin_disprove_with_witness_is_standard_sized() { + let operator_secret = SecretKey::from_slice(&[1; 32]).expect("valid operator secret"); + let committee_secret = SecretKey::from_slice(&[2; 32]).expect("valid committee secret"); + let operator_keypair = Keypair::from_secret_key(SECP256K1, &operator_secret); + let committee_keypair = Keypair::from_secret_key(SECP256K1, &committee_secret); + let operator_key = + XOnlyPublicKey::from(bitcoin::PublicKey::from(operator_keypair.public_key())); + let committee_key = + XOnlyPublicKey::from(bitcoin::PublicKey::from(committee_keypair.public_key())); + + let guest_secret = Wots96::generate_secret_key(); + let guest_public_key = Wots96::generate_public_key(&guest_secret); + let assert_secret = Wots96::generate_secret_key(); + let assert_public_key = Wots96::generate_public_key(&assert_secret); + let expected_constant = [0x22; 32]; + let mut guest_pubin = [0u8; 96]; + guest_pubin[..32].fill(0x11); + guest_pubin[32..64].fill(0x23); + guest_pubin[64..].fill(0xff); + let operator_assert_pubin = [0u8; 96]; + + let connector_d = ConnectorD::new( + Network::Testnet4, + &operator_key, + &committee_key, + &guest_public_key, + &assert_public_key, + &expected_constant, + &vec![], + &default_timelock_config(Network::Testnet4), + ); + let assert_witness = + Wots96::sign_to_raw_witness(&assert_secret, &operator_assert_pubin).to_vec(); + let guest_witness = Wots96::sign_to_raw_witness(&guest_secret, &guest_pubin).to_vec(); + assert!( + validate_pubin( + guest_witness.clone(), + assert_witness.clone(), + vec![], + connector_d.generate_taproot_leaf_script(CONNECTOR_D_PUBIN_DISPROVE_LEAF_INDEX), + ) + .is_some(), + "locally constructed pubin-disprove witness must satisfy Connector-D", + ); + let mut witness = assert_witness; + witness.extend(guest_witness); + let input = pubin_disprove( + &connector_d, + &Input { + outpoint: OutPoint::null(), + amount: Amount::from_sat(pubin_disprove_input_amount()), + }, + witness, + ) + .expect("build pubin-disprove input"); + let tx = Transaction { + version: bitcoin::transaction::Version(2), + lock_time: bitcoin::absolute::LockTime::ZERO, + input: vec![input], + output: vec![ + p2a_output(), + TxOut { + value: Amount::ZERO, + script_pubkey: generate_opreturn_script(b"pubin-disprove".to_vec()), + }, + ], + }; + + let base_size = tx.base_size(); + let witness_size = tx.input[0].witness.size(); + let total_size = tx.total_size(); + println!( + "pubin-disprove tx sizes: base_size={base_size}, witness_size={witness_size}, total_size={total_size}" + ); + assert_eq!( + total_size, + base_size + witness_size + 2, + "pubin-disprove total size must include the SegWit marker/flag and script witness: total={total_size}, base={base_size}, witness={witness_size}", + ); + assert!( + tx.weight() <= Transaction::MAX_STANDARD_WEIGHT, + "pubin-disprove exceeds Bitcoin Core's standard transaction limit: weight={}, total_size={total_size}", + tx.weight().to_wu(), + ); + } +} diff --git a/crates/bitvm-gc/tests/regtest.rs b/crates/bitvm-gc/tests/regtest.rs new file mode 100644 index 000000000..57b804155 --- /dev/null +++ b/crates/bitvm-gc/tests/regtest.rs @@ -0,0 +1,1242 @@ +use anyhow::{Context, Result, anyhow, bail, ensure}; +use ark_bn254::{Bn254, Fr, G1Affine, G2Affine}; +use ark_ec::AffineRepr; +use ark_groth16::Proof; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use bitcoin::hashes::{Hash, hash160}; +use bitcoin::key::Keypair; +use bitcoin::secp256k1::{SECP256K1, SecretKey}; +use bitcoin::{ + Address, Amount, EcdsaSighashType, Network, OutPoint, PublicKey, ScriptBuf, Sequence, + Transaction, TxIn, TxOut, Txid, XOnlyPublicKey, absolute, transaction, +}; +use bitcoin_script::script; +use bitvm_gc::babe_adapter::{ + BABE_M_CC, BabeProverState, CACSetupPackage, TxAssertWitness, assert_wots_message, + build_assert_witness, build_setup_package, derive_finalized_indices, extract_gc_circuit_data, + open_and_solder, recover_operator_proof_from_assert_witness, verify_setup, +}; +use bitvm_gc::committee::{ + agg_and_push_pegin_confirm_sigs, committee_pre_sign, generate_nonce_from_seed, key_aggregation, + nonce_aggregation, nonces_aggregation, push_committee_pre_signatures, sign_pegin_confirm, + signature_aggregation, verify_graph_committee_pre_signatures, verify_nonce_signatures, +}; +use bitvm_gc::keys::{CommitteeMasterKey, OperatorMasterKey}; +use bitvm_gc::operator::{ + generate_bitvm_graph, operator_pre_sign, operator_sign_assert, operator_sign_challenge_ack, + operator_sign_commit_pubin, operator_sign_kickoff, operator_sign_prekickoff_input_0, + operator_sign_take1, operator_sign_take2, operator_sign_watchtower_challenge_init, + operator_sign_watchtower_challenge_timeout, operator_sign_wrongly_challenged, + verify_graph_operator_pre_signatures, +}; +use bitvm_gc::timelocks::{ + connector_f_timelock_blocks, default_timelock_config, disprove_timelock_blocks, + operator_ack_timelock_blocks, operator_commit_timelock_blocks, take1_timelock_blocks, + take2_timelock_blocks, watchtower_challenge_timelock_blocks, +}; +use bitvm_gc::types::{ + BitvmGcCircuitData, BitvmGcGraph, BitvmGcGraphParameters, BitvmGcInstanceParameters, + PrekickoffParameters, UserInfo, +}; +use bitvm_gc::verifier::{ + build_disprove_tx, build_pubin_disprove_txin, build_verifier_assert_tx, export_challenge_tx, + validate_pubin_disprove, +}; +use bitvm_gc::watchtower::{build_watchtower_challenge_tx, estimate_watchtower_challenge_vbytes}; +use esplora_client::AsyncClient as EsploraClient; +use goat::assert_scripts::{INPUT_WIRE_NUM, Label, WireHash, label_hash}; +use goat::connectors::base::TaprootConnector; +use goat::connectors::kickoff_connectors::{ + ForceSkipConnector, KickoffConnector, PrekickoffConnector, +}; +use goat::scripts::{generate_opreturn_script, p2a_output}; +use goat::transactions::base::{DUST_AMOUNT, Input}; +use goat::transactions::pre_signed::PreSignedTransaction; +use goat::transactions::prekickoff::PrekickoffTransaction; +use goat::transactions::signing::populate_p2wsh_witness; +use reqwest::Client; +use serde::{Deserialize, Serialize, de::DeserializeOwned}; +use serde_json::{Value, json}; +use sha2::{Digest, Sha256}; +use std::fs; +use std::path::{Path, PathBuf}; +use std::sync::OnceLock; +use std::time::{Duration, Instant}; +use tokio::time::sleep; +use uuid::Uuid; + +const REGTEST_ESPLORA_URL: &str = "http://127.0.0.1:3002"; +const REGTEST_RPC_URL: &str = "http://127.0.0.1:18443/wallet/alice"; +const FIXTURE_VERSION: u32 = 1; +const FIXTURE_FILE: &str = "bitvm-gc-regtest-proof-gc-v1.bin"; +const DEFAULT_FEE_SATS: u64 = 1_000; +const PREKICKOFF_AMOUNT_SATS: u64 = 500_000; +const PEGIN_AMOUNT_SATS: u64 = 100_000_000; +const PAYER_AMOUNT_SATS: u64 = 5_000_000; +const FEE_RATE_SAT_PER_VBYTE: u64 = 2; +const CONFIRM_TIMEOUT: Duration = Duration::from_secs(60); + +static MOCK_FIXTURE: OnceLock> = OnceLock::new(); + +#[derive(Serialize, Deserialize)] +struct MockProofGcFixture { + version: u32, + setup_package: CACSetupPackage, + opened: Vec<(usize, u64)>, + prover_state: BabeProverState, + gc_data: BitvmGcCircuitData, + proof_bytes: Vec, +} + +struct TestKeys { + user: Keypair, + operator: Keypair, + challenger: Keypair, + committee: Vec, + verifier: Keypair, + watchtowers: Vec, +} + +struct RegtestRpc { + client: Client, + url: String, + user: String, + password: String, +} + +struct RegtestGraph { + graph: BitvmGcGraph, + keys: TestKeys, + assert_witness: TxAssertWitness, + challenge_labels: Vec