Skip to content

Commit

Permalink
refactor: reorganize module structure and update dependencies in brid…
Browse files Browse the repository at this point in the history
…ge circuit implementation
  • Loading branch information
ozankaymak committed Feb 28, 2025
1 parent 05eabbb commit 95ea1e9
Show file tree
Hide file tree
Showing 20 changed files with 1,795 additions and 1,648 deletions.
4 changes: 2 additions & 2 deletions bridge-circuit-host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ edition = "2021"
[workspace]

[dependencies]
risc0-zkvm = { version = "=1.2.4", features = ["metal"]}
risc0-zkvm = { version = "=1.2.4", features = ["metal", "bonsai", "client", "prove" ]}
risc0-circuit-recursion = "=1.2.4"
risc0-groth16 = { version = "=1.2.4", default-features=false }
ark-bn254 = "=0.4.0"
ark-ff = "=0.4.0"
ark-ec = "=0.4.0"
Expand All @@ -24,7 +25,6 @@ final-spv = { git="https://github.com/chainwayxyz/risc0-to-bitvm2.git", rev="a23
borsh = {version = "1.5.3", features = ["derive"] }
num-bigint = "0.4.6"
num-traits = "0.2.19"
risc0-groth16 = "1.2.4"
anyhow = "1.0"
bitcoin = { version = "0.32.0", features = ["serde"] }
alloy = {version = "0.1", features = ["provider-http", "serde"]}
Expand Down
47 changes: 47 additions & 0 deletions bridge-circuit-host/output.txt

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions bridge-circuit-host/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use alloy::{
use alloy_primitives::U256;
use alloy_rpc_types::EIP1186AccountProofResponse;
use anyhow::bail;
use circuits_lib::bridge_circuit_core::structs::{LightClientProof, StorageProof};
use hex::decode;
use risc0_zkvm::{InnerReceipt, Receipt};
use serde_json::json;
use circuits_lib::bridge_circuit_core::structs::{LightClientProof, StorageProof};

const UTXOS_STORAGE_INDEX: [u8; 32] =
hex_literal::hex!("0000000000000000000000000000000000000000000000000000000000000026");
Expand All @@ -32,7 +32,7 @@ pub async fn fetch_light_client_proof(l1_height: u32) -> Result<(LightClientProo
.request("lightClientProver_getLightClientProofByL1Height", request)
.await
.unwrap();

let proof_str = response["proof"].as_str().expect("Proof is not a string")[2..].to_string();

let bytes = decode(proof_str).expect("Invalid hex");
Expand Down
19 changes: 9 additions & 10 deletions bridge-circuit-host/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
use bitcoin::consensus::Decodable;
use bitcoin::hashes::Hash;
use borsh::{self, BorshDeserialize};
use bridge_circuit_host::{fetch_light_client_proof, fetch_storage_proof};
use circuits_lib::bridge_circuit_core::groth16::CircuitGroth16Proof;
use circuits_lib::bridge_circuit_core::structs::WorkOnlyCircuitInput;
use circuits_lib::bridge_circuit_core::winternitz::{
generate_public_key, sign_digits, Parameters, WinternitzCircuitInput, WinternitzHandler,
};
use final_spv::merkle_tree::BitcoinMerkleTree;
use final_spv::spv::SPV;
use header_chain::header_chain::{BlockHeaderCircuitOutput, CircuitBlockHeader};
use header_chain::mmr_native::MMRNative;
use bridge_circuit_host::{fetch_light_client_proof, fetch_storage_proof};
use rand::{rngs::SmallRng, Rng, SeedableRng};
use risc0_groth16::verifying_key;
use risc0_zkvm::{
compute_image_id, default_executor, default_prover, ExecutorEnv, ProverOpts, Receipt,
};
use std::convert::TryInto;
use circuits_lib::bridge_circuit_core::groth16::CircuitGroth16Proof;
use circuits_lib::bridge_circuit_core::winternitz::{
generate_public_key, sign_digits, Parameters, WinternitzCircuitInput, WinternitzHandler,
};
use circuits_lib::bridge_circuit_core::structs::WorkOnlyCircuitInput;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{filter::EnvFilter, layer::SubscriberExt};
const HEADERS: &[u8] = include_bytes!("bin-files/testnet4-headers.bin");
const TESTNET_BLOCK_47029: &[u8] = include_bytes!("bin-files/testnet4_block_47029.bin");
const BRIDGE_CIRCUIT_ELF: &[u8] =
include_bytes!("../../risc0-circuits/elfs/testnet4-bridge-circuit-guest");
const WORK_ONLY_ELF: &[u8] =
include_bytes!("../../risc0-circuits/elfs/testnet4-work-only-guest");
const WORK_ONLY_ELF: &[u8] = include_bytes!("../../risc0-circuits/elfs/testnet4-work-only-guest");
const HEADER_CHAIN_INNER_PROOF: &[u8] = include_bytes!("bin-files/first_70000_proof.bin");

const PAYOUT_TX: [u8; 301] = hex_literal::hex!("02000000000102d43afcd7236286bee4eb5316c597b9977cae4ac69eb8f40d4a47155b94db64540000000000fdffffffeb0577a0d00e1774686e4ef6107d85509a83b63f63056a87ee4a9ff551846bf20100000000fdffffff032036963b00000000160014b9d8ffd3b02047bc33442a2c427abc54ba53a6f83a906b1e020000001600142551d4ad0ab54037f8770ae535ce2e3e56e3f9d50000000000000000036a010101418c1976233f4523d6c988d6c9430b292d5cac77d2358117eeb7dc4dfab728da305ed183fdd44054d368398b64de7ed057fe28c31c689d8ca8c9ea813e100f9203830140b452bea0f0b6ca19442142034d3d9fedfa10bec5e58c12f1f407905214a8c8594f906cb67ffac173fedfcabff55c09e2d44cb9b2cd48f87deae15f729283bf2900000000");

#[tokio::main]
async fn main() {
tracing_subscriber::registry()
.with(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("debug")))
.with(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")))
.with(tracing_subscriber::fmt::layer())
.init();

Expand Down Expand Up @@ -89,7 +89,6 @@ async fn main() {
let pub_key: Vec<[u8; 20]> = generate_public_key(&params, &secret_key);
let signature = sign_digits(&params, &secret_key, &compressed_proof_and_total_work);


let l1_hegith = 71610;
let (light_client_proof, lcp_receipt) = fetch_light_client_proof(l1_hegith).await.unwrap();

Expand Down
65 changes: 41 additions & 24 deletions circuits-lib/src/bridge_circuit/bridge_circuit.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
use bitcoin::hashes::Hash;
use storage_proof::verify_storage_proofs;
use lc_proof::lc_proof_verifier;
use risc0_zkvm::guest::env;
use std::str::FromStr;
use bridge_circuit_core::groth16::CircuitGroth16Proof;
use bridge_circuit_core::utils::hash160;
use bridge_circuit_core::winternitz::{
verify_winternitz_signature, WinternitzCircuitInput, WinternitzCircuitOutput, WinternitzHandler
verify_winternitz_signature, WinternitzCircuitInput, WinternitzCircuitOutput, WinternitzHandler,
};
use bridge_circuit_core::zkvm::ZkvmGuest;
use bridge_circuit_core::groth16::CircuitGroth16Proof;
use lc_proof::lc_proof_verifier;
use risc0_zkvm::guest::env;
use std::str::FromStr;
use storage_proof::verify_storage_proofs;

use crate::bridge_circuit::groth16::CircuitGroth16WithTotalWork;
use crate::bridge_circuit_core;

use super::{lc_proof, storage_proof};




pub fn verify_winternitz_and_groth16(input: &WinternitzHandler) -> bool {
let start = env::cycle_count();
let res = verify_winternitz_signature(input);
Expand All @@ -31,11 +28,12 @@ pub fn convert_to_groth16_and_verify(message: &Vec<u8>, pre_state: &[u8; 32]) ->
Ok(compressed_seal) => compressed_seal,
Err(_) => return false,
};

let total_work: [u8; 16] = match message[128..144].try_into() {
Ok(total_work) => total_work,
Err(_) => return false,
};
println!("Total work: {:?}", total_work);

let seal = match CircuitGroth16Proof::from_compressed(&compressed_seal) {
Ok(seal) => seal,
Expand All @@ -62,7 +60,7 @@ pub fn bridge_circuit(guest: &impl ZkvmGuest, pre_state: [u8; 32]) {
for (wt_idx, winternitz_handler) in input.winternitz_details.iter().enumerate() {
let flag = verify_winternitz_signature(winternitz_handler);
watchtower_flags.push(flag);

if flag {
wt_messages_with_idxs.push((wt_idx, winternitz_handler.message.clone()));
}
Expand All @@ -72,25 +70,34 @@ pub fn bridge_circuit(guest: &impl ZkvmGuest, pre_state: [u8; 32]) {
wt_messages_with_idxs.sort_by(|a, b| b.1.cmp(&a.1));
let mut total_work = [0u8; 32];
for pair in wt_messages_with_idxs.iter() {

// Grooth16 verification of work only circuit
if convert_to_groth16_and_verify(&pair.1, &pre_state) {
total_work[16..32].copy_from_slice(&pair.1[128..144].chunks_exact(4).flat_map(|c| c.iter().rev()).copied().collect::<Vec<_>>());
total_work[16..32].copy_from_slice(
&pair.1[128..144]
.chunks_exact(4)
.flat_map(|c| c.iter().rev())
.copied()
.collect::<Vec<_>>(),
);
break;
}
}

// If total work is less than the max total work of watchtowers, panic
if input.hcp.chain_state.total_work < total_work {
panic!("Invalid total work: Total Work {:?} - Max Total Work: {:?}", input.hcp.chain_state.total_work, total_work);
panic!(
"Invalid total work: Total Work {:?} - Max Total Work: {:?}",
input.hcp.chain_state.total_work, total_work
);
}

let num_wts = input.winternitz_details.len();
let pk_size = input.winternitz_details[0].pub_key.len();
let mut pub_key_concat: Vec<u8> = vec![0; num_wts * pk_size * 20];
for (i, wots_handler) in input.winternitz_details.iter().enumerate() {
for (j, pubkey) in wots_handler.pub_key.iter().enumerate() {
pub_key_concat[(pk_size * i * 20 + j * 20)..(pk_size * i * 20 + (j + 1) * 20)].copy_from_slice(pubkey);
pub_key_concat[(pk_size * i * 20 + j * 20)..(pk_size * i * 20 + (j + 1) * 20)]
.copy_from_slice(pubkey);
}
}

Expand All @@ -104,30 +111,40 @@ pub fn bridge_circuit(guest: &impl ZkvmGuest, pre_state: [u8; 32]) {
let state_root = lc_proof_verifier(input.lcp.clone());

// Storage proof verification for deposit tx index and withdrawal outpoint
let user_wd_outpoint_str= verify_storage_proofs(&input.sp, state_root);
let user_wd_outpoint_str = verify_storage_proofs(&input.sp, state_root);

let user_wd_outpoint = num_bigint::BigUint::from_str(&user_wd_outpoint_str).unwrap();
let user_wd_txid = bitcoin::Txid::from_byte_array(user_wd_outpoint.to_bytes_be().as_slice().try_into().unwrap());
assert_eq!(user_wd_txid, input.payout_spv.transaction.input[0].previous_output.txid);
println!("Payout transaction output: {:?}", input.payout_spv.transaction.output);
let user_wd_txid = bitcoin::Txid::from_byte_array(
user_wd_outpoint
.to_bytes_be()
.as_slice()
.try_into()
.unwrap(),
);
assert_eq!(
user_wd_txid,
input.payout_spv.transaction.input[0].previous_output.txid
);
println!(
"Payout transaction output: {:?}",
input.payout_spv.transaction.output
);

let last_output = input.payout_spv.transaction.output.last().unwrap();
let last_output_script = last_output.script_pubkey.to_bytes();

assert!(last_output_script[0] == 0x6a);
let len = last_output_script[1];
let operator_id = last_output_script[2..(2 + len as usize)].to_vec();
let operator_id = last_output_script[2..(2 + len as usize)].to_vec();

guest.commit(
&WinternitzCircuitOutput {
guest.commit(&WinternitzCircuitOutput {
winternitz_pubkeys_digest: hash160(&pub_key_concat),
correct_watchtowers: watchtower_flags,
payout_tx_blockhash: input.payout_spv.block_header.compute_block_hash(),
last_blockhash: [0u8; 32], // TODO: Change here - WE'LL CHANGE WHEN WITHDRAWAL IS AVAILABLE
deposit_txid: input.sp.txid_hex,
operator_id: operator_id,
}
);
});
let end = env::cycle_count();
println!("WNT: {}", end - start);
}
Loading

0 comments on commit 95ea1e9

Please sign in to comment.