Skip to content
Open

GC #13

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
10 changes: 10 additions & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion goat/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ strum.workspace = true
strum_macros.workspace = true
bitcoin-scriptexec.workspace = true
serde.workspace = true
serde-big-array.workspace = true
num-traits.workspace = true
sha2.workspace = true
tokio.workspace = true
Expand Down Expand Up @@ -48,4 +49,3 @@ lto = true
[profile.profiling]
inherits = "release"
debug = true

253 changes: 253 additions & 0 deletions goat/src/assert_scripts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
use crate::wots::{Wots, Wots64, Wots96};
use bitvm::{signatures::WinternitzSecret, treepp::*};
use serde::{Deserialize, Serialize};

pub const INPUT_WIRE_NUM: usize = 512;
pub const PROVER_SIG_LEN: usize = 2 * Wots64::TOTAL_DIGIT_LEN as usize;
pub type OperatorAssertSecretKey = WinternitzSecret;
pub type OperatorAssertPublicKey = <Wots64 as Wots>::PublicKey;

pub type Label = Vec<u8>;
pub type LabelHash = [u8; 20];
#[derive(Serialize, Deserialize, Eq, PartialEq, Clone)]
pub struct WireHash {
pub true_label_hash: LabelHash,
pub false_label_hash: LabelHash,
}

pub fn label_hash(label: &Label) -> LabelHash {
use bitcoin::hashes::{hash160, Hash};
hash160::Hash::hash(label).to_byte_array()
}

fn label_hash_script() -> Script {
script! {
OP_HASH160
}
}

pub fn wrongly_challenged_script(hashlock: &LabelHash) -> Script {
script! {
{ label_hash_script() }
{ hashlock.to_vec() }
OP_EQUALVERIFY
OP_TRUE
}
}

pub fn verify_prover_assert_script_512_wire(
prover_wots_pubkey: &<Wots64 as Wots>::PublicKey,
) -> Script {
script! {
{ Wots64::checksig_verify_and_clear_stack(prover_wots_pubkey) }
OP_TRUE
}
}

pub fn verify_verifier_assert_script_512_wire(
prover_wots_pubkey: &<Wots64 as Wots>::PublicKey,
label_hashes: &[WireHash; 512],
) -> Script {
script! {
for byte_hashes in label_hashes.chunks(8).rev() {
for wire_hashes in byte_hashes.chunks(4).rev() {
{ 0 }
for (bit_index, wire_hash) in wire_hashes.iter().enumerate().rev() {
OP_SWAP
OP_DUP
{ label_hash_script() }
{ wire_hash.true_label_hash.to_vec() }
OP_EQUAL
OP_IF
OP_DROP
{ 1 << bit_index }
OP_ADD
OP_ELSE
{ label_hash_script() }
{ wire_hash.false_label_hash.to_vec() }
OP_EQUALVERIFY
OP_ENDIF
}
OP_TOALTSTACK
}
}
{ Wots64::checksig_verify(prover_wots_pubkey) }
for _ in 0..(Wots64::MSG_BYTE_LEN * 2) {
OP_FROMALTSTACK
OP_EQUALVERIFY
}
OP_TRUE
}
}

pub fn verify_prover_assert_script_768_wire(
prover_wots_pubkey: &<Wots96 as Wots>::PublicKey,
) -> Script {
script! {
{ Wots96::checksig_verify_and_clear_stack(prover_wots_pubkey) }
OP_TRUE
}
}

pub fn verify_verifier_assert_script_768_wire(
prover_wots_pubkey: &<Wots96 as Wots>::PublicKey,
label_hashes: [WireHash; 768],
) -> Script {
script! {
for byte_hashes in label_hashes.chunks(8).rev() {
{ 0 }
for (bit_index, wire_hash) in byte_hashes.iter().enumerate().rev() {
OP_SWAP
OP_DUP
{ label_hash_script() }
{ wire_hash.true_label_hash.to_vec() }
OP_EQUAL
OP_IF
OP_DROP
{ 1 << bit_index }
OP_ADD
OP_ELSE
{ label_hash_script() }
{ wire_hash.false_label_hash.to_vec() }
OP_EQUALVERIFY
OP_ENDIF
}
OP_TOALTSTACK
}
{ Wots96::checksig_verify(prover_wots_pubkey) }
for _ in 0..Wots96::MSG_BYTE_LEN {
OP_FROMALTSTACK
OP_EQUALVERIFY
}
OP_TRUE
}
}

