use crate::{
bridge_circuit::structs::{WorkOnlyCircuitInput, WorkOnlyCircuitOutput},
common::{
constants::{
MAINNET_HEADER_CHAIN_METHOD_ID, REGTEST_HEADER_CHAIN_METHOD_ID,
SIGNET_HEADER_CHAIN_METHOD_ID, TESTNET4_HEADER_CHAIN_METHOD_ID,
},
zkvm::ZkvmGuest,
},
};
use crypto_bigint::{Encoding, U128, U256};
use risc0_zkvm::guest::env;
const HEADER_CHAIN_METHOD_ID: [u32; 8] = {
match option_env!("BITCOIN_NETWORK") {
Some(network) if matches!(network.as_bytes(), b"mainnet") => MAINNET_HEADER_CHAIN_METHOD_ID,
Some(network) if matches!(network.as_bytes(), b"testnet4") => {
TESTNET4_HEADER_CHAIN_METHOD_ID
}
Some(network) if matches!(network.as_bytes(), b"signet") => SIGNET_HEADER_CHAIN_METHOD_ID,
Some(network) if matches!(network.as_bytes(), b"regtest") => REGTEST_HEADER_CHAIN_METHOD_ID,
None => MAINNET_HEADER_CHAIN_METHOD_ID,
_ => panic!("Invalid network type"),
}
};
pub fn work_only_circuit(guest: &impl ZkvmGuest) {
let input: WorkOnlyCircuitInput = guest.read_from_host();
assert_eq!(
HEADER_CHAIN_METHOD_ID, input.header_chain_circuit_output.method_id,
"Invalid header chain method ID"
);
env::verify(
input.header_chain_circuit_output.method_id,
&borsh::to_vec(&input.header_chain_circuit_output).unwrap(),
)
.unwrap();
let total_work_u256: U256 =
U256::from_be_bytes(input.header_chain_circuit_output.chain_state.total_work);
let words = work_conversion(total_work_u256);
guest.commit(&WorkOnlyCircuitOutput {
work_u128: words,
genesis_state_hash: input.header_chain_circuit_output.genesis_state_hash,
});
}
fn work_conversion(work: U256) -> [u8; 16] {
let (_, work): (U128, U128) = work.into();
work.to_be_bytes()
}
#[cfg(test)]
mod tests {
use crypto_bigint::{Encoding, U256};
use crate::work_only::work_conversion;
#[test]
fn test_work_conversion_one() {
let u128_one_words = work_conversion(U256::ONE);
assert_eq!(
u128_one_words,
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
);
let u128_one_borsh =
borsh::to_vec(&u128_one_words).expect("Serialization to vec is infallible");
assert_eq!(u128_one_borsh.len(), 16);
assert_eq!(
u128_one_borsh,
vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
);
let u128_one = borsh::from_slice::<[u8; 16]>(&u128_one_borsh)
.expect("Deserialization from slice is infallible");
assert_eq!(u128_one, u128_one_words);
}
#[test]
fn test_work_conversion_real() {
let work_bytes = U256::from_be_bytes([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
1, 0, 1,
]);
let work_words = work_conversion(work_bytes);
assert_eq!(work_words, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]);
let u128_one_borsh =
borsh::to_vec(&work_words).expect("Serialization to vec is infallible");
assert_eq!(u128_one_borsh.len(), 16);
assert_eq!(
u128_one_borsh,
vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]
);
let u128_one = borsh::from_slice::<[u8; 16]>(&u128_one_borsh)
.expect("Deserialization from slice is infallible");
assert_eq!(u128_one, work_words);
}
}