Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion circuits/operator-proof/guest/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 0 additions & 4 deletions circuits/operator-proof/guest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ alloy-primitives = { version = "1.0.0", features = ["sha3-keccak", "map-foldhash
#revm = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2", features = ["serde", "bn"], default-features = false }
sha2 = "0.10.9"

[build-dependencies]
hex = "0.4.3"


[patch.crates-io]
# Precompile patches
sha2 = { git = "https://github.com/ziren-patches/RustCrypto-hashes", branch = "patch-sha2-0.10.9", package = "sha2" }
Expand Down
68 changes: 0 additions & 68 deletions circuits/operator-proof/guest/build.rs

This file was deleted.

7 changes: 4 additions & 3 deletions circuits/operator-proof/guest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ use header_chain::{HeaderChainCircuitInput, SPV};
use state_chain::StateChainCircuitInput;
use std::str::FromStr;

include!(concat!(env!("OUT_DIR"), "/fixed_watchtowers.rs"));

pub fn main() {
// calculate operator public input: https://github.com/ProjectZKM/Ziren/blob/main/crates/sdk/src/utils.rs#L42
let included_watchtowers: U256 = zkm_zkvm::io::read::<U256>();
Expand All @@ -20,6 +18,8 @@ pub fn main() {
let latest_sequencer_commit_txid = operator_latest_sequencer_commit_txn.compute_txid(); // public input

// https://github.com/KSlashh/BitVM/blob/v2/goat/src/transactions/watchtower_challenge.rs#L128
let watchtower_challenge_indices: Vec<u16> = zkm_zkvm::io::read();
let graph_watchtower_xonly_public_keys: Vec<[u8; 32]> = zkm_zkvm::io::read();
let watchtower_challenge_txns: Vec<Transaction> = zkm_zkvm::io::read();
let watchtower_challenge_txn_pubkey: Vec<bitcoin::secp256k1::PublicKey> = zkm_zkvm::io::read();
let watchtower_challenge_txn_scripts: Vec<ScriptBuf> = zkm_zkvm::io::read();
Expand All @@ -36,11 +36,12 @@ pub fn main() {
included_watchtowers,
graph_id,
operator_genesis_sequencer_commit_txid,
watchtower_challenge_indices,
watchtower_challenge_txns,
watchtower_challenge_txn_pubkey,
watchtower_challenge_txn_scripts,
watchtower_challenge_txn_prev_outs,
&FIXED_WATCHTOWER_XONLY_PUBLIC_KEYS,
&graph_watchtower_xonly_public_keys,
operator_header_chain,
operator_commit_chain,
operator_state_chain,
Expand Down
8 changes: 0 additions & 8 deletions circuits/operator-proof/host/build.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
use zkm_build::build_program;

const ENV_FIXED_WATCHTOWER_KEYS: &str = "FIXED_WATCHTOWER_XONLY_PUBLIC_KEYS";

fn main() {
println!("cargo:rerun-if-env-changed={ENV_FIXED_WATCHTOWER_KEYS}");
if std::env::var(ENV_FIXED_WATCHTOWER_KEYS).is_err() {
println!(
"cargo:warning={ENV_FIXED_WATCHTOWER_KEYS} is not set; building operator guest with an empty fixed watchtower list"
);
}
build_program("../guest");
}
58 changes: 44 additions & 14 deletions circuits/operator-proof/host/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,34 @@ use sha2::{Digest, Sha256};
use std::sync::OnceLock;
static ELF_ID: OnceLock<String> = OnceLock::new();

/// Parses the full graph key list and keeps each included challenge's original graph index.
fn parse_indexed_watchtower_inputs(
watchtower_challenge_txids: &str,
watchtower_public_keys: &str,
) -> anyhow::Result<(Vec<(u16, Txid, PublicKey)>, Vec<[u8; 32]>)> {
let txids = watchtower_challenge_txids.split(',').collect::<Vec<_>>();
let public_keys = watchtower_public_keys
.split(',')
.map(PublicKey::from_str)
.collect::<Result<Vec<_>, _>>()?;
anyhow::ensure!(
txids.len() == public_keys.len(),
"watchtower challenge txids and public keys must have equal lengths"
);
anyhow::ensure!(!public_keys.is_empty(), "watchtower public key list must not be empty");
anyhow::ensure!(public_keys.len() <= 256, "watchtower public key list exceeds 256 entries");

let graph_keys = public_keys.iter().map(|key| key.x_only_public_key().0.serialize()).collect();
let included = txids
.iter()
.enumerate()
.filter(|(_, txid)| !txid.trim().is_empty())
.map(|(index, txid)| Ok((index as u16, Txid::from_str(txid)?, public_keys[index])))
.collect::<anyhow::Result<Vec<_>>>()?;

Ok((included, graph_keys))
}

pub async fn fetch_target_block_and_watchtower_tx(
esplora_url: &str,
latest_sequencer_commit_txid: &str,
Expand All @@ -102,19 +130,15 @@ pub async fn fetch_target_block_and_watchtower_tx(
bitcoin::Block,
BlockHash,
Transaction,
Vec<u16>,
Vec<[u8; 32]>,
Vec<Transaction>,
Vec<TxOut>,
Vec<PublicKey>,
Vec<ScriptBuf>,
)> {
let watchtower_challenge_txids: Vec<&str> =
watchtower_challenge_txids.split(",").filter(|s| !s.is_empty()).collect();
let watchtower_public_keys: Vec<&str> =
watchtower_public_keys.split(",").filter(|s| !s.is_empty()).collect();
anyhow::ensure!(
watchtower_challenge_txids.len() == watchtower_public_keys.len(),
"watchtower challenge txids and public keys must have equal lengths"
);
let (indexed_watchtower_inputs, graph_watchtower_xonly_public_keys) =
parse_indexed_watchtower_inputs(watchtower_challenge_txids, watchtower_public_keys)?;
let btc_client = BTCClient::new(bitcoin_network, Some(&esplora_url));

let latest_sequencer_commit_txid = Txid::from_str(&latest_sequencer_commit_txid)?;
Expand Down Expand Up @@ -166,6 +190,7 @@ pub async fn fetch_target_block_and_watchtower_tx(

// --- watchtower_challenge_txns --- //
let mut watchtower_challenge_txns = Vec::new();
let mut watchtower_challenge_indices = Vec::new();
let mut watchtower_challenge_txn_prev_outs: Vec<TxOut> = Vec::new();
let mut watchtower_challenge_txn_pubkeys = Vec::new();
let mut watchtower_challenge_txn_scripts: Vec<ScriptBuf> = Vec::new();
Expand All @@ -179,21 +204,20 @@ pub async fn fetch_target_block_and_watchtower_tx(
),
};

for (id, pk) in watchtower_challenge_txids.iter().zip(watchtower_public_keys.iter()) {
tracing::info!("txid: {}, pk: {}", id, pk);
let txid = id.parse()?;
for (node_index, txid, public_key) in indexed_watchtower_inputs {
tracing::info!("txid: {}, pk: {}", txid, public_key);
let txn = match btc_client.get_tx(&txid).await? {
Some(tx) => tx,
None => anyhow::bail!("Failed to fetch watchtower challenge txn: {}", id),
None => anyhow::bail!("Failed to fetch watchtower challenge txn: {}", txid),
};
// get prev outs
// FIXME: update the index
let index = txn.input[0].previous_output.vout as usize;
watchtower_challenge_txn_prev_outs
.push(watchtower_challlenge_init_txn.output[index].clone());

let public_key = PublicKey::from_str(pk).unwrap();
watchtower_challenge_txn_pubkeys.push(public_key.clone());
watchtower_challenge_indices.push(node_index);
watchtower_challenge_txn_pubkeys.push(public_key);
watchtower_challenge_txns.push(txn);

// https://github.com/GOATNetwork/BitVM/blob/GA/goat/src/transactions/watchtower_challenge.rs#L45
Expand All @@ -214,6 +238,8 @@ pub async fn fetch_target_block_and_watchtower_tx(
target_block_ss_commit,
operator_committed_blockhash,
operator_latest_sequencer_commit_txn,
watchtower_challenge_indices,
graph_watchtower_xonly_public_keys,
watchtower_challenge_txns,
watchtower_challenge_txn_prev_outs,
watchtower_challenge_txn_pubkeys,
Expand Down Expand Up @@ -271,6 +297,8 @@ impl ProofBuilder for OperatorProofBuilder {

operator_committed_blockhash,

watchtower_challenge_indices,
graph_watchtower_xonly_public_keys,
watchtower_challenge_txns,
watchtower_challenge_txn_prev_outs,
watchtower_challenge_txn_pubkeys,
Expand Down Expand Up @@ -413,6 +441,8 @@ impl ProofBuilder for OperatorProofBuilder {
stdin.write(&operator_genesis_sequencer_commit_txid.to_byte_array());
stdin.write(&operator_latest_sequencer_commit_txn);

stdin.write(&watchtower_challenge_indices);
stdin.write(&graph_watchtower_xonly_public_keys);
stdin.write(&watchtower_challenge_txns);
stdin.write(&watchtower_challenge_txn_pubkeys);
stdin.write(&watchtower_challenge_txn_scripts);
Expand Down
4 changes: 4 additions & 0 deletions circuits/operator-proof/host/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ async fn main() {
target_block_ss_commit,
operator_committed_blockhash,
operator_latest_sequencer_commit_txn,
watchtower_challenge_indices,
graph_watchtower_xonly_public_keys,
watchtower_challenge_txns,
watchtower_challenge_txn_prev_outs,
watchtower_challenge_txn_pubkeys,
Expand Down Expand Up @@ -51,6 +53,8 @@ async fn main() {
operator_latest_sequencer_commit_txn,
operator_committed_blockhash,

watchtower_challenge_indices,
graph_watchtower_xonly_public_keys,
watchtower_challenge_txns,
watchtower_challenge_txn_prev_outs,
watchtower_challenge_txn_pubkeys,
Expand Down
2 changes: 2 additions & 0 deletions circuits/proof-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ pub enum ProofRequest {

operator_committed_blockhash: BlockHash,

watchtower_challenge_indices: Vec<u16>,
graph_watchtower_xonly_public_keys: Vec<[u8; 32]>,
watchtower_challenge_txns: Vec<Transaction>,
watchtower_challenge_txn_prev_outs: Vec<TxOut>,
watchtower_challenge_txn_pubkeys: Vec<bitcoin::secp256k1::PublicKey>,
Expand Down
Loading