mod common;
use common::{HASH, parse};
use std::sync::atomic::{AtomicUsize, Ordering};
use zheng::envelope::{Envelope, SuccinctStatement};
use zheng::execution::succinct::{self, TensorRs, TensorRsParams, Whir, WhirParams};
fn scan(envelope: &Envelope) -> (usize, usize) {
let bytes = envelope.to_bytes();
assert!(Envelope::from_bytes(&bytes).unwrap().verify(None).is_ok());
let accepted = AtomicUsize::new(0);
let total = bytes.len() * 8;
let threads = std::thread::available_parallelism().map_or(4, |n| n.get());
std::thread::scope(|s| {
for t in 0..threads {
let (bytes, accepted) = (&bytes, &accepted);
s.spawn(move || {
let mut bad = bytes.clone();
for flip in (t..total).step_by(threads) {
let (i, bit) = (flip / 8, 1u8 << (flip % 8));
bad[i] ^= bit;
let ok = Envelope::from_bytes(&bad).is_ok_and(|e| e.verify(None).is_ok());
if ok {
eprintln!("accepted flip: byte {i} bit {}", flip % 8);
accepted.fetch_add(1, Ordering::Relaxed);
}
bad[i] ^= bit;
}
});
}
});
(total, accepted.into_inner())
}
#[test]
fn every_bit_flip_of_a_whir_hash_proof_is_rejected() {
let (statement, proof) =
succinct::prove::<Whir>(&WhirParams::default(), &parse(HASH), &[7], 1_000_000).unwrap();
let e = Envelope::Succinct {
statement: SuccinctStatement::Execution(statement),
proof: proof.into(),
};
let (flips, accepted) = scan(&e);
println!(
"WHIR hash.tri: {} bytes, {flips} flips, {accepted} accepted",
e.to_bytes().len()
);
assert_eq!(accepted, 0);
}
#[test]
#[ignore]
fn every_bit_flip_of_a_tensor_hash_proof_is_rejected() {
let (statement, proof) =
succinct::prove::<TensorRs>(&TensorRsParams::default(), &parse(HASH), &[7], 1_000_000)
.unwrap();
let e = Envelope::Succinct {
statement: SuccinctStatement::Execution(statement),
proof: proof.into(),
};
let (flips, accepted) = scan(&e);
println!(
"TensorRs hash.tri: {} bytes, {flips} flips, {accepted} accepted",
e.to_bytes().len()
);
assert_eq!(accepted, 0);
}
#[test]
fn every_bit_flip_of_a_shipped_device_proof_is_rejected() {
let (statement, proof) = succinct::prove_default(&parse(HASH), &[7], 1_000_000).unwrap();
let e = Envelope::Succinct {
statement: SuccinctStatement::Execution(statement),
proof,
};
let (flips, accepted) = scan(&e);
println!(
"device_params hash.tri: {} bytes, {flips} flips, {accepted} accepted",
e.to_bytes().len()
);
assert_eq!(accepted, 0);
}
#[test]
#[ignore]
fn every_bit_flip_of_a_folding_5_proof_is_rejected() {
for pow_bits in [16, 22] {
let p = WhirParams {
log_inv_rate: 6,
folding_factor: 5,
pow_bits,
..WhirParams::default()
};
let (statement, proof) =
succinct::prove::<Whir>(&p, &parse(HASH), &[7], 1_000_000).unwrap();
let e = Envelope::Succinct {
statement: SuccinctStatement::Execution(statement),
proof: proof.into(),
};
let (flips, accepted) = scan(&e);
println!(
"WHIR 1/64 k=5 pow={pow_bits} hash.tri: {} bytes, {flips} flips, {accepted} accepted",
e.to_bytes().len()
);
assert_eq!(accepted, 0);
}
}
#[test]
#[ignore]
fn every_bit_flip_of_a_node_merkle_proof_is_rejected() {
let levels = 4;
let root = zheng::execution::node::digest_noun(common::node_merkle_root(levels, 5));
let program = common::node_merkle_program(levels, Some(&root));
let (statement, proof) = succinct::prove_default(&program, &[5], 1 << 40).unwrap();
let e = Envelope::Succinct {
statement: SuccinctStatement::Execution(statement),
proof,
};
let (flips, accepted) = scan(&e);
println!(
"node-merkle-4: {} bytes, {flips} flips, {accepted} accepted",
e.to_bytes().len()
);
assert_eq!(accepted, 0);
}