Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hash checks of parameter files during initialization #28

Merged
merged 3 commits into from
Aug 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion include/librustzcash.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ extern "C" {
/// paths as necessary. Only called once.
void librustzcash_init_zksnark_params(
const char* spend_path,
const char* spend_hash,
const char* output_path,
const char* sprout_path
const char* output_hash,
const char* sprout_path,
const char* sprout_hash
);

/// Validates the provided Equihash solution against
Expand Down
42 changes: 42 additions & 0 deletions src/hashreader.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use blake2_rfc::blake2b::Blake2b;
use std::io::{self, Read};

/// Abstraction over a reader which hashes the data being read.
pub struct HashReader<R: Read> {
reader: R,
hasher: Blake2b,
}

impl<R: Read> HashReader<R> {
/// Construct a new `HashReader` given an existing `reader` by value.
pub fn new(reader: R) -> Self {
HashReader {
reader: reader,
hasher: Blake2b::new(64),
}
}

/// 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<R: Read> Read for HashReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let bytes = self.reader.read(buf)?;

if bytes > 0 {
self.hasher.update(&buf[0..bytes]);
}

Ok(bytes)
}
}
60 changes: 56 additions & 4 deletions src/rustzcash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ extern crate pairing;
extern crate rand;
extern crate sapling_crypto;

mod hashreader;

#[macro_use]
extern crate lazy_static;

Expand Down Expand Up @@ -36,7 +38,7 @@ use blake2_rfc::blake2s::Blake2s;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use rand::{OsRng, Rand, Rng};
use std::io::BufReader;
use std::io::{self, BufReader};

use libc::{c_char, c_uchar, int64_t, size_t, uint32_t, uint64_t};
use std::ffi::CStr;
Expand Down Expand Up @@ -110,12 +112,30 @@ fn fixed_scalar_mult(from: &[u8], p_g: FixedGenerators) -> edwards::Point<Bls12,
#[no_mangle]
pub extern "system" fn librustzcash_init_zksnark_params(
spend_path: *const c_char,
spend_hash: *const c_char,
output_path: *const c_char,
output_hash: *const c_char,
sprout_path: *const c_char,
sprout_hash: *const c_char,
) {
// Initialize jubjub parameters here
lazy_static::initialize(&JUBJUB);

let spend_hash = unsafe { CStr::from_ptr(spend_hash) }
.to_str()
.expect("hash should be a valid string")
.to_string();

let output_hash = unsafe { CStr::from_ptr(output_hash) }
.to_str()
.expect("hash should be a valid string")
.to_string();

let sprout_hash = unsafe { CStr::from_ptr(sprout_hash) }
.to_str()
.expect("hash should be a valid string")
.to_string();

// These should be valid CStr's, but the decoding may fail on Windows
// so we may need to use OSStr or something.
let spend_path = unsafe { CStr::from_ptr(spend_path) }
Expand All @@ -132,20 +152,52 @@ pub extern "system" fn librustzcash_init_zksnark_params(
.to_string();

// Load from each of the paths
let mut spend_fs = File::open(spend_path).expect("couldn't load Sapling spend parameters file");
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");
let sprout_fs = File::open(&sprout_path).expect("couldn't load Sprout groth16 parameters file");

let mut spend_fs = hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, spend_fs));
let mut output_fs =
File::open(output_path).expect("couldn't load Sapling output parameters file");
hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, output_fs));
let mut sprout_fs =
File::open(&sprout_path).expect("couldn't load Sprout groth16 parameters file");
hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, sprout_fs));

// Deserialize params
let spend_params = Parameters::<Bls12>::read(&mut spend_fs, false)
.expect("couldn't deserialize Sapling spend parameters file");
let output_params = Parameters::<Bls12>::read(&mut output_fs, false)
.expect("couldn't deserialize Sapling spend parameters file");

// We only deserialize the verifying key for the Sprout parameters, which
// appears at the beginning of the parameter file. The rest is loaded
// during proving time.
let sprout_vk = VerifyingKey::<Bls12>::read(&mut sprout_fs)
.expect("couldn't deserialize Sprout Groth16 verifying key");

// 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)
.expect("couldn't finish reading Sapling spend parameter file");
io::copy(&mut output_fs, &mut sink)
.expect("couldn't finish reading Sapling output parameter file");
io::copy(&mut sprout_fs, &mut sink)
.expect("couldn't finish reading Sprout groth16 parameter file");

if spend_fs.into_hash() != spend_hash {
panic!("Sapling spend parameter file is not correct, please clean your `~/.zcash-params/` and re-run `fetch-params`.");
}

if output_fs.into_hash() != output_hash {
panic!("Sapling output parameter file is not correct, please clean your `~/.zcash-params/` and re-run `fetch-params`.");
}

if sprout_fs.into_hash() != sprout_hash {
panic!("Sprout groth16 parameter file is not correct, please clean your `~/.zcash-params/` and re-run `fetch-params`.");
}

// Prepare verifying keys
let spend_vk = prepare_verifying_key(&spend_params.vk);
let output_vk = prepare_verifying_key(&output_params.vk);
Expand Down