TxProver trait to abstract over the circuit parameters

An implementation using local parameters is provided in the zcash_proofs
crate.
This commit is contained in:
Jack Grigg 2018-11-18 11:20:59 +00:00
parent 05f098e893
commit 01618038bf
No known key found for this signature in database
GPG Key ID: 9E8255172BBF9898
7 changed files with 390 additions and 1 deletions

33
Cargo.lock generated
View File

@ -185,6 +185,15 @@ dependencies = [
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "directories"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fake-simd"
version = "0.1.2"
@ -531,6 +540,25 @@ name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "zcash_client_backend"
version = "0.0.0"
@ -569,6 +597,7 @@ dependencies = [
"bellman 0.1.0",
"blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ff 0.4.0",
"pairing 0.14.2",
"rand_os 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -600,6 +629,7 @@ dependencies = [
"checksum crypto_api_chachapoly 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9ee35dbace0831b5fe7cb9b43eb029aa14a10f594a115025d4628a2baa63ab"
"checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603"
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
"checksum directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72d337a64190607d4fcca2cb78982c5dd57f4916e19696b48a575fa746b6cb0f"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
"checksum fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce3371c82bfbd984f624cab093f55e7336f5a6e589f8518e1258f54f011b89ad"
"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c"
@ -636,3 +666,6 @@ dependencies = [
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -20,6 +20,7 @@ pub mod block;
pub mod keys;
pub mod merkle_tree;
pub mod note_encryption;
pub mod prover;
pub mod sapling;
mod serialize;
pub mod transaction;

View File

@ -0,0 +1,162 @@
//! Abstractions over the proving system and parameters.
use pairing::bls12_381::{Bls12, Fr};
use sapling_crypto::{
jubjub::{edwards, fs::Fs, Unknown},
primitives::{Diversifier, PaymentAddress, ProofGenerationKey},
redjubjub::{PublicKey, Signature},
};
use crate::{
merkle_tree::CommitmentTreeWitness, sapling::Node, transaction::components::GROTH_PROOF_SIZE,
};
/// Interface for creating zero-knowledge proofs for shielded transactions.
pub trait TxProver {
/// Type for persisting any necessary context across multiple Sapling proofs.
type SaplingProvingContext;
/// Instantiate a new Sapling proving context.
fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext;
/// Create the value commitment, re-randomized key, and proof for a Sapling
/// [`SpendDescription`], while accumulating its value commitment randomness inside
/// the context for later use.
///
/// [`SpendDescription`]: crate::transaction::components::SpendDescription
fn spend_proof(
&self,
ctx: &mut Self::SaplingProvingContext,
proof_generation_key: ProofGenerationKey<Bls12>,
diversifier: Diversifier,
rcm: Fs,
ar: Fs,
value: u64,
anchor: Fr,
witness: CommitmentTreeWitness<Node>,
) -> Result<
(
[u8; GROTH_PROOF_SIZE],
edwards::Point<Bls12, Unknown>,
PublicKey<Bls12>,
),
(),
>;
/// Create the value commitment and proof for a Sapling [`OutputDescription`],
/// while accumulating its value commitment randomness inside the context for later
/// use.
///
/// [`OutputDescription`]: crate::transaction::components::OutputDescription
fn output_proof(
&self,
ctx: &mut Self::SaplingProvingContext,
esk: Fs,
payment_address: PaymentAddress<Bls12>,
rcm: Fs,
value: u64,
) -> ([u8; GROTH_PROOF_SIZE], edwards::Point<Bls12, Unknown>);
/// Create the `bindingSig` for a Sapling transaction. All calls to
/// [`TxProver::spend_proof`] and [`TxProver::output_proof`] must be completed before
/// calling this function.
fn binding_sig(
&self,
ctx: &mut Self::SaplingProvingContext,
value_balance: i64,
sighash: &[u8; 32],
) -> Result<Signature, ()>;
}
#[cfg(test)]
pub(crate) mod mock {
use ff::Field;
use pairing::bls12_381::{Bls12, Fr};
use rand_os::OsRng;
use sapling_crypto::{
jubjub::{edwards, fs::Fs, FixedGenerators, Unknown},
primitives::{Diversifier, PaymentAddress, ProofGenerationKey, ValueCommitment},
redjubjub::{PublicKey, Signature},
};
use crate::{
merkle_tree::CommitmentTreeWitness, sapling::Node,
transaction::components::GROTH_PROOF_SIZE, JUBJUB,
};
use super::TxProver;
pub(crate) struct MockTxProver;
#[cfg(test)]
impl TxProver for MockTxProver {
type SaplingProvingContext = ();
fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext {}
fn spend_proof(
&self,
_ctx: &mut Self::SaplingProvingContext,
proof_generation_key: ProofGenerationKey<Bls12>,
_diversifier: Diversifier,
_rcm: Fs,
ar: Fs,
value: u64,
_anchor: Fr,
_witness: CommitmentTreeWitness<Node>,
) -> Result<
(
[u8; GROTH_PROOF_SIZE],
edwards::Point<Bls12, Unknown>,
PublicKey<Bls12>,
),
(),
> {
let mut rng = OsRng;
let cv = ValueCommitment::<Bls12> {
value,
randomness: Fs::random(&mut rng),
}
.cm(&JUBJUB)
.into();
let rk = PublicKey::<Bls12>(proof_generation_key.ak.clone().into()).randomize(
ar,
FixedGenerators::SpendingKeyGenerator,
&JUBJUB,
);
Ok(([0u8; GROTH_PROOF_SIZE], cv, rk))
}
fn output_proof(
&self,
_ctx: &mut Self::SaplingProvingContext,
_esk: Fs,
_payment_address: PaymentAddress<Bls12>,
_rcm: Fs,
value: u64,
) -> ([u8; GROTH_PROOF_SIZE], edwards::Point<Bls12, Unknown>) {
let mut rng = OsRng;
let cv = ValueCommitment::<Bls12> {
value,
randomness: Fs::random(&mut rng),
}
.cm(&JUBJUB)
.into();
([0u8; GROTH_PROOF_SIZE], cv)
}
fn binding_sig(
&self,
_ctx: &mut Self::SaplingProvingContext,
_value_balance: i64,
_sighash: &[u8; 32],
) -> Result<Signature, ()> {
Err(())
}
}
}

View File

@ -11,7 +11,7 @@ use serialize::Vector;
use JUBJUB;
// π_A + π_B + π_C
const GROTH_PROOF_SIZE: usize = (48 + 96 + 48);
pub const GROTH_PROOF_SIZE: usize = (48 + 96 + 48);
// π_A + π_A' + π_B + π_B' + π_C + π_C' + π_K + π_H
const PHGR_PROOF_SIZE: usize = (33 + 33 + 65 + 33 + 33 + 33 + 33 + 33);

View File

@ -9,6 +9,7 @@ authors = [
bellman = { path = "../bellman" }
blake2b_simd = "0.5"
byteorder = "1"
directories = "1"
ff = { path = "../ff" }
pairing = { path = "../pairing" }
rand_os = "0.2"

View File

@ -1,6 +1,7 @@
extern crate bellman;
extern crate blake2b_simd;
extern crate byteorder;
extern crate directories;
extern crate ff;
extern crate pairing;
extern crate rand_os;
@ -14,6 +15,7 @@ use std::io::{self, BufReader};
use std::path::Path;
mod hashreader;
pub mod prover;
pub mod sapling;
pub fn load_parameters(

190
zcash_proofs/src/prover.rs Normal file
View File

@ -0,0 +1,190 @@
//! Abstractions over the proving system and parameters for ease of use.
use bellman::groth16::{Parameters, PreparedVerifyingKey};
use directories::BaseDirs;
use pairing::bls12_381::{Bls12, Fr};
use sapling_crypto::{
jubjub::{edwards, fs::Fs, Unknown},
primitives::{Diversifier, PaymentAddress, ProofGenerationKey},
redjubjub::{PublicKey, Signature},
};
use std::path::Path;
use zcash_primitives::{
merkle_tree::CommitmentTreeWitness, prover::TxProver, sapling::Node,
transaction::components::GROTH_PROOF_SIZE, JUBJUB,
};
use crate::{load_parameters, sapling::SaplingProvingContext};
const SAPLING_SPEND_HASH: &str = "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c";
const SAPLING_OUTPUT_HASH: &str = "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028";
/// An implementation of [`TxProver`] using Sapling Spend and Output parameters from
/// locally-accessible paths.
pub struct LocalTxProver {
spend_params: Parameters<Bls12>,
spend_vk: PreparedVerifyingKey<Bls12>,
output_params: Parameters<Bls12>,
}
impl LocalTxProver {
/// Creates a `LocalTxProver` using parameters from the given local paths.
///
/// # Examples
///
/// ```should_panic
/// use std::path::Path;
/// use zcash_proofs::prover::LocalTxProver;
///
/// let tx_prover = LocalTxProver::new(
/// Path::new("/path/to/sapling-spend.params"),
/// Path::new("/path/to/sapling-output.params"),
/// );
/// ```
///
/// # Panics
///
/// This function will panic if the paths do not point to valid parameter files with
/// the expected hashes.
pub fn new(spend_path: &Path, output_path: &Path) -> Self {
let (spend_params, spend_vk, output_params, _, _) = load_parameters(
spend_path,
SAPLING_SPEND_HASH,
output_path,
SAPLING_OUTPUT_HASH,
None,
None,
);
LocalTxProver {
spend_params,
spend_vk,
output_params,
}
}
/// Attempts to create a `LocalTxProver` using parameters from the default local
/// location.
///
/// Returns `None` if any of the parameters cannot be found in the default local
/// location.
///
/// # Examples
///
/// ```
/// use zcash_proofs::prover::LocalTxProver;
///
/// match LocalTxProver::with_default_location() {
/// Some(tx_prover) => (),
/// None => println!("Please run zcash-fetch-params or fetch-params.sh to download the parameters."),
/// }
/// ```
///
/// # Panics
///
/// This function will panic if the parameters in the default local location do not
/// have the expected hashes.
pub fn with_default_location() -> Option<Self> {
let base_dirs = BaseDirs::new()?;
let unix_params_dir = base_dirs.home_dir().join(".zcash-params");
let win_osx_params_dir = base_dirs.data_dir().join("ZcashParams");
let (spend_path, output_path) = if unix_params_dir.exists() {
(
unix_params_dir.join("sapling-spend.params"),
unix_params_dir.join("sapling-output.params"),
)
} else if win_osx_params_dir.exists() {
(
win_osx_params_dir.join("sapling-spend.params"),
win_osx_params_dir.join("sapling-output.params"),
)
} else {
return None;
};
if !(spend_path.exists() && output_path.exists()) {
return None;
}
Some(LocalTxProver::new(&spend_path, &output_path))
}
}
impl TxProver for LocalTxProver {
type SaplingProvingContext = SaplingProvingContext;
fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext {
SaplingProvingContext::new()
}
fn spend_proof(
&self,
ctx: &mut Self::SaplingProvingContext,
proof_generation_key: ProofGenerationKey<Bls12>,
diversifier: Diversifier,
rcm: Fs,
ar: Fs,
value: u64,
anchor: Fr,
witness: CommitmentTreeWitness<Node>,
) -> Result<
(
[u8; GROTH_PROOF_SIZE],
edwards::Point<Bls12, Unknown>,
PublicKey<Bls12>,
),
(),
> {
let (proof, cv, rk) = ctx.spend_proof(
proof_generation_key,
diversifier,
rcm,
ar,
value,
anchor,
witness,
&self.spend_params,
&self.spend_vk,
&JUBJUB,
)?;
let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof
.write(&mut zkproof[..])
.expect("should be able to serialize a proof");
Ok((zkproof, cv, rk))
}
fn output_proof(
&self,
ctx: &mut Self::SaplingProvingContext,
esk: Fs,
payment_address: PaymentAddress<Bls12>,
rcm: Fs,
value: u64,
) -> ([u8; GROTH_PROOF_SIZE], edwards::Point<Bls12, Unknown>) {
let (proof, cv) = ctx.output_proof(
esk,
payment_address,
rcm,
value,
&self.output_params,
&JUBJUB,
);
let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof
.write(&mut zkproof[..])
.expect("should be able to serialize a proof");
(zkproof, cv)
}
fn binding_sig(
&self,
ctx: &mut Self::SaplingProvingContext,
value_balance: i64,
sighash: &[u8; 32],
) -> Result<Signature, ()> {
ctx.binding_sig(value_balance, sighash, &JUBJUB)
}
}