use sha2::{Digest, Sha256}; use std::{env, fs::File, io::Write, path::Path}; const TARGET_FILE: &str = "context.rs"; const MAX_MERKLE_TREE_DEPTH: usize = 64; const BYTES_PER_CHUNK: usize = 32; fn hash_nodes(hasher: &mut Sha256, a: &[u8], b: &[u8], out: &mut [u8]) { hasher.update(a); hasher.update(b); out.copy_from_slice(&hasher.finalize_reset()); } fn compute_zero_hashes() -> [u8; MAX_MERKLE_TREE_DEPTH * BYTES_PER_CHUNK] { let mut hasher = Sha256::new(); let mut buffer = [0u8; MAX_MERKLE_TREE_DEPTH * BYTES_PER_CHUNK]; for i in 0..MAX_MERKLE_TREE_DEPTH - 1 { let focus_range = i * BYTES_PER_CHUNK..(i + 2) * BYTES_PER_CHUNK; let focus = &mut buffer[focus_range]; let (source, target) = focus.split_at_mut(BYTES_PER_CHUNK); hash_nodes(&mut hasher, source, source, target); } buffer } // This function derives a set of bytes corresponding to "zero hashes" at build-time // in lieu of needing to declare any sort of runtime static memory or similar technique. // If any of the hashing code changes significantly for the SSZ accumulator scheme, // this code will need to be updated as well. fn generate() -> std::io::Result<()> { let out_dir = env::var_os("OUT_DIR").unwrap(); let dest_path = Path::new(&out_dir).join(TARGET_FILE); let mut f = File::create(dest_path)?; let data = compute_zero_hashes(); write!( f, " // Generated by build.rs static CONTEXT: Context = Context {{ zero_hashes: {data:?}, }};", ) .unwrap(); Ok(()) } fn main() -> std::io::Result<()> { generate()?; println!("cargo:rerun-if-changed=build.rs"); Ok(()) }