1#![doc = include_str!("../README.md")]
2
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![allow(clippy::result_unit_err)]
6
7use ironfish_bellperson::groth16::{prepare_verifying_key, Parameters, PreparedVerifyingKey, VerifyingKey};
8use blstrs::Bls12;
9use std::fs::File;
10use std::io::{self, BufReader};
11use std::path::Path;
12
13#[cfg(feature = "directories")]
14use directories::BaseDirs;
15#[cfg(feature = "directories")]
16use std::path::PathBuf;
17
18pub mod circuit;
19pub mod constants;
20mod hashreader;
21pub mod sapling;
22pub mod sprout;
23
24#[cfg(any(feature = "local-prover", feature = "bundled-prover"))]
25#[cfg_attr(
26 docsrs,
27 doc(cfg(any(feature = "local-prover", feature = "bundled-prover")))
28)]
29pub mod prover;
30
31#[cfg(feature = "local-prover")]
33const SAPLING_SPEND_NAME: &str = "sapling-spend.params";
34#[cfg(feature = "local-prover")]
35const SAPLING_OUTPUT_NAME: &str = "sapling-output.params";
36
37const SAPLING_SPEND_HASH: &str = "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c";
39const SAPLING_OUTPUT_HASH: &str = "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028";
40const SPROUT_HASH: &str = "e9b238411bd6c0ec4791e9d04245ec350c9c5744f5610dfcce4365d5ca49dfefd5054e371842b3f88fa1b9d7e8e075249b3ebabd167fa8b0f3161292d36c180a";
41
42#[cfg(feature = "download-params")]
43const DOWNLOAD_URL: &str = "https://download.z.cash/downloads";
44
45#[cfg(feature = "directories")]
47#[cfg_attr(docsrs, doc(cfg(feature = "directories")))]
48pub fn default_params_folder() -> Option<PathBuf> {
49 BaseDirs::new().map(|base_dirs| {
50 if cfg!(any(windows, target_os = "macos")) {
51 base_dirs.data_dir().join("ZcashParams")
52 } else {
53 base_dirs.home_dir().join(".zcash-params")
54 }
55 })
56}
57
58#[cfg(feature = "download-params")]
62#[cfg_attr(docsrs, doc(cfg(feature = "download-params")))]
63pub fn download_parameters() -> Result<(), minreq::Error> {
64 let params_dir = default_params_folder().ok_or_else(|| {
66 io::Error::new(io::ErrorKind::Other, "Could not load default params folder")
67 })?;
68 std::fs::create_dir_all(¶ms_dir)?;
69
70 let fetch_params = |name: &str, expected_hash: &str| -> Result<(), minreq::Error> {
71 use std::io::Write;
72
73 let part_1 = minreq::get(format!("{}/{}.part.1", DOWNLOAD_URL, name)).send()?;
75 let part_2 = minreq::get(format!("{}/{}.part.2", DOWNLOAD_URL, name)).send()?;
76
77 let hash = blake2b_simd::State::new()
79 .update(part_1.as_bytes())
80 .update(part_2.as_bytes())
81 .finalize()
82 .to_hex();
83 if &hash != expected_hash {
84 return Err(io::Error::new(
85 io::ErrorKind::InvalidData,
86 format!(
87 "{} failed validation (expected: {}, actual: {}, fetched {} bytes)",
88 name,
89 expected_hash,
90 hash,
91 part_1.as_bytes().len() + part_2.as_bytes().len()
92 ),
93 )
94 .into());
95 }
96
97 let mut f = File::create(params_dir.join(name))?;
99 f.write_all(part_1.as_bytes())?;
100 f.write_all(part_2.as_bytes())?;
101 Ok(())
102 };
103
104 fetch_params(SAPLING_SPEND_NAME, SAPLING_SPEND_HASH)?;
105 fetch_params(SAPLING_OUTPUT_NAME, SAPLING_OUTPUT_HASH)?;
106
107 Ok(())
108}
109
110pub struct ZcashParameters {
111 pub spend_params: Parameters<Bls12>,
112 pub spend_vk: PreparedVerifyingKey<Bls12>,
113 pub output_params: Parameters<Bls12>,
114 pub output_vk: PreparedVerifyingKey<Bls12>,
115 pub sprout_vk: Option<PreparedVerifyingKey<Bls12>>,
116}
117
118pub fn load_parameters(
119 spend_path: &Path,
120 output_path: &Path,
121 sprout_path: Option<&Path>,
122) -> ZcashParameters {
123 let spend_fs = File::open(spend_path).expect("couldn't load Sapling spend parameters file");
125 let output_fs = File::open(output_path).expect("couldn't load Sapling output parameters file");
126 let sprout_fs =
127 sprout_path.map(|p| File::open(p).expect("couldn't load Sprout groth16 parameters file"));
128
129 parse_parameters(
130 BufReader::with_capacity(1024 * 1024, spend_fs),
131 BufReader::with_capacity(1024 * 1024, output_fs),
132 sprout_fs.map(|fs| BufReader::with_capacity(1024 * 1024, fs)),
133 )
134}
135
136pub fn parse_parameters<R: io::Read>(
140 spend_fs: R,
141 output_fs: R,
142 sprout_fs: Option<R>,
143) -> ZcashParameters {
144 let mut spend_fs = hashreader::HashReader::new(spend_fs);
145 let mut output_fs = hashreader::HashReader::new(output_fs);
146 let mut sprout_fs = sprout_fs.map(hashreader::HashReader::new);
147
148 let spend_params = Parameters::<Bls12>::read(&mut spend_fs, false)
150 .expect("couldn't deserialize Sapling spend parameters file");
151 let output_params = Parameters::<Bls12>::read(&mut output_fs, false)
152 .expect("couldn't deserialize Sapling spend parameters file");
153
154 let sprout_vk = sprout_fs.as_mut().map(|mut fs| {
158 VerifyingKey::<Bls12>::read(&mut fs)
159 .expect("couldn't deserialize Sprout Groth16 verifying key")
160 });
161
162 let mut sink = io::sink();
167 io::copy(&mut spend_fs, &mut sink)
168 .expect("couldn't finish reading Sapling spend parameter file");
169 io::copy(&mut output_fs, &mut sink)
170 .expect("couldn't finish reading Sapling output parameter file");
171 if let Some(mut sprout_fs) = sprout_fs.as_mut() {
172 io::copy(&mut sprout_fs, &mut sink)
173 .expect("couldn't finish reading Sprout groth16 parameter file");
174 }
175
176 if spend_fs.into_hash() != SAPLING_SPEND_HASH {
177 panic!("Sapling spend parameter file is not correct, please clean your `~/.zcash-params/` and re-run `fetch-params`.");
178 }
179
180 if output_fs.into_hash() != SAPLING_OUTPUT_HASH {
181 panic!("Sapling output parameter file is not correct, please clean your `~/.zcash-params/` and re-run `fetch-params`.");
182 }
183
184 if sprout_fs
185 .map(|fs| fs.into_hash() != SPROUT_HASH)
186 .unwrap_or(false)
187 {
188 panic!("Sprout groth16 parameter file is not correct, please clean your `~/.zcash-params/` and re-run `fetch-params`.");
189 }
190
191 let spend_vk = prepare_verifying_key(&spend_params.vk);
193 let output_vk = prepare_verifying_key(&output_params.vk);
194 let sprout_vk = sprout_vk.map(|vk| prepare_verifying_key(&vk));
195
196 ZcashParameters {
197 spend_params,
198 spend_vk,
199 output_params,
200 output_vk,
201 sprout_vk,
202 }
203}