Skip to content

Commit

Permalink
Merge pull request #19 from chainwayxyz/ekrem/gate-response
Browse files Browse the repository at this point in the history
Ekrem/gate response
  • Loading branch information
ekrembal authored Dec 7, 2023
2 parents 7185621 + 5108233 commit 0cfd98d
Show file tree
Hide file tree
Showing 9 changed files with 337 additions and 18 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ edition = "2021"

[dependencies]
bitcoin = {version = "0.31.0", features = ["rand"]}
hex = "0.4.3"
rand = "0.8.5"

[dev-dependencies]
bitcoin-scriptexec = { git = "https://github.com/ekrembal/rust-bitcoin-scriptexec" }
bitcoin-scriptexec = { git = "https://github.com/ekrembal/rust-bitcoin-scriptexec" }
2 changes: 1 addition & 1 deletion src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ impl CircuitTrait for Circuit {
&secp,
internal_key,
tree_info.merkle_root(),
Network::Bitcoin,
Network::Signet,
)
}
}
Expand Down
184 changes: 175 additions & 9 deletions src/gates.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
use bitcoin::opcodes::all::{
OP_AND, OP_EQUALVERIFY, OP_FROMALTSTACK, OP_NOT, OP_SHA256, OP_TOALTSTACK, OP_XOR,
};
use bitcoin::script::Builder;
use bitcoin::ScriptBuf;

use crate::traits::wire::WireTrait;
use crate::{traits::gate::GateTrait, wire::Wire};
use std::cell::RefCell;
use std::rc::Rc;
Expand Down Expand Up @@ -27,8 +34,25 @@ impl GateTrait for NotGate {
out.selector = Some(w);
}

fn create_challenge_script(&self) -> String {
"NotGate".to_string()
fn create_response_script(&self, lock_hash: [u8; 32]) -> ScriptBuf {
let builder = Builder::new()
.push_opcode(OP_SHA256)
.push_slice(lock_hash)
.push_opcode(OP_EQUALVERIFY);
let builder = self.output_wires[0]
.try_borrow()
.unwrap()
.add_bit_commitment_script(builder)
.push_opcode(OP_TOALTSTACK);
let builder = self.input_wires[0]
.try_borrow()
.unwrap()
.add_bit_commitment_script(builder);
builder
.push_opcode(OP_NOT)
.push_opcode(OP_FROMALTSTACK)
.push_opcode(OP_EQUALVERIFY)
.into_script()
}
}

Expand Down Expand Up @@ -57,8 +81,31 @@ impl GateTrait for AndGate {
out.selector = Some(w);
}

fn create_challenge_script(&self) -> String {
"AndGate".to_string()
fn create_response_script(&self, lock_hash: [u8; 32]) -> ScriptBuf {
let builder = Builder::new()
.push_opcode(OP_SHA256)
.push_slice(lock_hash)
.push_opcode(OP_EQUALVERIFY);
let builder = self.output_wires[0]
.try_borrow()
.unwrap()
.add_bit_commitment_script(builder)
.push_opcode(OP_TOALTSTACK);
let builder = self.input_wires[0]
.try_borrow()
.unwrap()
.add_bit_commitment_script(builder)
.push_opcode(OP_TOALTSTACK);
let builder = self.input_wires[1]
.try_borrow()
.unwrap()
.add_bit_commitment_script(builder);
builder
.push_opcode(OP_FROMALTSTACK)
.push_opcode(OP_AND)
.push_opcode(OP_FROMALTSTACK)
.push_opcode(OP_EQUALVERIFY)
.into_script()
}
}

Expand Down Expand Up @@ -87,12 +134,131 @@ impl GateTrait for XorGate {
out.selector = Some(w);
}

