From 6b43b2d0d6a80cfcd184d9925792c43bd3262429 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 14 Aug 2018 23:43:33 +0100 Subject: [PATCH 1/8] Refactor Sapling spendAuthSig creation into zcash_primitives::sapling --- Cargo.lock | 1 + librustzcash/Cargo.toml | 1 + librustzcash/src/rustzcash.rs | 23 +++----------------- zcash_primitives/src/lib.rs | 1 + zcash_primitives/src/sapling.rs | 37 +++++++++++++++++++++++++++++++++ 5 files changed, 43 insertions(+), 20 deletions(-) create mode 100644 zcash_primitives/src/sapling.rs diff --git a/Cargo.lock b/Cargo.lock index a754c35..3870758 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -230,6 +230,7 @@ dependencies = [ "pairing 0.14.2", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", + "zcash_primitives 0.0.0", "zcash_proofs 0.0.0", "zip32 0.0.0", ] diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index c2ab7ff..e633152 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -22,6 +22,7 @@ lazy_static = "1" byteorder = "1" rand = "0.4" sapling-crypto = { path = "../sapling-crypto" } +zcash_primitives = { path = "../zcash_primitives" } zcash_proofs = { path = "../zcash_proofs" } zip32 = { path = "../zip32" } diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index f264690..29df19f 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -6,6 +6,7 @@ extern crate libc; extern crate pairing; extern crate rand; extern crate sapling_crypto; +extern crate zcash_primitives; extern crate zcash_proofs; extern crate zip32; @@ -61,6 +62,7 @@ use std::ffi::OsString; use std::os::windows::ffi::OsStringExt; use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey}; +use zcash_primitives::sapling::spend_sig; use zcash_proofs::sapling::{ CommitmentTreeWitness, SaplingProvingContext, SaplingVerificationContext, }; @@ -1069,27 +1071,8 @@ pub extern "system" fn librustzcash_sapling_spend_sig( Err(_) => return false, }; - // We compute `rsk`... - let rsk = ask.randomize(ar); - - // We compute `rk` from there (needed for key prefixing) - let rk = - redjubjub::PublicKey::from_private(&rsk, FixedGenerators::SpendingKeyGenerator, &JUBJUB); - - // Compute the signature's message for rk/spend_auth_sig - let mut data_to_be_signed = [0u8; 64]; - rk.0.write(&mut data_to_be_signed[0..32]) - .expect("message buffer should be 32 bytes"); - (&mut data_to_be_signed[32..64]).copy_from_slice(&(unsafe { &*sighash })[..]); - // Do the signing - let mut rng = OsRng::new().expect("should be able to construct RNG"); - let sig = rsk.sign( - &data_to_be_signed, - &mut rng, - FixedGenerators::SpendingKeyGenerator, - &JUBJUB, - ); + let sig = spend_sig(ask, ar, unsafe { &*sighash }, &JUBJUB); // Write out the signature sig.write(&mut (unsafe { &mut *result })[..]) diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 6a84cc3..e053e50 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -10,6 +10,7 @@ extern crate sapling_crypto; use sapling_crypto::jubjub::JubjubBls12; +pub mod sapling; mod serialize; pub mod transaction; diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs new file mode 100644 index 0000000..b59dc2b --- /dev/null +++ b/zcash_primitives/src/sapling.rs @@ -0,0 +1,37 @@ +use pairing::bls12_381::Bls12; +use rand::OsRng; +use sapling_crypto::{ + jubjub::{fs::Fs, FixedGenerators, JubjubBls12}, + redjubjub::{PrivateKey, PublicKey, Signature}, +}; + +/// Create the spendAuthSig for a Sapling SpendDescription. +pub fn spend_sig( + ask: PrivateKey, + ar: Fs, + sighash: &[u8; 32], + params: &JubjubBls12, +) -> Signature { + // Initialize secure RNG + let mut rng = OsRng::new().expect("should be able to construct RNG"); + + // We compute `rsk`... + let rsk = ask.randomize(ar); + + // We compute `rk` from there (needed for key prefixing) + let rk = PublicKey::from_private(&rsk, FixedGenerators::SpendingKeyGenerator, params); + + // Compute the signature's message for rk/spend_auth_sig + let mut data_to_be_signed = [0u8; 64]; + rk.0.write(&mut data_to_be_signed[0..32]) + .expect("message buffer should be 32 bytes"); + (&mut data_to_be_signed[32..64]).copy_from_slice(&sighash[..]); + + // Do the signing + rsk.sign( + &data_to_be_signed, + &mut rng, + FixedGenerators::SpendingKeyGenerator, + params, + ) +} From 09a20aacfe9f937f81b4b3389ff929367a76c1d6 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 14 Sep 2018 09:00:27 +0100 Subject: [PATCH 2/8] Make zcash_primitives::JUBJUB the canonical instantiation of JubjubBls12 --- Cargo.lock | 2 +- librustzcash/src/rustzcash.rs | 9 ++------- zcash_primitives/src/lib.rs | 2 +- zip32/Cargo.toml | 2 +- zip32/src/lib.rs | 12 +++--------- 5 files changed, 8 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3870758..e6214b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -466,9 +466,9 @@ dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", "sapling-crypto 0.0.1", + "zcash_primitives 0.0.0", ] [metadata] diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 29df19f..e889a4b 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -12,7 +12,6 @@ extern crate zip32; mod hashreader; -#[macro_use] extern crate lazy_static; use ff::{BitIterator, PrimeField, PrimeFieldRepr}; @@ -24,7 +23,7 @@ use sapling_crypto::{ jubjub::{ edwards, fs::{Fs, FsRepr}, - FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown, + FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown, }, pedersen_hash::{pedersen_hash, Personalization}, redjubjub::{self, Signature}, @@ -62,7 +61,7 @@ use std::ffi::OsString; use std::os::windows::ffi::OsStringExt; use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey}; -use zcash_primitives::sapling::spend_sig; +use zcash_primitives::{sapling::spend_sig, JUBJUB}; use zcash_proofs::sapling::{ CommitmentTreeWitness, SaplingProvingContext, SaplingVerificationContext, }; @@ -72,10 +71,6 @@ pub mod equihash; #[cfg(test)] mod tests; -lazy_static! { - static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; -} - static mut SAPLING_SPEND_VK: Option> = None; static mut SAPLING_OUTPUT_VK: Option> = None; static mut SPROUT_GROTH16_VK: Option> = None; diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index e053e50..2475209 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -15,5 +15,5 @@ mod serialize; pub mod transaction; lazy_static! { - static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; + pub static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; } diff --git a/zip32/Cargo.toml b/zip32/Cargo.toml index 0cee23d..05923c8 100644 --- a/zip32/Cargo.toml +++ b/zip32/Cargo.toml @@ -16,9 +16,9 @@ aes = "0.2" byteorder = "1" ff = { path = "../ff" } fpe = "0.1" -lazy_static = "1.0" pairing = { path = "../pairing" } sapling-crypto = { path = "../sapling-crypto" } +zcash_primitives = { path = "../zcash_primitives" } [dependencies.blake2-rfc] git = "https://github.com/gtank/blake2-rfc" diff --git a/zip32/src/lib.rs b/zip32/src/lib.rs index f26ccad..1543e62 100644 --- a/zip32/src/lib.rs +++ b/zip32/src/lib.rs @@ -3,10 +3,9 @@ extern crate blake2_rfc; extern crate byteorder; extern crate ff; extern crate fpe; -#[macro_use] -extern crate lazy_static; extern crate pairing; extern crate sapling_crypto; +extern crate zcash_primitives; use aes::Aes256; use blake2_rfc::blake2b::{Blake2b, Blake2bResult}; @@ -15,16 +14,11 @@ use ff::{Field, PrimeField, PrimeFieldRepr}; use fpe::ff1::{BinaryNumeralString, FF1}; use pairing::bls12_381::Bls12; use sapling_crypto::{ - jubjub::{ - edwards, FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, ToUniform, Unknown, - }, + jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, ToUniform, Unknown}, primitives::{Diversifier, PaymentAddress, ViewingKey}, }; use std::io::{self, Read, Write}; - -lazy_static! { - static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; -} +use zcash_primitives::JUBJUB; pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed"; pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &'static [u8; 16] = b"ZcashIP32Sapling"; From 2d43e3be7c7f643c8b83294b6b2e0577f7f6f5b6 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 17 Sep 2018 11:45:20 +0100 Subject: [PATCH 3/8] Move parameter-loading into zcash_proofs --- Cargo.lock | 1 + librustzcash/src/rustzcash.rs | 81 ++++--------------- zcash_proofs/Cargo.toml | 4 + .../src/hashreader.rs | 0 zcash_proofs/src/lib.rs | 77 ++++++++++++++++++ 5 files changed, 99 insertions(+), 64 deletions(-) rename {librustzcash => zcash_proofs}/src/hashreader.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index e6214b0..33d7675 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -446,6 +446,7 @@ name = "zcash_proofs" version = "0.0.0" dependencies = [ "bellman 0.1.0", + "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "pairing 0.14.2", diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index e889a4b..5499749 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -10,8 +10,6 @@ extern crate zcash_primitives; extern crate zcash_proofs; extern crate zip32; -mod hashreader; - extern crate lazy_static; use ff::{BitIterator, PrimeField, PrimeFieldRepr}; @@ -33,8 +31,7 @@ use sapling_crypto::circuit::sapling::TREE_DEPTH as SAPLING_TREE_DEPTH; use sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}; use bellman::groth16::{ - create_random_proof, prepare_verifying_key, verify_proof, Parameters, PreparedVerifyingKey, - Proof, VerifyingKey, + create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof, }; use blake2_rfc::blake2s::Blake2s; @@ -42,7 +39,7 @@ use blake2_rfc::blake2s::Blake2s; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use rand::{OsRng, Rng}; -use std::io::{self, BufReader}; +use std::io::BufReader; use libc::{c_char, c_uchar, int64_t, size_t, uint32_t, uint64_t}; use std::ffi::CStr; @@ -62,8 +59,9 @@ use std::os::windows::ffi::OsStringExt; use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey}; use zcash_primitives::{sapling::spend_sig, JUBJUB}; -use zcash_proofs::sapling::{ - CommitmentTreeWitness, SaplingProvingContext, SaplingVerificationContext, +use zcash_proofs::{ + load_parameters, + sapling::{CommitmentTreeWitness, SaplingProvingContext, SaplingVerificationContext}, }; pub mod equihash; @@ -196,70 +194,25 @@ fn init_zksnark_params( let spend_hash = unsafe { CStr::from_ptr(spend_hash) } .to_str() - .expect("hash should be a valid string") - .to_string(); + .expect("hash should be a valid string"); let output_hash = unsafe { CStr::from_ptr(output_hash) } .to_str() - .expect("hash should be a valid string") - .to_string(); + .expect("hash should be a valid string"); let sprout_hash = unsafe { CStr::from_ptr(sprout_hash) } .to_str() - .expect("hash should be a valid string") - .to_string(); + .expect("hash should be a valid string"); - // 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"); - 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 = - hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, output_fs)); - let mut sprout_fs = - hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, sprout_fs)); - - // Deserialize params - let spend_params = Parameters::::read(&mut spend_fs, false) - .expect("couldn't deserialize Sapling spend parameters file"); - let output_params = Parameters::::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::::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); - let sprout_vk = prepare_verifying_key(&sprout_vk); + // Load params + let (spend_params, spend_vk, output_params, output_vk, sprout_vk) = load_parameters( + spend_path, + spend_hash, + output_path, + output_hash, + sprout_path, + sprout_hash, + ); // Caller is responsible for calling this function once, so // these global mutations are safe. diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index ac1fd6b..5bcdb26 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -12,3 +12,7 @@ ff = { path = "../ff" } pairing = { path = "../pairing" } rand = "0.4" sapling-crypto = { path = "../sapling-crypto" } + +[dependencies.blake2-rfc] +git = "https://github.com/gtank/blake2-rfc" +rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" diff --git a/librustzcash/src/hashreader.rs b/zcash_proofs/src/hashreader.rs similarity index 100% rename from librustzcash/src/hashreader.rs rename to zcash_proofs/src/hashreader.rs diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index 55ae761..6d40454 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -1,8 +1,85 @@ extern crate bellman; +extern crate blake2_rfc; extern crate byteorder; extern crate ff; extern crate pairing; extern crate rand; extern crate sapling_crypto; +use bellman::groth16::{prepare_verifying_key, Parameters, PreparedVerifyingKey, VerifyingKey}; +use pairing::bls12_381::Bls12; +use std::fs::File; +use std::io::{self, BufReader}; +use std::path::Path; + +mod hashreader; pub mod sapling; + +pub fn load_parameters( + spend_path: &Path, + spend_hash: &str, + output_path: &Path, + output_hash: &str, + sprout_path: &Path, + sprout_hash: &str, +) -> ( + Parameters, + PreparedVerifyingKey, + Parameters, + PreparedVerifyingKey, + PreparedVerifyingKey, +) { + // 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"); + 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 = + hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, output_fs)); + let mut sprout_fs = + hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, sprout_fs)); + + // Deserialize params + let spend_params = Parameters::::read(&mut spend_fs, false) + .expect("couldn't deserialize Sapling spend parameters file"); + let output_params = Parameters::::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::::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); + let sprout_vk = prepare_verifying_key(&sprout_vk); + + (spend_params, spend_vk, output_params, output_vk, sprout_vk) +} From 9ae5a9d6246dcf8493d8c042b4c07d72e6e52d6b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 17 Sep 2018 11:59:46 +0100 Subject: [PATCH 4/8] Make loading of Sprout key optional in zcash_proofs API --- librustzcash/src/rustzcash.rs | 6 +++--- zcash_proofs/src/lib.rs | 27 ++++++++++++++++----------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 5499749..ab9357d 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -210,8 +210,8 @@ fn init_zksnark_params( spend_hash, output_path, output_hash, - sprout_path, - sprout_hash, + Some(sprout_path), + Some(sprout_hash), ); // Caller is responsible for calling this function once, so @@ -223,7 +223,7 @@ fn init_zksnark_params( SAPLING_SPEND_VK = Some(spend_vk); SAPLING_OUTPUT_VK = Some(output_vk); - SPROUT_GROTH16_VK = Some(sprout_vk); + SPROUT_GROTH16_VK = Some(sprout_vk.unwrap()); } } diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index 6d40454..ca17a8b 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -20,25 +20,26 @@ pub fn load_parameters( spend_hash: &str, output_path: &Path, output_hash: &str, - sprout_path: &Path, - sprout_hash: &str, + sprout_path: Option<&Path>, + sprout_hash: Option<&str>, ) -> ( Parameters, PreparedVerifyingKey, Parameters, PreparedVerifyingKey, - PreparedVerifyingKey, + Option>, ) { // 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"); - let sprout_fs = File::open(sprout_path).expect("couldn't load Sprout groth16 parameters file"); + let sprout_fs = + sprout_path.map(|p| File::open(p).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 = hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, output_fs)); let mut sprout_fs = - hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, sprout_fs)); + sprout_fs.map(|fs| hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, fs))); // Deserialize params let spend_params = Parameters::::read(&mut spend_fs, false) @@ -49,8 +50,10 @@ pub fn load_parameters( // 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::::read(&mut sprout_fs) - .expect("couldn't deserialize Sprout Groth16 verifying key"); + let sprout_vk = sprout_fs.as_mut().map(|mut fs| { + VerifyingKey::::read(&mut 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 @@ -61,8 +64,10 @@ pub fn load_parameters( .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 let Some(mut sprout_fs) = sprout_fs.as_mut() { + 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`."); @@ -72,14 +77,14 @@ pub fn load_parameters( 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 { + if sprout_fs.map(|fs| fs.into_hash()) != sprout_hash.map(|h| h.to_owned()) { 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); - let sprout_vk = prepare_verifying_key(&sprout_vk); + let sprout_vk = sprout_vk.map(|vk| prepare_verifying_key(&vk)); (spend_params, spend_vk, output_params, output_vk, sprout_vk) } From 80db0ae2f954f82653073afac45abe1d9f0d1bdc Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 14 Sep 2018 09:03:52 +0100 Subject: [PATCH 5/8] ExpandedSpendingKey::proof_generation_key(), visibility tweaks --- zip32/src/lib.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/zip32/src/lib.rs b/zip32/src/lib.rs index 1543e62..2541c41 100644 --- a/zip32/src/lib.rs +++ b/zip32/src/lib.rs @@ -15,7 +15,7 @@ use fpe::ff1::{BinaryNumeralString, FF1}; use pairing::bls12_381::Bls12; use sapling_crypto::{ jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, ToUniform, Unknown}, - primitives::{Diversifier, PaymentAddress, ViewingKey}, + primitives::{Diversifier, PaymentAddress, ProofGenerationKey, ViewingKey}, }; use std::io::{self, Read, Write}; use zcash_primitives::JUBJUB; @@ -42,7 +42,7 @@ fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bResult { /// An outgoing viewing key #[derive(Clone, Copy, PartialEq)] -struct OutgoingViewingKey([u8; 32]); +pub struct OutgoingViewingKey([u8; 32]); impl OutgoingViewingKey { fn derive_child(&self, i_l: &[u8]) -> Self { @@ -55,15 +55,15 @@ impl OutgoingViewingKey { /// A Sapling expanded spending key #[derive(Clone)] pub struct ExpandedSpendingKey { - ask: E::Fs, + pub ask: E::Fs, nsk: E::Fs, ovk: OutgoingViewingKey, } /// A Sapling full viewing key pub struct FullViewingKey { - vk: ViewingKey, - ovk: OutgoingViewingKey, + pub vk: ViewingKey, + pub ovk: OutgoingViewingKey, } impl ExpandedSpendingKey { @@ -76,6 +76,15 @@ impl ExpandedSpendingKey { ExpandedSpendingKey { ask, nsk, ovk } } + pub fn proof_generation_key(&self, params: &E::Params) -> ProofGenerationKey { + ProofGenerationKey { + ak: params + .generator(FixedGenerators::SpendingKeyGenerator) + .mul(self.ask, params), + nsk: self.nsk, + } + } + fn derive_child(&self, i_l: &[u8]) -> Self { let mut ask = E::Fs::to_uniform(prf_expand(i_l, &[0x13]).as_bytes()); let mut nsk = E::Fs::to_uniform(prf_expand(i_l, &[0x14]).as_bytes()); From 34ca75cceb87a38e122a00f2deed8c841f5aa75e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 19 Oct 2018 01:07:39 +0100 Subject: [PATCH 6/8] impl Clone for ExtendedFullViewingKey --- zip32/src/lib.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/zip32/src/lib.rs b/zip32/src/lib.rs index 2541c41..b0135e9 100644 --- a/zip32/src/lib.rs +++ b/zip32/src/lib.rs @@ -131,6 +131,18 @@ impl ExpandedSpendingKey { } } +impl Clone for FullViewingKey { + fn clone(&self) -> Self { + FullViewingKey { + vk: ViewingKey { + ak: self.vk.ak.clone(), + nk: self.vk.nk.clone(), + }, + ovk: self.ovk.clone(), + } + } +} + impl FullViewingKey { fn from_expanded_spending_key(expsk: &ExpandedSpendingKey, params: &E::Params) -> Self { FullViewingKey { @@ -351,6 +363,7 @@ pub struct ExtendedSpendingKey { } // A Sapling extended full viewing key +#[derive(Clone)] pub struct ExtendedFullViewingKey { depth: u8, parent_fvk_tag: FVKTag, From 012d43bc8cae0a13340227a4c3bb0a4a859b9c07 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 18 Nov 2018 13:13:43 +0000 Subject: [PATCH 7/8] derive Debug for various structs --- sapling-crypto/src/jubjub/edwards.rs | 1 + sapling-crypto/src/jubjub/mod.rs | 1 + sapling-crypto/src/redjubjub.rs | 3 +- .../src/transaction/components.rs | 57 +++++++++++++++++++ zcash_primitives/src/transaction/mod.rs | 36 ++++++++++++ 5 files changed, 97 insertions(+), 1 deletion(-) diff --git a/sapling-crypto/src/jubjub/edwards.rs b/sapling-crypto/src/jubjub/edwards.rs index 49018fe..3aa9345 100644 --- a/sapling-crypto/src/jubjub/edwards.rs +++ b/sapling-crypto/src/jubjub/edwards.rs @@ -25,6 +25,7 @@ use std::io::{ // // See "Twisted Edwards Curves Revisited" // Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson +#[derive(Debug)] pub struct Point { x: E::Fr, y: E::Fr, diff --git a/sapling-crypto/src/jubjub/mod.rs b/sapling-crypto/src/jubjub/mod.rs index e46fac5..c925877 100644 --- a/sapling-crypto/src/jubjub/mod.rs +++ b/sapling-crypto/src/jubjub/mod.rs @@ -43,6 +43,7 @@ pub mod fs; pub mod tests; /// Point of unknown order. +#[derive(Debug)] pub enum Unknown { } /// Point of prime order. diff --git a/sapling-crypto/src/redjubjub.rs b/sapling-crypto/src/redjubjub.rs index e159179..00e2f8f 100644 --- a/sapling-crypto/src/redjubjub.rs +++ b/sapling-crypto/src/redjubjub.rs @@ -29,7 +29,7 @@ fn h_star(a: &[u8], b: &[u8]) -> E::Fs { hash_to_scalar::(b"Zcash_RedJubjubH", a, b) } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Signature { rbar: [u8; 32], sbar: [u8; 32], @@ -37,6 +37,7 @@ pub struct Signature { pub struct PrivateKey(pub E::Fs); +#[derive(Debug)] pub struct PublicKey(pub Point); impl Signature { diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index 39b468d..9d5a2a0 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -58,6 +58,7 @@ impl Amount { } } +#[derive(Debug)] pub struct Script(pub Vec); impl Script { @@ -71,6 +72,7 @@ impl Script { } } +#[derive(Debug)] pub struct OutPoint { hash: [u8; 32], n: u32, @@ -90,6 +92,7 @@ impl OutPoint { } } +#[derive(Debug)] pub struct TxIn { pub prevout: OutPoint, script_sig: Script, @@ -116,6 +119,7 @@ impl TxIn { } } +#[derive(Debug)] pub struct TxOut { value: Amount, script_pubkey: Script, @@ -147,6 +151,16 @@ pub struct SpendDescription { pub spend_auth_sig: Signature, } +impl std::fmt::Debug for SpendDescription { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!( + f, + "SpendDescription(cv = {:?}, anchor = {:?}, nullifier = {:?}, rk = {:?}, spend_auth_sig = {:?})", + self.cv, self.anchor, self.nullifier, self.rk, self.spend_auth_sig + ) + } +} + impl SpendDescription { pub fn read(mut reader: &mut R) -> io::Result { // Consensus rules (§4.4): @@ -211,6 +225,16 @@ pub struct OutputDescription { pub zkproof: [u8; GROTH_PROOF_SIZE], } +impl std::fmt::Debug for OutputDescription { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!( + f, + "OutputDescription(cv = {:?}, cmu = {:?}, ephemeral_key = {:?})", + self.cv, self.cmu, self.ephemeral_key + ) + } +} + impl OutputDescription { pub fn read(mut reader: &mut R) -> io::Result { // Consensus rules (§4.5): @@ -268,6 +292,15 @@ enum SproutProof { PHGR([u8; PHGR_PROOF_SIZE]), } +impl std::fmt::Debug for SproutProof { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match self { + SproutProof::Groth(_) => write!(f, "SproutProof::Groth"), + SproutProof::PHGR(_) => write!(f, "SproutProof::PHGR"), + } + } +} + pub struct JSDescription { vpub_old: Amount, vpub_new: Amount, @@ -281,6 +314,30 @@ pub struct JSDescription { ciphertexts: [[u8; 601]; ZC_NUM_JS_OUTPUTS], } +impl std::fmt::Debug for JSDescription { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!( + f, + "JSDescription( + vpub_old = {:?}, vpub_new = {:?}, + anchor = {:?}, + nullifiers = {:?}, + commitments = {:?}, + ephemeral_key = {:?}, + random_seed = {:?}, + macs = {:?})", + self.vpub_old, + self.vpub_new, + self.anchor, + self.nullifiers, + self.commitments, + self.ephemeral_key, + self.random_seed, + self.macs + ) + } +} + impl JSDescription { pub fn read(mut reader: R, use_groth: bool) -> io::Result { // Consensus rule (§4.3): Canonical encoding is enforced here diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index 787c01d..70934e1 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -21,6 +21,7 @@ const SAPLING_VERSION_GROUP_ID: u32 = 0x892F2085; const SAPLING_TX_VERSION: u32 = 4; /// A Zcash transaction. +#[derive(Debug)] pub struct Transaction(TransactionData); impl Deref for Transaction { @@ -48,6 +49,41 @@ pub struct TransactionData { pub binding_sig: Option, } +impl std::fmt::Debug for TransactionData { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!( + f, + "TransactionData( + overwintered = {:?}, + version = {:?}, + version_group_id = {:?}, + vin = {:?}, + vout = {:?}, + lock_time = {:?}, + expiry_height = {:?}, + value_balance = {:?}, + shielded_spends = {:?}, + shielded_outputs = {:?}, + joinsplits = {:?}, + joinsplit_pubkey = {:?}, + binding_sig = {:?})", + self.overwintered, + self.version, + self.version_group_id, + self.vin, + self.vout, + self.lock_time, + self.expiry_height, + self.value_balance, + self.shielded_spends, + self.shielded_outputs, + self.joinsplits, + self.joinsplit_pubkey, + self.binding_sig + ) + } +} + impl TransactionData { pub fn new() -> Self { TransactionData { From 3d39706aeeb8a1e56b65192b02c1a437796191d9 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 1 Dec 2018 00:43:45 +0000 Subject: [PATCH 8/8] Make SpendDescription.spend_auth_sig optional --- zcash_primitives/src/transaction/components.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index 9d5a2a0..981dc4c 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -148,7 +148,7 @@ pub struct SpendDescription { pub nullifier: [u8; 32], pub rk: PublicKey, pub zkproof: [u8; GROTH_PROOF_SIZE], - pub spend_auth_sig: Signature, + pub spend_auth_sig: Option, } impl std::fmt::Debug for SpendDescription { @@ -194,7 +194,7 @@ impl SpendDescription { // Consensus rules (§4.4): // - Canonical encoding is enforced here. // - Signature validity is enforced in SaplingVerificationContext::check_spend() - let spend_auth_sig = Signature::read(&mut reader)?; + let spend_auth_sig = Some(Signature::read(&mut reader)?); Ok(SpendDescription { cv, @@ -212,7 +212,15 @@ impl SpendDescription { writer.write_all(&self.nullifier)?; self.rk.write(&mut writer)?; writer.write_all(&self.zkproof)?; - self.spend_auth_sig.write(&mut writer) + match self.spend_auth_sig { + Some(sig) => sig.write(&mut writer), + None => { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Missing spend auth signature", + )) + } + } } }