zcash_proofs: Add API for downloading the Sapling parameters

Includes an example that exposes the API as a binary.
This commit is contained in:
Jack Grigg 2020-06-26 12:38:40 +12:00
parent e910788e8e
commit 9012672164
3 changed files with 69 additions and 5 deletions

View File

@ -17,6 +17,7 @@ blake2b_simd = "0.5"
byteorder = "1"
directories = { version = "1", optional = true }
ff = { version = "0.6", path = "../ff" }
minreq = { version = "2", features = ["https"], optional = true }
pairing = { version = "0.16", path = "../pairing" }
rand_core = "0.5.1"
zcash_primitives = { version = "0.2", path = "../zcash_primitives" }
@ -26,8 +27,13 @@ rand_xorshift = "0.2"
[features]
default = ["local-prover", "multicore"]
download-params = ["minreq"]
local-prover = ["directories"]
multicore = ["bellman/multicore"]
[[example]]
name = "download-params"
required-features = ["download-params"]
[badges]
maintenance = { status = "actively-developed" }

View File

@ -0,0 +1,3 @@
fn main() -> Result<(), minreq::Error> {
zcash_proofs::download_parameters()
}

View File

@ -29,6 +29,14 @@ pub mod prover;
const SAPLING_SPEND_NAME: &str = "sapling-spend.params";
const SAPLING_OUTPUT_NAME: &str = "sapling-output.params";
// Circuit hashes
const SAPLING_SPEND_HASH: &str = "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c";
const SAPLING_OUTPUT_HASH: &str = "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028";
const SPROUT_HASH: &str = "e9b238411bd6c0ec4791e9d04245ec350c9c5744f5610dfcce4365d5ca49dfefd5054e371842b3f88fa1b9d7e8e075249b3ebabd167fa8b0f3161292d36c180a";
#[cfg(feature = "download-params")]
const DOWNLOAD_URL: &str = "https://download.z.cash/downloads";
/// Returns the default folder that the Zcash proving parameters are located in.
#[cfg(feature = "directories")]
fn default_params_folder() -> Option<PathBuf> {
@ -41,6 +49,58 @@ fn default_params_folder() -> Option<PathBuf> {
})
}
/// Download the Zcash Sapling parameters, storing them in the default location.
///
/// This mirrors the behaviour of the `fetch-params.sh` script from `zcashd`.
#[cfg(feature = "download-params")]
pub fn download_parameters() -> Result<(), minreq::Error> {
// Ensure that the default Zcash parameters location exists.
let params_dir = default_params_folder().ok_or(io::Error::new(
io::ErrorKind::Other,
"Could not load default params folder",
))?;
std::fs::create_dir_all(&params_dir)?;
let fetch_params = |name: &str, expected_hash: &str| -> Result<(), minreq::Error> {
use std::io::Write;
// Download the parts directly (Sapling parameters are small enough for this).
let part_1 = minreq::get(format!("{}/{}.part.1", DOWNLOAD_URL, name)).send()?;
let part_2 = minreq::get(format!("{}/{}.part.2", DOWNLOAD_URL, name)).send()?;
// Verify parameter file hash.
let hash = blake2b_simd::State::new()
.update(part_1.as_bytes())
.update(part_2.as_bytes())
.finalize()
.to_hex();
if &hash != expected_hash {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"{} failed validation (expected: {}, actual: {}, fetched {} bytes)",
name,
expected_hash,
hash,
part_1.as_bytes().len() + part_2.as_bytes().len()
),
)
.into());
}
// Write parameter file.
let mut f = File::create(params_dir.join(name))?;
f.write_all(part_1.as_bytes())?;
f.write_all(part_2.as_bytes())?;
Ok(())
};
fetch_params(SAPLING_SPEND_NAME, SAPLING_SPEND_HASH)?;
fetch_params(SAPLING_OUTPUT_NAME, SAPLING_OUTPUT_HASH)?;
Ok(())
}
pub fn load_parameters(
spend_path: &Path,
output_path: &Path,
@ -52,11 +112,6 @@ pub fn load_parameters(
PreparedVerifyingKey<Bls12>,
Option<PreparedVerifyingKey<Bls12>>,
) {
// Sapling circuit hashes
const SAPLING_SPEND_HASH: &str = "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c";
const SAPLING_OUTPUT_HASH: &str = "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028";
const SPROUT_HASH: &str = "e9b238411bd6c0ec4791e9d04245ec350c9c5744f5610dfcce4365d5ca49dfefd5054e371842b3f88fa1b9d7e8e075249b3ebabd167fa8b0f3161292d36c180a";
// Load from each of the paths
let spend_fs = File::open(spend_path).expect("couldn't load Sapling spend parameters file");
let output_fs = File::open(output_path).expect("couldn't load Sapling output parameters file");