#[cfg(test)]
mod tests {
use super::*;
use bitvm::execute_script;
use rand::RngCore;

#[test]
fn test_verify_verifier_assert_script_512_wire() {
let secret = Wots64::generate_secret_key();
let public_key = Wots64::generate_public_key(&secret);

let true_labels: Vec<Vec<u8>> = (0..512)
.map(|i| {
let mut label = vec![0x54; 20];
label[0] = (i & 0xff) as u8;
label[1] = (i >> 8) as u8;
label
})
.collect();
let false_labels: Vec<Vec<u8>> = (0..512)
.map(|i| {
let mut label = vec![0x46; 20];
label[0] = (i & 0xff) as u8;
label[1] = (i >> 8) as u8;
label
})
.collect();

let mut msg: [u8; 64] = [0; 64];
rand::thread_rng().fill_bytes(&mut msg);

let mut bits = [false; 512];
for i in 0..512 {
bits[i] = (msg[i / 8] >> (i % 8)) & 1 == 1;
}

let label_hashes = std::array::from_fn(|i| WireHash {
true_label_hash: label_hash(&true_labels[i]),
false_label_hash: label_hash(&false_labels[i]),
});
let selected_labels: Vec<Vec<u8>> = (0..512)
.map(|i| {
if bits[i] {
true_labels[i].clone()
} else {
false_labels[i].clone()
}
})
.collect();

let s = script! {
{ Wots64::sign_to_raw_witness(&secret, &msg) }
for wire_index in 0..512 {
{ selected_labels[wire_index].clone() }
}
{ verify_verifier_assert_script_512_wire(&public_key, &label_hashes) }
};
println!("verifier assert full script size: {}", s.len());
let result = execute_script(s);
println!(
"verifier assert max stack item size: {:?}",
result.stats.max_nb_stack_items
);
assert!(result.success);
assert_eq!(result.final_stack.len(), 1);
}

#[test]
fn test_verify_verifier_assert_script_768_wire() {
let secret = Wots96::generate_secret_key();
let public_key = Wots96::generate_public_key(&secret);

let true_labels: Vec<Vec<u8>> = (0..768)
.map(|i| {
let mut label = vec![0x54; 20];
label[0] = (i & 0xff) as u8;
label[1] = (i >> 8) as u8;
label
})
.collect();
let false_labels: Vec<Vec<u8>> = (0..768)
.map(|i| {
let mut label = vec![0x46; 20];
label[0] = (i & 0xff) as u8;
label[1] = (i >> 8) as u8;
label
})
.collect();

let mut msg: [u8; 96] = [0; 96];
rand::thread_rng().fill_bytes(&mut msg);

let mut bits = [false; 768];
for i in 0..768 {
bits[i] = (msg[i / 8] >> (i % 8)) & 1 == 1;
}

let label_hashes = std::array::from_fn(|i| WireHash {
true_label_hash: label_hash(&true_labels[i]),
false_label_hash: label_hash(&false_labels[i]),
});
let selected_labels: Vec<Vec<u8>> = (0..768)
.map(|i| {
if bits[i] {
true_labels[i].clone()
} else {
false_labels[i].clone()
}
})
.collect();

let s = script! {
{ Wots96::sign_to_raw_witness(&secret, &msg) }
for wire_index in 0..768 {
{ selected_labels[wire_index].clone() }
}
{ verify_verifier_assert_script_768_wire(&public_key, label_hashes) }
};
println!("verifier assert full script size: {}", s.len());
let result = execute_script(s);
println!(
"verifier assert max stack item size: {:?}",
result.stats.max_nb_stack_items
);
assert!(result.success);
assert_eq!(result.final_stack.len(), 1);
}
}
Loading
Loading