mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-01-30 23:42:13 +00:00
Merge pull request #65 from str4d/general-refactor
Initial primitives refactor
This commit is contained in:
commit
e4187f07ff
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -230,6 +230,7 @@ dependencies = [
|
|||||||
"pairing 0.14.2",
|
"pairing 0.14.2",
|
||||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sapling-crypto 0.0.1",
|
"sapling-crypto 0.0.1",
|
||||||
|
"zcash_primitives 0.0.0",
|
||||||
"zcash_proofs 0.0.0",
|
"zcash_proofs 0.0.0",
|
||||||
"zip32 0.0.0",
|
"zip32 0.0.0",
|
||||||
]
|
]
|
||||||
@ -445,6 +446,7 @@ name = "zcash_proofs"
|
|||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bellman 0.1.0",
|
"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)",
|
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ff 0.4.0",
|
"ff 0.4.0",
|
||||||
"pairing 0.14.2",
|
"pairing 0.14.2",
|
||||||
@ -465,9 +467,9 @@ dependencies = [
|
|||||||
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ff 0.4.0",
|
"ff 0.4.0",
|
||||||
"fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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",
|
"pairing 0.14.2",
|
||||||
"sapling-crypto 0.0.1",
|
"sapling-crypto 0.0.1",
|
||||||
|
"zcash_primitives 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
|
@ -22,6 +22,7 @@ lazy_static = "1"
|
|||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
rand = "0.4"
|
rand = "0.4"
|
||||||
sapling-crypto = { path = "../sapling-crypto" }
|
sapling-crypto = { path = "../sapling-crypto" }
|
||||||
|
zcash_primitives = { path = "../zcash_primitives" }
|
||||||
zcash_proofs = { path = "../zcash_proofs" }
|
zcash_proofs = { path = "../zcash_proofs" }
|
||||||
zip32 = { path = "../zip32" }
|
zip32 = { path = "../zip32" }
|
||||||
|
|
||||||
|
@ -6,12 +6,10 @@ extern crate libc;
|
|||||||
extern crate pairing;
|
extern crate pairing;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate sapling_crypto;
|
extern crate sapling_crypto;
|
||||||
|
extern crate zcash_primitives;
|
||||||
extern crate zcash_proofs;
|
extern crate zcash_proofs;
|
||||||
extern crate zip32;
|
extern crate zip32;
|
||||||
|
|
||||||
mod hashreader;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
use ff::{BitIterator, PrimeField, PrimeFieldRepr};
|
use ff::{BitIterator, PrimeField, PrimeFieldRepr};
|
||||||
@ -23,7 +21,7 @@ use sapling_crypto::{
|
|||||||
jubjub::{
|
jubjub::{
|
||||||
edwards,
|
edwards,
|
||||||
fs::{Fs, FsRepr},
|
fs::{Fs, FsRepr},
|
||||||
FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown,
|
FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown,
|
||||||
},
|
},
|
||||||
pedersen_hash::{pedersen_hash, Personalization},
|
pedersen_hash::{pedersen_hash, Personalization},
|
||||||
redjubjub::{self, Signature},
|
redjubjub::{self, Signature},
|
||||||
@ -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 sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH};
|
||||||
|
|
||||||
use bellman::groth16::{
|
use bellman::groth16::{
|
||||||
create_random_proof, prepare_verifying_key, verify_proof, Parameters, PreparedVerifyingKey,
|
create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof,
|
||||||
Proof, VerifyingKey,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use blake2_rfc::blake2s::Blake2s;
|
use blake2_rfc::blake2s::Blake2s;
|
||||||
@ -42,7 +39,7 @@ use blake2_rfc::blake2s::Blake2s;
|
|||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
|
||||||
use rand::{OsRng, Rng};
|
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 libc::{c_char, c_uchar, int64_t, size_t, uint32_t, uint64_t};
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
@ -61,8 +58,10 @@ use std::ffi::OsString;
|
|||||||
use std::os::windows::ffi::OsStringExt;
|
use std::os::windows::ffi::OsStringExt;
|
||||||
|
|
||||||
use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey};
|
use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey};
|
||||||
use zcash_proofs::sapling::{
|
use zcash_primitives::{sapling::spend_sig, JUBJUB};
|
||||||
CommitmentTreeWitness, SaplingProvingContext, SaplingVerificationContext,
|
use zcash_proofs::{
|
||||||
|
load_parameters,
|
||||||
|
sapling::{CommitmentTreeWitness, SaplingProvingContext, SaplingVerificationContext},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod equihash;
|
pub mod equihash;
|
||||||
@ -70,10 +69,6 @@ pub mod equihash;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() };
|
|
||||||
}
|
|
||||||
|
|
||||||
static mut SAPLING_SPEND_VK: Option<PreparedVerifyingKey<Bls12>> = None;
|
static mut SAPLING_SPEND_VK: Option<PreparedVerifyingKey<Bls12>> = None;
|
||||||
static mut SAPLING_OUTPUT_VK: Option<PreparedVerifyingKey<Bls12>> = None;
|
static mut SAPLING_OUTPUT_VK: Option<PreparedVerifyingKey<Bls12>> = None;
|
||||||
static mut SPROUT_GROTH16_VK: Option<PreparedVerifyingKey<Bls12>> = None;
|
static mut SPROUT_GROTH16_VK: Option<PreparedVerifyingKey<Bls12>> = None;
|
||||||
@ -199,70 +194,25 @@ fn init_zksnark_params(
|
|||||||
|
|
||||||
let spend_hash = unsafe { CStr::from_ptr(spend_hash) }
|
let spend_hash = unsafe { CStr::from_ptr(spend_hash) }
|
||||||
.to_str()
|
.to_str()
|
||||||
.expect("hash should be a valid string")
|
.expect("hash should be a valid string");
|
||||||
.to_string();
|
|
||||||
|
|
||||||
let output_hash = unsafe { CStr::from_ptr(output_hash) }
|
let output_hash = unsafe { CStr::from_ptr(output_hash) }
|
||||||
.to_str()
|
.to_str()
|
||||||
.expect("hash should be a valid string")
|
.expect("hash should be a valid string");
|
||||||
.to_string();
|
|
||||||
|
|
||||||
let sprout_hash = unsafe { CStr::from_ptr(sprout_hash) }
|
let sprout_hash = unsafe { CStr::from_ptr(sprout_hash) }
|
||||||
.to_str()
|
.to_str()
|
||||||
.expect("hash should be a valid string")
|
.expect("hash should be a valid string");
|
||||||
.to_string();
|
|
||||||
|
|
||||||
// Load from each of the paths
|
// Load params
|
||||||
let spend_fs = File::open(spend_path).expect("couldn't load Sapling spend parameters file");
|
let (spend_params, spend_vk, output_params, output_vk, sprout_vk) = load_parameters(
|
||||||
let output_fs = File::open(output_path).expect("couldn't load Sapling output parameters file");
|
spend_path,
|
||||||
let sprout_fs = File::open(sprout_path).expect("couldn't load Sprout groth16 parameters file");
|
spend_hash,
|
||||||
|
output_path,
|
||||||
let mut spend_fs = hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, spend_fs));
|
output_hash,
|
||||||
let mut output_fs =
|
Some(sprout_path),
|
||||||
hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, output_fs));
|
Some(sprout_hash),
|
||||||
let mut sprout_fs =
|
);
|
||||||
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);
|
|
||||||
let sprout_vk = prepare_verifying_key(&sprout_vk);
|
|
||||||
|
|
||||||
// Caller is responsible for calling this function once, so
|
// Caller is responsible for calling this function once, so
|
||||||
// these global mutations are safe.
|
// these global mutations are safe.
|
||||||
@ -273,7 +223,7 @@ fn init_zksnark_params(
|
|||||||
|
|
||||||
SAPLING_SPEND_VK = Some(spend_vk);
|
SAPLING_SPEND_VK = Some(spend_vk);
|
||||||
SAPLING_OUTPUT_VK = Some(output_vk);
|
SAPLING_OUTPUT_VK = Some(output_vk);
|
||||||
SPROUT_GROTH16_VK = Some(sprout_vk);
|
SPROUT_GROTH16_VK = Some(sprout_vk.unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1069,27 +1019,8 @@ pub extern "system" fn librustzcash_sapling_spend_sig(
|
|||||||
Err(_) => return false,
|
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
|
// Do the signing
|
||||||
let mut rng = OsRng::new().expect("should be able to construct RNG");
|
let sig = spend_sig(ask, ar, unsafe { &*sighash }, &JUBJUB);
|
||||||
let sig = rsk.sign(
|
|
||||||
&data_to_be_signed,
|
|
||||||
&mut rng,
|
|
||||||
FixedGenerators::SpendingKeyGenerator,
|
|
||||||
&JUBJUB,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Write out the signature
|
// Write out the signature
|
||||||
sig.write(&mut (unsafe { &mut *result })[..])
|
sig.write(&mut (unsafe { &mut *result })[..])
|
||||||
|
@ -25,6 +25,7 @@ use std::io::{
|
|||||||
//
|
//
|
||||||
// See "Twisted Edwards Curves Revisited"
|
// See "Twisted Edwards Curves Revisited"
|
||||||
// Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson
|
// Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Point<E: JubjubEngine, Subgroup> {
|
pub struct Point<E: JubjubEngine, Subgroup> {
|
||||||
x: E::Fr,
|
x: E::Fr,
|
||||||
y: E::Fr,
|
y: E::Fr,
|
||||||
|
@ -43,6 +43,7 @@ pub mod fs;
|
|||||||
pub mod tests;
|
pub mod tests;
|
||||||
|
|
||||||
/// Point of unknown order.
|
/// Point of unknown order.
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Unknown { }
|
pub enum Unknown { }
|
||||||
|
|
||||||
/// Point of prime order.
|
/// Point of prime order.
|
||||||
|
@ -29,7 +29,7 @@ fn h_star<E: JubjubEngine>(a: &[u8], b: &[u8]) -> E::Fs {
|
|||||||
hash_to_scalar::<E>(b"Zcash_RedJubjubH", a, b)
|
hash_to_scalar::<E>(b"Zcash_RedJubjubH", a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Signature {
|
pub struct Signature {
|
||||||
rbar: [u8; 32],
|
rbar: [u8; 32],
|
||||||
sbar: [u8; 32],
|
sbar: [u8; 32],
|
||||||
@ -37,6 +37,7 @@ pub struct Signature {
|
|||||||
|
|
||||||
pub struct PrivateKey<E: JubjubEngine>(pub E::Fs);
|
pub struct PrivateKey<E: JubjubEngine>(pub E::Fs);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct PublicKey<E: JubjubEngine>(pub Point<E, Unknown>);
|
pub struct PublicKey<E: JubjubEngine>(pub Point<E, Unknown>);
|
||||||
|
|
||||||
impl Signature {
|
impl Signature {
|
||||||
|
@ -10,9 +10,10 @@ extern crate sapling_crypto;
|
|||||||
|
|
||||||
use sapling_crypto::jubjub::JubjubBls12;
|
use sapling_crypto::jubjub::JubjubBls12;
|
||||||
|
|
||||||
|
pub mod sapling;
|
||||||
mod serialize;
|
mod serialize;
|
||||||
pub mod transaction;
|
pub mod transaction;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() };
|
pub static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() };
|
||||||
}
|
}
|
||||||
|
37
zcash_primitives/src/sapling.rs
Normal file
37
zcash_primitives/src/sapling.rs
Normal file
@ -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<Bls12>,
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
}
|
@ -58,6 +58,7 @@ impl Amount {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Script(pub Vec<u8>);
|
pub struct Script(pub Vec<u8>);
|
||||||
|
|
||||||
impl Script {
|
impl Script {
|
||||||
@ -71,6 +72,7 @@ impl Script {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct OutPoint {
|
pub struct OutPoint {
|
||||||
hash: [u8; 32],
|
hash: [u8; 32],
|
||||||
n: u32,
|
n: u32,
|
||||||
@ -90,6 +92,7 @@ impl OutPoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct TxIn {
|
pub struct TxIn {
|
||||||
pub prevout: OutPoint,
|
pub prevout: OutPoint,
|
||||||
script_sig: Script,
|
script_sig: Script,
|
||||||
@ -116,6 +119,7 @@ impl TxIn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct TxOut {
|
pub struct TxOut {
|
||||||
value: Amount,
|
value: Amount,
|
||||||
script_pubkey: Script,
|
script_pubkey: Script,
|
||||||
@ -144,7 +148,17 @@ pub struct SpendDescription {
|
|||||||
pub nullifier: [u8; 32],
|
pub nullifier: [u8; 32],
|
||||||
pub rk: PublicKey<Bls12>,
|
pub rk: PublicKey<Bls12>,
|
||||||
pub zkproof: [u8; GROTH_PROOF_SIZE],
|
pub zkproof: [u8; GROTH_PROOF_SIZE],
|
||||||
pub spend_auth_sig: Signature,
|
pub spend_auth_sig: Option<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 {
|
impl SpendDescription {
|
||||||
@ -180,7 +194,7 @@ impl SpendDescription {
|
|||||||
// Consensus rules (§4.4):
|
// Consensus rules (§4.4):
|
||||||
// - Canonical encoding is enforced here.
|
// - Canonical encoding is enforced here.
|
||||||
// - Signature validity is enforced in SaplingVerificationContext::check_spend()
|
// - 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 {
|
Ok(SpendDescription {
|
||||||
cv,
|
cv,
|
||||||
@ -198,7 +212,15 @@ impl SpendDescription {
|
|||||||
writer.write_all(&self.nullifier)?;
|
writer.write_all(&self.nullifier)?;
|
||||||
self.rk.write(&mut writer)?;
|
self.rk.write(&mut writer)?;
|
||||||
writer.write_all(&self.zkproof)?;
|
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",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,6 +233,16 @@ pub struct OutputDescription {
|
|||||||
pub zkproof: [u8; GROTH_PROOF_SIZE],
|
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 {
|
impl OutputDescription {
|
||||||
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
|
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
|
||||||
// Consensus rules (§4.5):
|
// Consensus rules (§4.5):
|
||||||
@ -268,6 +300,15 @@ enum SproutProof {
|
|||||||
PHGR([u8; PHGR_PROOF_SIZE]),
|
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 {
|
pub struct JSDescription {
|
||||||
vpub_old: Amount,
|
vpub_old: Amount,
|
||||||
vpub_new: Amount,
|
vpub_new: Amount,
|
||||||
@ -281,6 +322,30 @@ pub struct JSDescription {
|
|||||||
ciphertexts: [[u8; 601]; ZC_NUM_JS_OUTPUTS],
|
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 {
|
impl JSDescription {
|
||||||
pub fn read<R: Read>(mut reader: R, use_groth: bool) -> io::Result<Self> {
|
pub fn read<R: Read>(mut reader: R, use_groth: bool) -> io::Result<Self> {
|
||||||
// Consensus rule (§4.3): Canonical encoding is enforced here
|
// Consensus rule (§4.3): Canonical encoding is enforced here
|
||||||
|
@ -21,6 +21,7 @@ const SAPLING_VERSION_GROUP_ID: u32 = 0x892F2085;
|
|||||||
const SAPLING_TX_VERSION: u32 = 4;
|
const SAPLING_TX_VERSION: u32 = 4;
|
||||||
|
|
||||||
/// A Zcash transaction.
|
/// A Zcash transaction.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Transaction(TransactionData);
|
pub struct Transaction(TransactionData);
|
||||||
|
|
||||||
impl Deref for Transaction {
|
impl Deref for Transaction {
|
||||||
@ -48,6 +49,41 @@ pub struct TransactionData {
|
|||||||
pub binding_sig: Option<Signature>,
|
pub binding_sig: Option<Signature>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
impl TransactionData {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
TransactionData {
|
TransactionData {
|
||||||
|
@ -12,3 +12,7 @@ ff = { path = "../ff" }
|
|||||||
pairing = { path = "../pairing" }
|
pairing = { path = "../pairing" }
|
||||||
rand = "0.4"
|
rand = "0.4"
|
||||||
sapling-crypto = { path = "../sapling-crypto" }
|
sapling-crypto = { path = "../sapling-crypto" }
|
||||||
|
|
||||||
|
[dependencies.blake2-rfc]
|
||||||
|
git = "https://github.com/gtank/blake2-rfc"
|
||||||
|
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
|
||||||
|
@ -1,8 +1,90 @@
|
|||||||
extern crate bellman;
|
extern crate bellman;
|
||||||
|
extern crate blake2_rfc;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate ff;
|
extern crate ff;
|
||||||
extern crate pairing;
|
extern crate pairing;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate sapling_crypto;
|
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 mod sapling;
|
||||||
|
|
||||||
|
pub fn load_parameters(
|
||||||
|
spend_path: &Path,
|
||||||
|
spend_hash: &str,
|
||||||
|
output_path: &Path,
|
||||||
|
output_hash: &str,
|
||||||
|
sprout_path: Option<&Path>,
|
||||||
|
sprout_hash: Option<&str>,
|
||||||
|
) -> (
|
||||||
|
Parameters<Bls12>,
|
||||||
|
PreparedVerifyingKey<Bls12>,
|
||||||
|
Parameters<Bls12>,
|
||||||
|
PreparedVerifyingKey<Bls12>,
|
||||||
|
Option<PreparedVerifyingKey<Bls12>>,
|
||||||
|
) {
|
||||||
|
// 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 =
|
||||||
|
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 =
|
||||||
|
sprout_fs.map(|fs| hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, 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 = sprout_fs.as_mut().map(|mut fs| {
|
||||||
|
VerifyingKey::<Bls12>::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
|
||||||
|
// 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");
|
||||||
|
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`.");
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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 = sprout_vk.map(|vk| prepare_verifying_key(&vk));
|
||||||
|
|
||||||
|
(spend_params, spend_vk, output_params, output_vk, sprout_vk)
|
||||||
|
}
|
||||||
|
@ -16,9 +16,9 @@ aes = "0.2"
|
|||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
ff = { path = "../ff" }
|
ff = { path = "../ff" }
|
||||||
fpe = "0.1"
|
fpe = "0.1"
|
||||||
lazy_static = "1.0"
|
|
||||||
pairing = { path = "../pairing" }
|
pairing = { path = "../pairing" }
|
||||||
sapling-crypto = { path = "../sapling-crypto" }
|
sapling-crypto = { path = "../sapling-crypto" }
|
||||||
|
zcash_primitives = { path = "../zcash_primitives" }
|
||||||
|
|
||||||
[dependencies.blake2-rfc]
|
[dependencies.blake2-rfc]
|
||||||
git = "https://github.com/gtank/blake2-rfc"
|
git = "https://github.com/gtank/blake2-rfc"
|
||||||
|
@ -3,10 +3,9 @@ extern crate blake2_rfc;
|
|||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate ff;
|
extern crate ff;
|
||||||
extern crate fpe;
|
extern crate fpe;
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
extern crate pairing;
|
extern crate pairing;
|
||||||
extern crate sapling_crypto;
|
extern crate sapling_crypto;
|
||||||
|
extern crate zcash_primitives;
|
||||||
|
|
||||||
use aes::Aes256;
|
use aes::Aes256;
|
||||||
use blake2_rfc::blake2b::{Blake2b, Blake2bResult};
|
use blake2_rfc::blake2b::{Blake2b, Blake2bResult};
|
||||||
@ -15,16 +14,11 @@ use ff::{Field, PrimeField, PrimeFieldRepr};
|
|||||||
use fpe::ff1::{BinaryNumeralString, FF1};
|
use fpe::ff1::{BinaryNumeralString, FF1};
|
||||||
use pairing::bls12_381::Bls12;
|
use pairing::bls12_381::Bls12;
|
||||||
use sapling_crypto::{
|
use sapling_crypto::{
|
||||||
jubjub::{
|
jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, ToUniform, Unknown},
|
||||||
edwards, FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, ToUniform, Unknown,
|
primitives::{Diversifier, PaymentAddress, ProofGenerationKey, ViewingKey},
|
||||||
},
|
|
||||||
primitives::{Diversifier, PaymentAddress, ViewingKey},
|
|
||||||
};
|
};
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
|
use zcash_primitives::JUBJUB;
|
||||||
lazy_static! {
|
|
||||||
static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed";
|
pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed";
|
||||||
pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &'static [u8; 16] = b"ZcashIP32Sapling";
|
pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &'static [u8; 16] = b"ZcashIP32Sapling";
|
||||||
@ -48,7 +42,7 @@ fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bResult {
|
|||||||
|
|
||||||
/// An outgoing viewing key
|
/// An outgoing viewing key
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
struct OutgoingViewingKey([u8; 32]);
|
pub struct OutgoingViewingKey([u8; 32]);
|
||||||
|
|
||||||
impl OutgoingViewingKey {
|
impl OutgoingViewingKey {
|
||||||
fn derive_child(&self, i_l: &[u8]) -> Self {
|
fn derive_child(&self, i_l: &[u8]) -> Self {
|
||||||
@ -61,15 +55,15 @@ impl OutgoingViewingKey {
|
|||||||
/// A Sapling expanded spending key
|
/// A Sapling expanded spending key
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ExpandedSpendingKey<E: JubjubEngine> {
|
pub struct ExpandedSpendingKey<E: JubjubEngine> {
|
||||||
ask: E::Fs,
|
pub ask: E::Fs,
|
||||||
nsk: E::Fs,
|
nsk: E::Fs,
|
||||||
ovk: OutgoingViewingKey,
|
ovk: OutgoingViewingKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Sapling full viewing key
|
/// A Sapling full viewing key
|
||||||
pub struct FullViewingKey<E: JubjubEngine> {
|
pub struct FullViewingKey<E: JubjubEngine> {
|
||||||
vk: ViewingKey<E>,
|
pub vk: ViewingKey<E>,
|
||||||
ovk: OutgoingViewingKey,
|
pub ovk: OutgoingViewingKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: JubjubEngine> ExpandedSpendingKey<E> {
|
impl<E: JubjubEngine> ExpandedSpendingKey<E> {
|
||||||
@ -82,6 +76,15 @@ impl<E: JubjubEngine> ExpandedSpendingKey<E> {
|
|||||||
ExpandedSpendingKey { ask, nsk, ovk }
|
ExpandedSpendingKey { ask, nsk, ovk }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn proof_generation_key(&self, params: &E::Params) -> ProofGenerationKey<E> {
|
||||||
|
ProofGenerationKey {
|
||||||
|
ak: params
|
||||||
|
.generator(FixedGenerators::SpendingKeyGenerator)
|
||||||
|
.mul(self.ask, params),
|
||||||
|
nsk: self.nsk,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn derive_child(&self, i_l: &[u8]) -> Self {
|
fn derive_child(&self, i_l: &[u8]) -> Self {
|
||||||
let mut ask = E::Fs::to_uniform(prf_expand(i_l, &[0x13]).as_bytes());
|
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());
|
let mut nsk = E::Fs::to_uniform(prf_expand(i_l, &[0x14]).as_bytes());
|
||||||
@ -128,6 +131,18 @@ impl<E: JubjubEngine> ExpandedSpendingKey<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: JubjubEngine> Clone for FullViewingKey<E> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
FullViewingKey {
|
||||||
|
vk: ViewingKey {
|
||||||
|
ak: self.vk.ak.clone(),
|
||||||
|
nk: self.vk.nk.clone(),
|
||||||
|
},
|
||||||
|
ovk: self.ovk.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<E: JubjubEngine> FullViewingKey<E> {
|
impl<E: JubjubEngine> FullViewingKey<E> {
|
||||||
fn from_expanded_spending_key(expsk: &ExpandedSpendingKey<E>, params: &E::Params) -> Self {
|
fn from_expanded_spending_key(expsk: &ExpandedSpendingKey<E>, params: &E::Params) -> Self {
|
||||||
FullViewingKey {
|
FullViewingKey {
|
||||||
@ -348,6 +363,7 @@ pub struct ExtendedSpendingKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A Sapling extended full viewing key
|
// A Sapling extended full viewing key
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ExtendedFullViewingKey {
|
pub struct ExtendedFullViewingKey {
|
||||||
depth: u8,
|
depth: u8,
|
||||||
parent_fvk_tag: FVKTag,
|
parent_fvk_tag: FVKTag,
|
||||||
|
Loading…
Reference in New Issue
Block a user