Skip to content

Commit

Permalink
Merge pull request #24 from chainwayxyz/ekrem/presign
Browse files Browse the repository at this point in the history
Ekrem/presign
  • Loading branch information
Hakkush-07 authored Dec 8, 2023
2 parents ae29bb6 + be1fee5 commit 6d9ee0b
Show file tree
Hide file tree
Showing 11 changed files with 231 additions and 66 deletions.
14 changes: 14 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ bitcoin = {version = "0.31.0", features = ["rand"]}
bitcoincore-rpc = {version = "0.18.0" }
hex = "0.4.3"
rand = "0.8.5"
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = "0.15"
url = "2.2.0"
futures-util = "0.3"
serde = "1.0.193"
serde_json = "1.0.108"


[dev-dependencies]
bitcoin-scriptexec = { git = "https://github.com/ekrembal/rust-bitcoin-scriptexec" }
Expand All @@ -18,3 +25,10 @@ bitcoin-scriptexec = { git = "https://github.com/ekrembal/rust-bitcoin-scriptexe
# rpc = ["bitcoincore-rpc"]


[[bin]]
name = "prover"
path = "src/prover.rs"

[[bin]]
name = "verifier"
path = "src/verifier.rs"
17 changes: 15 additions & 2 deletions src/actor.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use bitcoin::hashes::sha256;
use bitcoin::opcodes::all::*;
use bitcoin::TapNodeHash;
use bitcoin::{
hashes::Hash,
script::Builder,
Expand Down Expand Up @@ -53,20 +54,32 @@ impl Actor {
.into_script()
}

pub fn sign(&self, sighash: TapSighash) -> Signature {
pub fn sign_with_tweak(
&self,
sighash: TapSighash,
merkle_root: Option<TapNodeHash>,
) -> Signature {
self.secp.sign_schnorr_with_rng(
&Message::from_digest_slice(sighash.as_byte_array()).expect("should be hash"),
&self
.keypair
.add_xonly_tweak(
&self.secp,
&TapTweakHash::from_key_and_tweak(self.public_key, None).to_scalar(),
&TapTweakHash::from_key_and_tweak(self.public_key, merkle_root).to_scalar(),
)
.unwrap(),
&mut rand::thread_rng(),
)
}

pub fn sign(&self, sighash: TapSighash) -> Signature {
self.secp.sign_schnorr_with_rng(
&Message::from_digest_slice(sighash.as_byte_array()).expect("should be hash"),
&self.keypair,
&mut rand::thread_rng(),
)
}

pub fn generate_challenge_hashes(&mut self, num_gates: usize) -> Vec<[u8; 32]> {
let mut challenge_hashes = Vec::new();
let mut rng = rand::thread_rng();
Expand Down
10 changes: 10 additions & 0 deletions src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ impl CircuitTrait for Circuit {
output
}

fn get_wire_hashes(&self) -> Vec<[[u8; 32]; 2]> {
self.wires
.iter()
.map(|wire_rcref| {
let wire = wire_rcref.try_borrow_mut().unwrap();
wire.get_hash_pair()
})
.collect::<Vec<[[u8; 32]; 2]>>()
}

fn from_bristol(file: &str) -> Self {
let mut nog: usize = 0; // number of gates
let mut now: usize = 0; // number of wires
Expand Down
35 changes: 35 additions & 0 deletions src/communication.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// communication.rs
use futures_util::{SinkExt, StreamExt};
use serde::{Deserialize, Serialize};
use std::error::Error;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_tungstenite::tungstenite::protocol::Message;
use tokio_tungstenite::WebSocketStream;

pub async fn send_message<T, M>(
ws_stream: &mut WebSocketStream<T>,
message: &M,
) -> Result<(), Box<dyn Error>>
where
T: AsyncRead + AsyncWrite + Unpin,
M: Serialize,
{
let serialized = serde_json::to_string(message)?;
ws_stream.send(Message::Text(serialized)).await?;
Ok(())
}

pub async fn receive_message<T, M>(ws_stream: &mut WebSocketStream<T>) -> Result<M, Box<dyn Error>>
where
T: AsyncRead + AsyncWrite + Unpin,
M: for<'de> Deserialize<'de>,
{
if let Some(msg) = ws_stream.next().await {
let msg = msg?;
if let Message::Text(text) = msg {
let deserialized: M = serde_json::from_str(&text)?;
return Ok(deserialized);
}
}
Err("Failed to receive message".into())
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod actor;
pub mod circuit;
pub mod communication;
pub mod gates;
pub mod traits;
pub mod utils;
Expand Down
128 changes: 68 additions & 60 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use bitcoin::absolute::{Height, LockTime};
use bitcoin::consensus::encode::serialize_hex;
use bitcoin::consensus::Decodable;
use bitcoin::hash_types::Txid;
use bitcoin::secp256k1::{All, Secp256k1};

use bitcoin::secp256k1::Secp256k1;
use bitcoin::sighash::SighashCache;
use bitcoin::taproot::{LeafVersion, TaprootSpendInfo};
use bitcoin::{Amount, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Witness};
use bitcoin::taproot::LeafVersion;
use bitcoin::{Amount, OutPoint, ScriptBuf, TapLeafHash, Transaction, TxIn, TxOut, Witness};

use bitcoincore_rpc::{Auth, Client, RpcApi};
use bitvm::actor::Actor;
use bitvm::traits::wire::WireTrait;

use bitvm::wire::Wire;
use bitvm::{circuit::Circuit, traits::circuit::CircuitTrait};

use std::borrow::BorrowMut;
Expand All @@ -28,51 +27,6 @@ pub fn parse_hex_transaction(
}
}

pub fn use_equivocation(
_secp: Secp256k1<All>,
txid: Txid,
verifier: &Actor,
wire: Wire,
info: TaprootSpendInfo,
) {
let vout: u32 = 0;

let script = wire.generate_anti_contradiction_script(verifier.public_key);

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: verifier.address.script_pubkey(),
value: Amount::from_sat(9000),
}],
};

let mut sighash_cache = SighashCache::new(tx.borrow_mut());

let control_block = info
.control_block(&(script.clone(), LeafVersion::TapScript))
.expect("Cannot create control block");

let witness = sighash_cache.witness_mut(0).unwrap();
witness.push(wire.preimages.unwrap()[1]);
witness.push(wire.preimages.unwrap()[0]);
witness.push(script);
witness.push(&control_block.serialize());

// println!("sigHash : {:?}", sig_hash);
// println!("tx : {:?}", tx);
println!("equivocation");
println!("txid : {:?}", tx.txid());
println!("txid : {:?}", serialize_hex(&tx));
}

fn main() {
// if rpc feature is enabled, use the following code to connect to a bitcoin node
let rpc = Client::new(
Expand Down Expand Up @@ -117,7 +71,8 @@ fn main() {

let challenge_hashes = vicky.generate_challenge_hashes(circuit.num_gates());

let (address, info) = circuit.generate_challenge_tree(&secp, &paul, &vicky, challenge_hashes);
let (address, kickoff_taproot_info) =
circuit.generate_challenge_tree(&secp, &paul, &vicky, challenge_hashes);

let mut tx = Transaction {
version: bitcoin::transaction::Version::TWO,
Expand Down Expand Up @@ -154,25 +109,78 @@ fn main() {
.unwrap();

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

println!("txid : {:?}", serialize_hex(&tx));

let initial_tx = rpc
let kickoff_tx = rpc
.send_raw_transaction(&tx)
.unwrap_or_else(|e| panic!("Failed to send raw transaction: {}", e));
println!("initial tx = {:?}", initial_tx);
println!("initial kickoff tx = {:?}", kickoff_tx);

// let mut txid_str: [u8];
// tx.consensus_encode().unwrap();

let use_eq = 1;
let wire_rcref = &circuit.wires[0];
let wire = wire_rcref.try_borrow_mut().unwrap();

if use_eq > 0 {
let wire_rcref = &circuit.wires[0];
let wire = wire_rcref.try_borrow_mut().unwrap();
use_equivocation(secp, tx.txid(), &vicky, wire.to_owned(), info);
}
let vout: u32 = 0;

let script = wire.generate_anti_contradiction_script(vicky.public_key);

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

let mut sighash_cache = SighashCache::new(tx.borrow_mut());

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

let sig_hash = sighash_cache
.taproot_script_spend_signature_hash(
vout as usize,
&bitcoin::sighash::Prevouts::All(&prevouts),
TapLeafHash::from_script(&script, LeafVersion::TapScript),
bitcoin::sighash::TapSighashType::Default,
)
.unwrap();
let sig = vicky.sign(sig_hash);

let control_block = kickoff_taproot_info
.control_block(&(script.clone(), LeafVersion::TapScript))
.expect("Cannot create control block");

let witness = sighash_cache.witness_mut(0).unwrap();
witness.push(sig.as_ref());
witness.push(wire.preimages.unwrap()[1]);
witness.push(wire.preimages.unwrap()[0]);
witness.push(script);
witness.push(&control_block.serialize());

println!("equivocation");
println!("txid : {:?}", tx.txid());
println!("txid : {:?}", serialize_hex(&tx));
let eqv_tx = rpc
.send_raw_transaction(&tx)
.unwrap_or_else(|e| panic!("Failed to send raw transaction: {}", e));
println!("eqv tx = {:?}", eqv_tx);
}
41 changes: 41 additions & 0 deletions src/prover.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use bitcoin::XOnlyPublicKey;

// prover.rs
use bitvm::{
circuit::Circuit,
communication::{receive_message, send_message},
traits::circuit::CircuitTrait,
};

use tokio_tungstenite::connect_async;

// #[derive(Serialize, Deserialize, Debug)]
// struct WireHash {
// zero: [u8; 32],
// one: [u8; 32],
// }
// #[derive(Serialize, Deserialize, Debug)]
// struct WireHashes {
// wire_hashes: Vec<WireHash>,
// }

#[tokio::main]
async fn main() {
let url = "ws://127.0.0.1:9000";
let (mut ws_stream, _) = connect_async(url).await.expect("Failed to connect");
println!("WebSocket handshake has been successfully completed");

send_message(&mut ws_stream, &"bristol/add.txt".to_string())
.await
.unwrap();

let verifier_publickey_str: String = receive_message(&mut ws_stream).await.unwrap();
println!("Verifier public key: {}", verifier_publickey_str);
let verifier_publickey: XOnlyPublicKey = verifier_publickey_str.parse().unwrap();
println!("Verifier public key: {}", verifier_publickey);

let circuit = Circuit::from_bristol("bristol/add.txt");
let wire_hashes: Vec<[[u8; 32]; 2]> = circuit.get_wire_hashes();

send_message(&mut ws_stream, &wire_hashes).await.unwrap();
}
2 changes: 2 additions & 0 deletions src/traits/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ pub trait CircuitTrait {

fn evaluate(&mut self, inputs: Vec<Vec<bool>>) -> Vec<Vec<bool>>;

fn get_wire_hashes(&self) -> Vec<[[u8; 32]; 2]>;

fn from_bristol(file: &str) -> Self;

fn generate_challenge_tree(
Expand Down
1 change: 1 addition & 0 deletions src/traits/wire.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use bitcoin::{script::Builder, ScriptBuf, XOnlyPublicKey};

pub trait WireTrait {
fn get_hash_pair(&self) -> [[u8; 32]; 2];
fn generate_anti_contradiction_script(&self, verifier_pk: XOnlyPublicKey) -> ScriptBuf;
fn add_bit_commitment_script(&self, builder: Builder) -> Builder;
}
37 changes: 37 additions & 0 deletions src/verifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// verifier.rs
use bitvm::{
actor::Actor,
communication::{receive_message, send_message},
};
use tokio::net::{TcpListener, TcpStream};
use tokio_tungstenite::accept_async;

#[tokio::main]
async fn main() {
let listener = TcpListener::bind("127.0.0.1:9000").await.unwrap();
println!("Listening on: 127.0.0.1:9000");

while let Ok((stream, _)) = listener.accept().await {
tokio::spawn(handle_connection(stream));
}
}

async fn handle_connection(stream: TcpStream) {
let mut ws_stream = accept_async(stream)
.await
.expect("Error during the websocket handshake occurred");

let message: String = receive_message(&mut ws_stream).await.unwrap();
println!("Received: {}", message);

let verifier = Actor::new();

// send our public key to the prover
send_message(&mut ws_stream, &verifier.public_key.to_string())
.await
.unwrap();

let wire_hashes: Vec<[[u8; 32]; 2]> = receive_message(&mut ws_stream).await.unwrap();

println!("Wire hashes: {:?}", wire_hashes);
}
Loading

0 comments on commit 6d9ee0b

Please sign in to comment.