fn create_challenge_script(&self) -> String {
"XorGate".to_string()
fn create_response_script(&self, lock_hash: [u8; 32]) -> ScriptBuf {
let builder = Builder::new()
.push_opcode(OP_SHA256)
.push_slice(lock_hash)
.push_opcode(OP_EQUALVERIFY);
let builder = self.output_wires[0]
.try_borrow()
.unwrap()
.add_bit_commitment_script(builder)
.push_opcode(OP_TOALTSTACK);
let builder = self.input_wires[0]
.try_borrow()
.unwrap()
.add_bit_commitment_script(builder)
.push_opcode(OP_TOALTSTACK);
let builder = self.input_wires[1]
.try_borrow()
.unwrap()
.add_bit_commitment_script(builder);
builder
.push_opcode(OP_FROMALTSTACK)
.push_opcode(OP_XOR)
.push_opcode(OP_FROMALTSTACK)
.push_opcode(OP_EQUALVERIFY)
.into_script()
}
}

pub struct OrGate {
pub input_wires: Vec<Rc<RefCell<Wire>>>,
pub output_wires: Vec<Rc<RefCell<Wire>>>,
#[cfg(test)]
mod tests {
use super::*;
use bitcoin::hashes::sha256;
use bitcoin::hashes::Hash;
use bitcoin::TapLeafHash;
use bitcoin::Transaction;
use bitcoin_scriptexec::*;
use rand::Rng;

#[test]
fn test_not_gate() {
let input_wire_0 = Wire::new(0);
// get the input wire preimages, it should not be option, but a vector of preimages
let input_wire_0_preimages = input_wire_0.preimages.unwrap();
let output_wire_0 = Wire::new(1);
let output_wire_0_preimages = output_wire_0.preimages.unwrap();

let not_gate = NotGate::new(
vec![Rc::new(RefCell::new(input_wire_0))],
vec![Rc::new(RefCell::new(output_wire_0))],
);

let mut rng = rand::thread_rng();

let lock_preimage: [u8; 32] = rng.gen();

let lock_hash = sha256::Hash::hash(&lock_preimage).to_byte_array();

let script = not_gate.create_response_script(lock_hash);

let solution_01_preimages = vec![
input_wire_0_preimages[0].clone().to_vec(),
output_wire_0_preimages[1].clone().to_vec(),
lock_preimage.to_vec(),
];
let mut exec_01 = Exec::new(
ExecCtx::Tapscript,
Options::default(),
TxTemplate {
tx: Transaction {
version: bitcoin::transaction::Version::TWO,
lock_time: bitcoin::locktime::absolute::LockTime::ZERO,
input: vec![],
output: vec![],
},
prevouts: vec![],
input_idx: 0,
taproot_annex_scriptleaf: Some((TapLeafHash::all_zeros(), None)),
},
script.clone(),
solution_01_preimages,
)
.expect("error creating exec");

loop {
if exec_01.exec_next().is_err() {
println!("error: {:?}", exec_01.exec_next().err());
break;
}
}

let res = exec_01.result().unwrap().clone();
println!("res: {:?}", res);

assert_eq!(res.error, None);

let solution_01_preimages = vec![
input_wire_0_preimages[0].clone().to_vec(),
output_wire_0_preimages[0].clone().to_vec(),
lock_preimage.to_vec(),
];
let mut exec_00 = Exec::new(
ExecCtx::Tapscript,
Options::default(),
TxTemplate {
tx: Transaction {
version: bitcoin::transaction::Version::TWO,
lock_time: bitcoin::locktime::absolute::LockTime::ZERO,
input: vec![],
output: vec![],
},
prevouts: vec![],
input_idx: 0,
taproot_annex_scriptleaf: Some((TapLeafHash::all_zeros(), None)),
},
script,
solution_01_preimages,
)
.expect("error creating exec");

let has_error = loop {
if exec_00.exec_next().is_err() {
println!("error: {:?}", exec_00.exec_next().err());
break true;
}
};
assert!(has_error);
}
}
109 changes: 108 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,110 @@
use bitcoin::absolute::{Height, LockTime};

use bitcoin::consensus::encode::serialize_hex;
use bitcoin::consensus::Decodable;
use bitcoin::hash_types::Txid;
use bitcoin::sighash::SighashCache;
use bitcoin::{Amount, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Witness};
use bitvmrs::prover::Prover;
use bitvmrs::utils::{bool_array_to_number, number_to_bool_array};
use bitvmrs::verifier::Verifier;
use bitvmrs::{circuit::Circuit, traits::circuit::CircuitTrait};

use std::borrow::BorrowMut;
use std::io::{self, Write}; // Import necessary modules
pub fn parse_hex_transaction(
tx_hex: &str,
) -> Result<Transaction, bitcoin::consensus::encode::Error> {
if let Ok(reader) = hex::decode(tx_hex) {
Transaction::consensus_decode(&mut &reader[..])
} else {
Err(bitcoin::consensus::encode::Error::ParseFailed(
"Could not decode hex",
))
}
}
fn main() {
println!("Hello, world!");
let mut circuit = Circuit::from_bristol("bristol/add.txt");
let a1 = 633;
let a2 = 15;
let b1 = number_to_bool_array(a1, 64);
let b2 = number_to_bool_array(a2, 64);

let o = circuit.evaluate(vec![b1, b2]);
let output = bool_array_to_number(o.get(0).unwrap().to_vec());
println!("output : {:?}", output);
assert_eq!(output, a1 + a2);

let paul = Prover::new();
let vicky = Verifier::new();
let amt = 10_000;

println!("Send {} satoshis to Public Key: {}", amt, paul.address);

let mut txid_str = String::new();
let mut vout_str = String::new();

print!("Enter txid: ");
io::stdout().flush().unwrap(); // Make sure 'Enter txid' is printed before input
io::stdin()
.read_line(&mut txid_str)
.expect("Failed to read txid");
let txid_str = txid_str.trim(); // Trim newline/whitespace
let txid: Txid = txid_str.parse().expect("Invalid txid format");

// Read vout
print!("Enter vout: ");
io::stdout().flush().unwrap(); // Make sure 'Enter vout' is printed before input
io::stdin()
.read_line(&mut vout_str)
.expect("Failed to read vout");
let vout: u32 = vout_str.trim().parse().expect("Invalid vout format");

// let txid: Txid = "9aa3e28ba1742b0df567df6998c00ef78136be16dd107f422f8af9b0f56bd68c".parse().unwrap();
// let vout: u32 = "0".parse().unwrap();

let mut tx = Transaction {
version: bitcoin::transaction::Version::TWO,
lock_time: LockTime::from(Height::MIN),
input: vec![TxIn {
previous_output: OutPoint { txid, vout },
script_sig: ScriptBuf::new(),
sequence: bitcoin::transaction::Sequence::ENABLE_RBF_NO_LOCKTIME,
witness: Witness::new(),
}],
output: vec![TxOut {
script_pubkey: circuit
.generate_anti_contradiction_tree(paul.public_key, vicky.public_key)
.script_pubkey(),
value: Amount::from_sat(amt - 500),
}],
};

let prevouts = vec![TxOut {
script_pubkey: paul.address.script_pubkey(),
value: Amount::from_sat(amt),
}];

println!("prevout: {:?}", prevouts);
let mut sighash_cache = SighashCache::new(tx.borrow_mut());
// TODO: add support for signing with a keypair
let sig_hash = sighash_cache
.taproot_key_spend_signature_hash(
0,
&bitcoin::sighash::Prevouts::All(&prevouts),
bitcoin::sighash::TapSighashType::Default,
)
.unwrap();

// Witness::from_slice(sigHash)
let sig = paul.sign(sig_hash);
let witness = sighash_cache.witness_mut(0).unwrap();
witness.push(sig.as_ref());

println!("sigHash : {:?}", sig_hash);
println!("tx : {:?}", tx);
println!("txid : {:?}", tx.txid());
println!("txid : {:?}", serialize_hex(&tx));
// let mut txid_str: [u8];
// tx.consensus_encode().unwrap();
}
Loading

0 comments on commit 0cfd98d

Please sign in to comment.