diff --git a/zebra-consensus/src/primitives/groth16.rs b/zebra-consensus/src/primitives/groth16.rs index 533e2e5d637..9210707f4f8 100644 --- a/zebra-consensus/src/primitives/groth16.rs +++ b/zebra-consensus/src/primitives/groth16.rs @@ -18,16 +18,16 @@ use once_cell::sync::Lazy; use rand::thread_rng; use tokio::sync::broadcast::{channel, error::RecvError, Sender}; use tower::{util::ServiceFn, Service}; + use tower_batch::{Batch, BatchControl}; use tower_fallback::Fallback; + use zebra_chain::sapling::{Output, PerSpendAnchor, Spend}; -mod hash_reader; mod params; #[cfg(test)] mod tests; -use self::hash_reader::HashReader; use params::PARAMS; /// Global batch verification context for Groth16 proofs of Spend statements. diff --git a/zebra-consensus/src/primitives/groth16/hash_reader.rs b/zebra-consensus/src/primitives/groth16/hash_reader.rs deleted file mode 100644 index 165e004dca2..00000000000 --- a/zebra-consensus/src/primitives/groth16/hash_reader.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::io::{self, Read}; - -use blake2b_simd::State; - -/// Abstraction over a reader which hashes the data being read. -pub struct HashReader { - reader: R, - hasher: State, -} - -impl HashReader { - /// Construct a new `HashReader` given an existing `reader` by value. - pub fn new(reader: R) -> Self { - HashReader { - reader, - hasher: State::new(), - } - } - - /// Destroy this reader and return the hash of what was read. - pub fn into_hash(self) -> String { - let hash = self.hasher.finalize(); - - let mut s = String::new(); - for c in hash.as_bytes().iter() { - s += &format!("{:02x}", c); - } - - s - } -} - -impl Read for HashReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let bytes = self.reader.read(buf)?; - - if bytes > 0 { - self.hasher.update(&buf[0..bytes]); - } - - Ok(bytes) - } -} diff --git a/zebra-consensus/src/primitives/groth16/params.rs b/zebra-consensus/src/primitives/groth16/params.rs index 5158ec322e7..8a362e8be13 100644 --- a/zebra-consensus/src/primitives/groth16/params.rs +++ b/zebra-consensus/src/primitives/groth16/params.rs @@ -1,16 +1,6 @@ -use std::{ - fs, - io::{self, BufReader}, -}; - use bellman::groth16; use bls12_381::Bls12; -use super::HashReader; - -const SAPLING_SPEND_HASH: &str = "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c"; -const SAPLING_OUTPUT_HASH: &str = "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028"; - lazy_static::lazy_static! { pub static ref PARAMS: Groth16Params = Groth16Params::new(); } @@ -38,87 +28,32 @@ pub struct SaplingParams { } impl SaplingParams { - fn new() -> Self { - // Use exactly the same paths as fetch-params.sh. - let mut params_dir = dirs::home_dir().unwrap_or_else(|| "/".into()); + fn new() -> SaplingParams { + let params_dir = + zcash_proofs::default_params_folder().expect("unable to find user home directory"); - // TODO: Is this path correct for Windows? - #[cfg(not(any(target_os = "macos", target_os = "ios")))] - params_dir.push(".zcash-params"); - - #[cfg(any(target_os = "macos", target_os = "ios"))] - params_dir.push("Library/Application Support/ZcashParams"); - - // Now the directory is correct, make sure we don't accidentally modify it. - let params_dir = params_dir; - - // TODO: Make into a constant or re-implement in Rust. - let fetch_params_url = - "https://raw.githubusercontent.com/zcash/zcash/master/zcutil/fetch-params.sh"; - let params_hint = format!( - "Hint: download parameters to {:?} using {:?}.", - params_dir, fetch_params_url, - ); + // TODO: Sprout let mut spend_path = params_dir.clone(); spend_path.push("sapling-spend.params"); - let spend = fs::File::open(spend_path).unwrap_or_else(|_| { - panic!( - "unexpected missing or unreadable Sapling spend parameters file. {}", - params_hint - ) - }); let mut output_path = params_dir; output_path.push("sapling-output.params"); - let output = fs::File::open(output_path).unwrap_or_else(|_| { - panic!( - "unexpected missing or unreadable Sapling output parameters file. {}", - params_hint - ) - }); - - let spend_fs = BufReader::with_capacity(1024 * 1024, spend); - let output_fs = BufReader::with_capacity(1024 * 1024, output); - Self::read(spend_fs, output_fs) - .unwrap_or_else(|_| panic!("unexpected error reading parameter files. {}", params_hint)) - } - - fn read(spend_fs: R, output_fs: R) -> Result { - let mut spend_fs = HashReader::new(spend_fs); - let mut output_fs = HashReader::new(output_fs); - - // Deserialize params - let spend = groth16::Parameters::::read(&mut spend_fs, false)?; - let output = groth16::Parameters::::read(&mut output_fs, false)?; - - // There is extra stuff (the transcript) at the end of the parameter file which is - // used to verify the parameter validity, but we're not interested in that. We do - // want to read it, though, so that the BLAKE2b computed afterward is consistent - // with `b2sum` on the files. - let mut sink = io::sink(); - io::copy(&mut spend_fs, &mut sink)?; - io::copy(&mut output_fs, &mut sink)?; - - assert!( - spend_fs.into_hash() == SAPLING_SPEND_HASH, - "Sapling spend parameter is not correct." - ); - assert!( - output_fs.into_hash() == SAPLING_OUTPUT_HASH, - "Sapling output parameter is not correct." - ); + // Download parameters if needed. + // + // TODO: use try_exists when it stabilises, to exit early on permissions errors (#83186) + if !spend_path.exists() || !output_path.exists() { + zcash_proofs::download_parameters().expect("error downloading parameter files"); + } - // Prepare verifying keys - let spend_prepared_verifying_key = groth16::prepare_verifying_key(&spend.vk); - let output_prepared_verifying_key = groth16::prepare_verifying_key(&output.vk); + let parameters = zcash_proofs::load_parameters(&spend_path, &output_path, None); - Ok(Self { - spend, - spend_prepared_verifying_key, - output, - output_prepared_verifying_key, - }) + SaplingParams { + spend: parameters.spend_params, + spend_prepared_verifying_key: parameters.spend_vk, + output: parameters.output_params, + output_prepared_verifying_key: parameters.output_vk, + } } }