mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-02-22 05:45:47 +00:00
Move Sapling verification checks into zcash_proofs crate
This commit is contained in:
parent
eb2db2e667
commit
e1841806c5
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -344,6 +344,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_proofs 0.0.0",
|
||||||
"zip32 0.0.0",
|
"zip32 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -716,6 +717,11 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "zcash_proofs"
|
name = "zcash_proofs"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"bellman 0.1.0",
|
||||||
|
"pairing 0.14.2",
|
||||||
|
"sapling-crypto 0.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zcash_wallet"
|
name = "zcash_wallet"
|
||||||
|
@ -21,6 +21,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_proofs = { path = "../zcash_proofs" }
|
||||||
zip32 = { path = "../zip32" }
|
zip32 = { path = "../zip32" }
|
||||||
|
|
||||||
[dependencies.blake2-rfc]
|
[dependencies.blake2-rfc]
|
||||||
|
@ -5,6 +5,7 @@ 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_proofs;
|
||||||
extern crate zip32;
|
extern crate zip32;
|
||||||
|
|
||||||
mod hashreader;
|
mod hashreader;
|
||||||
@ -62,6 +63,7 @@ use std::ffi::OsString;
|
|||||||
use std::os::windows::ffi::OsStringExt;
|
use std::os::windows::ffi::OsStringExt;
|
||||||
|
|
||||||
use sapling_crypto::primitives::{ProofGenerationKey, ValueCommitment, ViewingKey};
|
use sapling_crypto::primitives::{ProofGenerationKey, ValueCommitment, ViewingKey};
|
||||||
|
use zcash_proofs::sapling::{compute_value_balance, SaplingVerificationContext};
|
||||||
|
|
||||||
pub mod equihash;
|
pub mod equihash;
|
||||||
|
|
||||||
@ -80,10 +82,6 @@ static mut SAPLING_SPEND_PARAMS: Option<Parameters<Bls12>> = None;
|
|||||||
static mut SAPLING_OUTPUT_PARAMS: Option<Parameters<Bls12>> = None;
|
static mut SAPLING_OUTPUT_PARAMS: Option<Parameters<Bls12>> = None;
|
||||||
static mut SPROUT_GROTH16_PARAMS_PATH: Option<PathBuf> = None;
|
static mut SPROUT_GROTH16_PARAMS_PATH: Option<PathBuf> = None;
|
||||||
|
|
||||||
fn is_small_order<Order>(p: &edwards::Point<Bls12, Order>) -> bool {
|
|
||||||
p.double(&JUBJUB).double(&JUBJUB).double(&JUBJUB) == edwards::Point::zero()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes an FrRepr to [u8] of length 32
|
/// Writes an FrRepr to [u8] of length 32
|
||||||
fn write_le(f: FrRepr, to: &mut [u8]) {
|
fn write_le(f: FrRepr, to: &mut [u8]) {
|
||||||
assert_eq!(to.len(), 32);
|
assert_eq!(to.len(), 32);
|
||||||
@ -648,16 +646,10 @@ pub extern "system" fn librustzcash_eh_isvalid(
|
|||||||
equihash::is_valid_solution(n, k, rs_input, rs_nonce, rs_soln)
|
equihash::is_valid_solution(n, k, rs_input, rs_nonce, rs_soln)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SaplingVerificationContext {
|
|
||||||
bvk: edwards::Point<Bls12, Unknown>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "system" fn librustzcash_sapling_verification_ctx_init(
|
pub extern "system" fn librustzcash_sapling_verification_ctx_init(
|
||||||
) -> *mut SaplingVerificationContext {
|
) -> *mut SaplingVerificationContext {
|
||||||
let ctx = Box::new(SaplingVerificationContext {
|
let ctx = Box::new(SaplingVerificationContext::new());
|
||||||
bvk: edwards::Point::zero(),
|
|
||||||
});
|
|
||||||
|
|
||||||
Box::into_raw(ctx)
|
Box::into_raw(ctx)
|
||||||
}
|
}
|
||||||
@ -715,79 +707,17 @@ pub extern "system" fn librustzcash_sapling_check_spend(
|
|||||||
Err(_) => return false,
|
Err(_) => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_small_order(&cv) {
|
unsafe { &mut *ctx }.check_spend(
|
||||||
return false;
|
cv,
|
||||||
}
|
anchor,
|
||||||
|
unsafe { &*nullifier },
|
||||||
if is_small_order(&rk.0) {
|
rk,
|
||||||
return false;
|
unsafe { &*sighash_value },
|
||||||
}
|
spend_auth_sig,
|
||||||
|
zkproof,
|
||||||
// Accumulate the value commitment in the context
|
|
||||||
{
|
|
||||||
let mut tmp = cv.clone();
|
|
||||||
tmp = tmp.add(&unsafe { &*ctx }.bvk, &JUBJUB);
|
|
||||||
|
|
||||||
// Update the context
|
|
||||||
unsafe { &mut *ctx }.bvk = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grab the nullifier as a sequence of bytes
|
|
||||||
let nullifier = &unsafe { &*nullifier }[..];
|
|
||||||
|
|
||||||
// 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_value })[..]);
|
|
||||||
|
|
||||||
// Verify the spend_auth_sig
|
|
||||||
if !rk.verify(
|
|
||||||
&data_to_be_signed,
|
|
||||||
&spend_auth_sig,
|
|
||||||
FixedGenerators::SpendingKeyGenerator,
|
|
||||||
&JUBJUB,
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct public input for circuit
|
|
||||||
let mut public_input = [Fr::zero(); 7];
|
|
||||||
{
|
|
||||||
let (x, y) = rk.0.into_xy();
|
|
||||||
public_input[0] = x;
|
|
||||||
public_input[1] = y;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let (x, y) = cv.into_xy();
|
|
||||||
public_input[2] = x;
|
|
||||||
public_input[3] = y;
|
|
||||||
}
|
|
||||||
public_input[4] = anchor;
|
|
||||||
|
|
||||||
// Add the nullifier through multiscalar packing
|
|
||||||
{
|
|
||||||
let nullifier = multipack::bytes_to_bits_le(nullifier);
|
|
||||||
let nullifier = multipack::compute_multipacking::<Bls12>(&nullifier);
|
|
||||||
|
|
||||||
assert_eq!(nullifier.len(), 2);
|
|
||||||
|
|
||||||
public_input[5] = nullifier[0];
|
|
||||||
public_input[6] = nullifier[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the proof
|
|
||||||
match verify_proof(
|
|
||||||
unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(),
|
unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(),
|
||||||
&zkproof,
|
&JUBJUB,
|
||||||
&public_input[..],
|
)
|
||||||
) {
|
|
||||||
// No error, and proof verification successful
|
|
||||||
Ok(true) => true,
|
|
||||||
|
|
||||||
// Any other case
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -823,76 +753,14 @@ pub extern "system" fn librustzcash_sapling_check_output(
|
|||||||
Err(_) => return false,
|
Err(_) => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_small_order(&cv) {
|
unsafe { &mut *ctx }.check_output(
|
||||||
return false;
|
cv,
|
||||||
}
|
cm,
|
||||||
|
epk,
|
||||||
if is_small_order(&epk) {
|
zkproof,
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accumulate the value commitment in the context
|
|
||||||
{
|
|
||||||
let mut tmp = cv.clone();
|
|
||||||
tmp = tmp.negate(); // Outputs subtract from the total.
|
|
||||||
tmp = tmp.add(&unsafe { &*ctx }.bvk, &JUBJUB);
|
|
||||||
|
|
||||||
// Update the context
|
|
||||||
unsafe { &mut *ctx }.bvk = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct public input for circuit
|
|
||||||
let mut public_input = [Fr::zero(); 5];
|
|
||||||
{
|
|
||||||
let (x, y) = cv.into_xy();
|
|
||||||
public_input[0] = x;
|
|
||||||
public_input[1] = y;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let (x, y) = epk.into_xy();
|
|
||||||
public_input[2] = x;
|
|
||||||
public_input[3] = y;
|
|
||||||
}
|
|
||||||
public_input[4] = cm;
|
|
||||||
|
|
||||||
// Verify the proof
|
|
||||||
match verify_proof(
|
|
||||||
unsafe { SAPLING_OUTPUT_VK.as_ref() }.unwrap(),
|
unsafe { SAPLING_OUTPUT_VK.as_ref() }.unwrap(),
|
||||||
&zkproof,
|
&JUBJUB,
|
||||||
&public_input[..],
|
)
|
||||||
) {
|
|
||||||
// No error, and proof verification successful
|
|
||||||
Ok(true) => true,
|
|
||||||
|
|
||||||
// Any other case
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function computes `value` in the exponent of the value commitment base
|
|
||||||
fn compute_value_balance(value: int64_t) -> Option<edwards::Point<Bls12, Unknown>> {
|
|
||||||
// Compute the absolute value (failing if -i64::MAX is
|
|
||||||
// the value)
|
|
||||||
let abs = match value.checked_abs() {
|
|
||||||
Some(a) => a as u64,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Is it negative? We'll have to negate later if so.
|
|
||||||
let is_negative = value.is_negative();
|
|
||||||
|
|
||||||
// Compute it in the exponent
|
|
||||||
let mut value_balance = JUBJUB
|
|
||||||
.generator(FixedGenerators::ValueCommitmentValue)
|
|
||||||
.mul(FsRepr::from(abs), &JUBJUB);
|
|
||||||
|
|
||||||
// Negate if necessary
|
|
||||||
if is_negative {
|
|
||||||
value_balance = value_balance.negate();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to unknown order point
|
|
||||||
Some(value_balance.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -908,37 +776,12 @@ pub extern "system" fn librustzcash_sapling_final_check(
|
|||||||
Err(_) => return false,
|
Err(_) => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Obtain current bvk from the context
|
unsafe { &*ctx }.final_check(
|
||||||
let mut bvk = redjubjub::PublicKey(unsafe { &*ctx }.bvk.clone());
|
value_balance,
|
||||||
|
unsafe { &*sighash_value },
|
||||||
// Compute value balance
|
binding_sig,
|
||||||
let mut value_balance = match compute_value_balance(value_balance) {
|
|
||||||
Some(a) => a,
|
|
||||||
None => return false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Subtract value_balance from current bvk to get final bvk
|
|
||||||
value_balance = value_balance.negate();
|
|
||||||
bvk.0 = bvk.0.add(&value_balance, &JUBJUB);
|
|
||||||
|
|
||||||
// Compute the signature's message for bvk/binding_sig
|
|
||||||
let mut data_to_be_signed = [0u8; 64];
|
|
||||||
bvk.0
|
|
||||||
.write(&mut data_to_be_signed[0..32])
|
|
||||||
.expect("bvk is 32 bytes");
|
|
||||||
(&mut data_to_be_signed[32..64]).copy_from_slice(&(unsafe { &*sighash_value })[..]);
|
|
||||||
|
|
||||||
// Verify the binding_sig
|
|
||||||
if !bvk.verify(
|
|
||||||
&data_to_be_signed,
|
|
||||||
&binding_sig,
|
|
||||||
FixedGenerators::ValueCommitmentRandomness,
|
|
||||||
&JUBJUB,
|
&JUBJUB,
|
||||||
) {
|
)
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -1324,7 +1167,7 @@ pub extern "system" fn librustzcash_sapling_binding_sig(
|
|||||||
// against our derived bvk.
|
// against our derived bvk.
|
||||||
{
|
{
|
||||||
// Compute value balance
|
// Compute value balance
|
||||||
let mut value_balance = match compute_value_balance(value_balance) {
|
let mut value_balance = match compute_value_balance(value_balance, &JUBJUB) {
|
||||||
Some(a) => a,
|
Some(a) => a,
|
||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
|
@ -6,3 +6,6 @@ authors = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bellman = { path = "../bellman" }
|
||||||
|
pairing = { path = "../pairing" }
|
||||||
|
sapling-crypto = { path = "../sapling-crypto" }
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
#[cfg(test)]
|
extern crate bellman;
|
||||||
mod tests {
|
extern crate pairing;
|
||||||
#[test]
|
extern crate sapling_crypto;
|
||||||
fn it_works() {
|
|
||||||
assert_eq!(2 + 2, 4);
|
pub mod sapling;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
37
zcash_proofs/src/sapling/mod.rs
Normal file
37
zcash_proofs/src/sapling/mod.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use pairing::bls12_381::Bls12;
|
||||||
|
use sapling_crypto::jubjub::{
|
||||||
|
edwards, fs::FsRepr, FixedGenerators, JubjubBls12, JubjubParams, Unknown,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod verifier;
|
||||||
|
|
||||||
|
pub use self::verifier::SaplingVerificationContext;
|
||||||
|
|
||||||
|
// This function computes `value` in the exponent of the value commitment base
|
||||||
|
pub fn compute_value_balance(
|
||||||
|
value: i64,
|
||||||
|
params: &JubjubBls12,
|
||||||
|
) -> Option<edwards::Point<Bls12, Unknown>> {
|
||||||
|
// Compute the absolute value (failing if -i64::MAX is
|
||||||
|
// the value)
|
||||||
|
let abs = match value.checked_abs() {
|
||||||
|
Some(a) => a as u64,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Is it negative? We'll have to negate later if so.
|
||||||
|
let is_negative = value.is_negative();
|
||||||
|
|
||||||
|
// Compute it in the exponent
|
||||||
|
let mut value_balance = params
|
||||||
|
.generator(FixedGenerators::ValueCommitmentValue)
|
||||||
|
.mul(FsRepr::from(abs), params);
|
||||||
|
|
||||||
|
// Negate if necessary
|
||||||
|
if is_negative {
|
||||||
|
value_balance = value_balance.negate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to unknown order point
|
||||||
|
Some(value_balance.into())
|
||||||
|
}
|
207
zcash_proofs/src/sapling/verifier.rs
Normal file
207
zcash_proofs/src/sapling/verifier.rs
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
use bellman::groth16::{verify_proof, PreparedVerifyingKey, Proof};
|
||||||
|
use pairing::{
|
||||||
|
bls12_381::{Bls12, Fr},
|
||||||
|
Field,
|
||||||
|
};
|
||||||
|
use sapling_crypto::{
|
||||||
|
circuit::multipack,
|
||||||
|
jubjub::{edwards, FixedGenerators, JubjubBls12, Unknown},
|
||||||
|
redjubjub::{PublicKey, Signature},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::compute_value_balance;
|
||||||
|
|
||||||
|
fn is_small_order<Order>(p: &edwards::Point<Bls12, Order>, params: &JubjubBls12) -> bool {
|
||||||
|
p.double(params).double(params).double(params) == edwards::Point::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A context object for verifying the Sapling components of a Zcash transaction.
|
||||||
|
pub struct SaplingVerificationContext {
|
||||||
|
bvk: edwards::Point<Bls12, Unknown>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SaplingVerificationContext {
|
||||||
|
/// Construct a new context to be used with a single transaction.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
SaplingVerificationContext {
|
||||||
|
bvk: edwards::Point::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform consensus checks on a Sapling SpendDescription, while
|
||||||
|
/// accumulating its value commitment inside the context for later use.
|
||||||
|
pub fn check_spend(
|
||||||
|
&mut self,
|
||||||
|
cv: edwards::Point<Bls12, Unknown>,
|
||||||
|
anchor: Fr,
|
||||||
|
nullifier: &[u8; 32],
|
||||||
|
rk: PublicKey<Bls12>,
|
||||||
|
sighash_value: &[u8; 32],
|
||||||
|
spend_auth_sig: Signature,
|
||||||
|
zkproof: Proof<Bls12>,
|
||||||
|
verifying_key: &PreparedVerifyingKey<Bls12>,
|
||||||
|
params: &JubjubBls12,
|
||||||
|
) -> bool {
|
||||||
|
if is_small_order(&cv, params) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_small_order(&rk.0, params) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accumulate the value commitment in the context
|
||||||
|
{
|
||||||
|
let mut tmp = cv.clone();
|
||||||
|
tmp = tmp.add(&self.bvk, params);
|
||||||
|
|
||||||
|
// Update the context
|
||||||
|
self.bvk = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the nullifier as a sequence of bytes
|
||||||
|
let nullifier = &nullifier[..];
|
||||||
|
|
||||||
|
// 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_value[..]);
|
||||||
|
|
||||||
|
// Verify the spend_auth_sig
|
||||||
|
if !rk.verify(
|
||||||
|
&data_to_be_signed,
|
||||||
|
&spend_auth_sig,
|
||||||
|
FixedGenerators::SpendingKeyGenerator,
|
||||||
|
params,
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct public input for circuit
|
||||||
|
let mut public_input = [Fr::zero(); 7];
|
||||||
|
{
|
||||||
|
let (x, y) = rk.0.into_xy();
|
||||||
|
public_input[0] = x;
|
||||||
|
public_input[1] = y;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let (x, y) = cv.into_xy();
|
||||||
|
public_input[2] = x;
|
||||||
|
public_input[3] = y;
|
||||||
|
}
|
||||||
|
public_input[4] = anchor;
|
||||||
|
|
||||||
|
// Add the nullifier through multiscalar packing
|
||||||
|
{
|
||||||
|
let nullifier = multipack::bytes_to_bits_le(nullifier);
|
||||||
|
let nullifier = multipack::compute_multipacking::<Bls12>(&nullifier);
|
||||||
|
|
||||||
|
assert_eq!(nullifier.len(), 2);
|
||||||
|
|
||||||
|
public_input[5] = nullifier[0];
|
||||||
|
public_input[6] = nullifier[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the proof
|
||||||
|
match verify_proof(verifying_key, &zkproof, &public_input[..]) {
|
||||||
|
// No error, and proof verification successful
|
||||||
|
Ok(true) => true,
|
||||||
|
|
||||||
|
// Any other case
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform consensus checks on a Sapling OutputDescription, while
|
||||||
|
/// accumulating its value commitment inside the context for later use.
|
||||||
|
pub fn check_output(
|
||||||
|
&mut self,
|
||||||
|
cv: edwards::Point<Bls12, Unknown>,
|
||||||
|
cm: Fr,
|
||||||
|
epk: edwards::Point<Bls12, Unknown>,
|
||||||
|
zkproof: Proof<Bls12>,
|
||||||
|
verifying_key: &PreparedVerifyingKey<Bls12>,
|
||||||
|
params: &JubjubBls12,
|
||||||
|
) -> bool {
|
||||||
|
if is_small_order(&cv, params) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_small_order(&epk, params) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accumulate the value commitment in the context
|
||||||
|
{
|
||||||
|
let mut tmp = cv.clone();
|
||||||
|
tmp = tmp.negate(); // Outputs subtract from the total.
|
||||||
|
tmp = tmp.add(&self.bvk, params);
|
||||||
|
|
||||||
|
// Update the context
|
||||||
|
self.bvk = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct public input for circuit
|
||||||
|
let mut public_input = [Fr::zero(); 5];
|
||||||
|
{
|
||||||
|
let (x, y) = cv.into_xy();
|
||||||
|
public_input[0] = x;
|
||||||
|
public_input[1] = y;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let (x, y) = epk.into_xy();
|
||||||
|
public_input[2] = x;
|
||||||
|
public_input[3] = y;
|
||||||
|
}
|
||||||
|
public_input[4] = cm;
|
||||||
|
|
||||||
|
// Verify the proof
|
||||||
|
match verify_proof(verifying_key, &zkproof, &public_input[..]) {
|
||||||
|
// No error, and proof verification successful
|
||||||
|
Ok(true) => true,
|
||||||
|
|
||||||
|
// Any other case
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform consensus checks on the valueBalance and bindingSig parts of a
|
||||||
|
/// Sapling transaction. All SpendDescriptions and OutputDescriptions must
|
||||||
|
/// have been checked before calling this function.
|
||||||
|
pub fn final_check(
|
||||||
|
&self,
|
||||||
|
value_balance: i64,
|
||||||
|
sighash_value: &[u8; 32],
|
||||||
|
binding_sig: Signature,
|
||||||
|
params: &JubjubBls12,
|
||||||
|
) -> bool {
|
||||||
|
// Obtain current bvk from the context
|
||||||
|
let mut bvk = PublicKey(self.bvk.clone());
|
||||||
|
|
||||||
|
// Compute value balance
|
||||||
|
let mut value_balance = match compute_value_balance(value_balance, params) {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Subtract value_balance from current bvk to get final bvk
|
||||||
|
value_balance = value_balance.negate();
|
||||||
|
bvk.0 = bvk.0.add(&value_balance, params);
|
||||||
|
|
||||||
|
// Compute the signature's message for bvk/binding_sig
|
||||||
|
let mut data_to_be_signed = [0u8; 64];
|
||||||
|
bvk.0
|
||||||
|
.write(&mut data_to_be_signed[0..32])
|
||||||
|
.expect("bvk is 32 bytes");
|
||||||
|
(&mut data_to_be_signed[32..64]).copy_from_slice(&sighash_value[..]);
|
||||||
|
|
||||||
|
// Verify the binding_sig
|
||||||
|
bvk.verify(
|
||||||
|
&data_to_be_signed,
|
||||||
|
&binding_sig,
|
||||||
|
FixedGenerators::ValueCommitmentRandomness,
|
||||||
|
params,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user