Merge pull request #6000 from ebfull/enablezip216forall
Enable ZIP 216 for blocks prior to NU5 activation
This commit is contained in:
commit
466ea88539
|
@ -48,15 +48,18 @@ endif
|
|||
CXXBRIDGE_RS = \
|
||||
rust/src/blake2b.rs \
|
||||
rust/src/equihash.rs \
|
||||
rust/src/orchard_bundle.rs
|
||||
rust/src/orchard_bundle.rs \
|
||||
rust/src/sapling.rs
|
||||
CXXBRIDGE_H = \
|
||||
rust/gen/include/rust/blake2b.h \
|
||||
rust/gen/include/rust/equihash.h \
|
||||
rust/gen/include/rust/orchard_bundle.h
|
||||
rust/gen/include/rust/orchard_bundle.h \
|
||||
rust/gen/include/rust/sapling.h
|
||||
CXXBRIDGE_CPP = \
|
||||
rust/gen/src/blake2b.cpp \
|
||||
rust/gen/src/equihash.cpp \
|
||||
rust/gen/src/orchard_bundle.cpp
|
||||
rust/gen/src/orchard_bundle.cpp \
|
||||
rust/gen/src/sapling.cpp
|
||||
|
||||
# We add a rust/cxx.h include to indicate that we provide this (via the rustcxx depends
|
||||
# package), so that cxxbridge doesn't include it within the generated headers and code.
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "librustzcash.h"
|
||||
#include <rust/ed25519.h>
|
||||
#include <rust/sapling.h>
|
||||
|
||||
static void ECDSA(benchmark::State& state)
|
||||
{
|
||||
|
@ -106,21 +107,19 @@ static void SaplingSpend(benchmark::State& state)
|
|||
ss >> spend;
|
||||
uint256 dataToBeSigned = uint256S("0x2dbf83fe7b88a7cbd80fac0c719483906bb9a0c4fc69071e4780d5f2c76e592c");
|
||||
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init(true);
|
||||
auto ctx = sapling::init_verifier();
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
librustzcash_sapling_check_spend(
|
||||
ctx,
|
||||
spend.cv.begin(),
|
||||
spend.anchor.begin(),
|
||||
spend.nullifier.begin(),
|
||||
spend.rk.begin(),
|
||||
spend.zkproof.begin(),
|
||||
spend.spendAuthSig.begin(),
|
||||
dataToBeSigned.begin());
|
||||
ctx->check_spend(
|
||||
spend.cv.GetRawBytes(),
|
||||
spend.anchor.GetRawBytes(),
|
||||
spend.nullifier.GetRawBytes(),
|
||||
spend.rk.GetRawBytes(),
|
||||
spend.zkproof,
|
||||
spend.spendAuthSig,
|
||||
dataToBeSigned.GetRawBytes()
|
||||
);
|
||||
}
|
||||
|
||||
librustzcash_sapling_verification_ctx_free(ctx);
|
||||
}
|
||||
|
||||
static void SaplingOutput(benchmark::State& state)
|
||||
|
@ -132,18 +131,16 @@ static void SaplingOutput(benchmark::State& state)
|
|||
PROTOCOL_VERSION);
|
||||
ss >> output;
|
||||
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init(true);
|
||||
auto ctx = sapling::init_verifier();
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
librustzcash_sapling_check_output(
|
||||
ctx,
|
||||
output.cv.begin(),
|
||||
output.cmu.begin(),
|
||||
output.ephemeralKey.begin(),
|
||||
output.zkproof.begin());
|
||||
ctx->check_output(
|
||||
output.cv.GetRawBytes(),
|
||||
output.cmu.GetRawBytes(),
|
||||
output.ephemeralKey.GetRawBytes(),
|
||||
output.zkproof
|
||||
);
|
||||
}
|
||||
|
||||
librustzcash_sapling_verification_ctx_free(ctx);
|
||||
}
|
||||
|
||||
BENCHMARK(ECDSA);
|
||||
|
|
|
@ -135,7 +135,8 @@ public:
|
|||
uint256S("00000000002038016f976744c369dce7419fca30e7171dfac703af5e5f7ad1d4");
|
||||
consensus.vUpgrades[Consensus::UPGRADE_NU5].nProtocolVersion = 170100;
|
||||
consensus.vUpgrades[Consensus::UPGRADE_NU5].nActivationHeight = 1687104;
|
||||
|
||||
consensus.vUpgrades[Consensus::UPGRADE_NU5].hashActivationBlock =
|
||||
uint256S("0000000000d723156d9b65ffcf4984da7a19675ed7e2f06d9e5d5188af087bf8");
|
||||
consensus.vUpgrades[Consensus::UPGRADE_ZFUTURE].nProtocolVersion = 0x7FFFFFFF;
|
||||
consensus.vUpgrades[Consensus::UPGRADE_ZFUTURE].nActivationHeight =
|
||||
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
|
||||
|
@ -239,7 +240,7 @@ public:
|
|||
}
|
||||
|
||||
// The best chain should have at least this much work.
|
||||
consensus.nMinimumChainWork = uint256S("00000000000000000000000000000000000000000000000004a90edff47bbdc6");
|
||||
consensus.nMinimumChainWork = uint256S("000000000000000000000000000000000000000000000000098e5c63248dcb28");
|
||||
|
||||
/**
|
||||
* The message start string should be awesome! ⓩ❤
|
||||
|
|
59
src/main.cpp
59
src/main.cpp
|
@ -47,6 +47,7 @@
|
|||
|
||||
#include <rust/ed25519.h>
|
||||
#include <rust/metrics.h>
|
||||
#include <rust/sapling.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -1317,26 +1318,18 @@ bool ContextualCheckShieldedInputs(
|
|||
if (!tx.vShieldedSpend.empty() ||
|
||||
!tx.vShieldedOutput.empty())
|
||||
{
|
||||
// The nu5Active flag passed in here enables the new consensus rules from ZIP 216
|
||||
// (https://zips.z.cash/zip-0216#specification) on the following fields:
|
||||
//
|
||||
// - spendAuthSig in Sapling Spend descriptions
|
||||
// - bindingSigSapling
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init(nu5Active);
|
||||
auto ctx = sapling::init_verifier();
|
||||
|
||||
for (const SpendDescription &spend : tx.vShieldedSpend) {
|
||||
if (!librustzcash_sapling_check_spend(
|
||||
ctx,
|
||||
spend.cv.begin(),
|
||||
spend.anchor.begin(),
|
||||
spend.nullifier.begin(),
|
||||
spend.rk.begin(),
|
||||
spend.zkproof.begin(),
|
||||
spend.spendAuthSig.begin(),
|
||||
dataToBeSigned.begin()
|
||||
))
|
||||
{
|
||||
librustzcash_sapling_verification_ctx_free(ctx);
|
||||
if (!ctx->check_spend(
|
||||
spend.cv.GetRawBytes(),
|
||||
spend.anchor.GetRawBytes(),
|
||||
spend.nullifier.GetRawBytes(),
|
||||
spend.rk.GetRawBytes(),
|
||||
spend.zkproof,
|
||||
spend.spendAuthSig,
|
||||
dataToBeSigned.GetRawBytes()
|
||||
)) {
|
||||
return state.DoS(
|
||||
dosLevelPotentiallyRelaxing,
|
||||
error("ContextualCheckShieldedInputs(): Sapling spend description invalid"),
|
||||
|
@ -1345,38 +1338,30 @@ bool ContextualCheckShieldedInputs(
|
|||
}
|
||||
|
||||
for (const OutputDescription &output : tx.vShieldedOutput) {
|
||||
if (!librustzcash_sapling_check_output(
|
||||
ctx,
|
||||
output.cv.begin(),
|
||||
output.cmu.begin(),
|
||||
output.ephemeralKey.begin(),
|
||||
output.zkproof.begin()
|
||||
))
|
||||
{
|
||||
librustzcash_sapling_verification_ctx_free(ctx);
|
||||
if (!ctx->check_output(
|
||||
output.cv.GetRawBytes(),
|
||||
output.cmu.GetRawBytes(),
|
||||
output.ephemeralKey.GetRawBytes(),
|
||||
output.zkproof
|
||||
)) {
|
||||
// This should be a non-contextual check, but we check it here
|
||||
// as we need to pass over the outputs anyway in order to then
|
||||
// call librustzcash_sapling_final_check().
|
||||
// call ctx->final_check().
|
||||
return state.DoS(100, error("ContextualCheckShieldedInputs(): Sapling output description invalid"),
|
||||
REJECT_INVALID, "bad-txns-sapling-output-description-invalid");
|
||||
}
|
||||
}
|
||||
|
||||
if (!librustzcash_sapling_final_check(
|
||||
ctx,
|
||||
if (!ctx->final_check(
|
||||
tx.GetValueBalanceSapling(),
|
||||
tx.bindingSig.begin(),
|
||||
dataToBeSigned.begin()
|
||||
))
|
||||
{
|
||||
librustzcash_sapling_verification_ctx_free(ctx);
|
||||
tx.bindingSig,
|
||||
dataToBeSigned.GetRawBytes()
|
||||
)) {
|
||||
return state.DoS(
|
||||
dosLevelPotentiallyRelaxing,
|
||||
error("ContextualCheckShieldedInputs(): Sapling binding signature invalid"),
|
||||
REJECT_INVALID, "bad-txns-sapling-binding-signature-invalid");
|
||||
}
|
||||
|
||||
librustzcash_sapling_verification_ctx_free(ctx);
|
||||
}
|
||||
|
||||
// Queue Orchard bundle to be batch-validated.
|
||||
|
|
|
@ -123,48 +123,6 @@ extern "C" {
|
|||
/// `librustzcash_sapling_proving_ctx_init`.
|
||||
void librustzcash_sapling_proving_ctx_free(void *);
|
||||
|
||||
/// Creates a Sapling verification context. Please free this
|
||||
/// when you're done.
|
||||
void * librustzcash_sapling_verification_ctx_init(
|
||||
bool zip216Enabled
|
||||
);
|
||||
|
||||
/// Check the validity of a Sapling Spend description,
|
||||
/// accumulating the value commitment into the context.
|
||||
bool librustzcash_sapling_check_spend(
|
||||
void *ctx,
|
||||
const unsigned char *cv,
|
||||
const unsigned char *anchor,
|
||||
const unsigned char *nullifier,
|
||||
const unsigned char *rk,
|
||||
const unsigned char *zkproof,
|
||||
const unsigned char *spendAuthSig,
|
||||
const unsigned char *sighashValue
|
||||
);
|
||||
|
||||
/// Check the validity of a Sapling Output description,
|
||||
/// accumulating the value commitment into the context.
|
||||
bool librustzcash_sapling_check_output(
|
||||
void *ctx,
|
||||
const unsigned char *cv,
|
||||
const unsigned char *cm,
|
||||
const unsigned char *ephemeralKey,
|
||||
const unsigned char *zkproof
|
||||
);
|
||||
|
||||
/// Finally checks the validity of the entire Sapling
|
||||
/// transaction given valueBalance and the binding signature.
|
||||
bool librustzcash_sapling_final_check(
|
||||
void *ctx,
|
||||
int64_t valueBalance,
|
||||
const unsigned char *bindingSig,
|
||||
const unsigned char *sighashValue
|
||||
);
|
||||
|
||||
/// Frees a Sapling verification context returned from
|
||||
/// `librustzcash_sapling_verification_ctx_init`.
|
||||
void librustzcash_sapling_verification_ctx_free(void *);
|
||||
|
||||
/// Compute a Sapling nullifier.
|
||||
///
|
||||
/// The `diversifier` parameter must be 11 bytes in length.
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
// See https://github.com/rust-lang/rfcs/pull/2585 for more background.
|
||||
#![allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
|
||||
use bellman::groth16::{Parameters, PreparedVerifyingKey, Proof};
|
||||
use bellman::groth16::{Parameters, PreparedVerifyingKey};
|
||||
use blake2s_simd::Params as Blake2sParams;
|
||||
use bls12_381::Bls12;
|
||||
use group::{cofactor::CofactorGroup, GroupEncoding};
|
||||
|
@ -47,21 +47,16 @@ use zcash_primitives::{
|
|||
constants::{CRH_IVK_PERSONALIZATION, PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR},
|
||||
merkle_tree::MerklePath,
|
||||
sapling::{
|
||||
self,
|
||||
keys::FullViewingKey,
|
||||
note_encryption::sapling_ka_agree,
|
||||
redjubjub::{self, Signature},
|
||||
Diversifier, Note, PaymentAddress, ProofGenerationKey, Rseed, ViewingKey,
|
||||
keys::FullViewingKey, note_encryption::sapling_ka_agree, redjubjub, Diversifier, Note,
|
||||
PaymentAddress, ProofGenerationKey, Rseed, ViewingKey,
|
||||
},
|
||||
sapling::{merkle_hash, spend_sig},
|
||||
transaction::components::Amount,
|
||||
zip32::{self, sapling_address, sapling_derive_internal_fvk, sapling_find_address},
|
||||
};
|
||||
use zcash_proofs::{
|
||||
circuit::sapling::TREE_DEPTH as SAPLING_TREE_DEPTH,
|
||||
load_parameters,
|
||||
sapling::{SaplingProvingContext, SaplingVerificationContext},
|
||||
sprout,
|
||||
circuit::sapling::TREE_DEPTH as SAPLING_TREE_DEPTH, load_parameters,
|
||||
sapling::SaplingProvingContext, sprout,
|
||||
};
|
||||
|
||||
mod blake2b;
|
||||
|
@ -81,6 +76,7 @@ mod init_ffi;
|
|||
mod orchard_bundle;
|
||||
mod orchard_ffi;
|
||||
mod orchard_keys_ffi;
|
||||
mod sapling;
|
||||
mod transaction_ffi;
|
||||
mod unified_keys_ffi;
|
||||
mod wallet;
|
||||
|
@ -537,150 +533,10 @@ pub extern "C" fn librustzcash_sapling_ka_derivepublic(
|
|||
true
|
||||
}
|
||||
|
||||
/// Creates a Sapling verification context. Please free this when you're done.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn librustzcash_sapling_verification_ctx_init(
|
||||
zip216_enabled: bool,
|
||||
) -> *mut SaplingVerificationContext {
|
||||
let ctx = Box::new(SaplingVerificationContext::new(zip216_enabled));
|
||||
|
||||
Box::into_raw(ctx)
|
||||
}
|
||||
|
||||
/// Frees a Sapling verification context returned from
|
||||
/// [`librustzcash_sapling_verification_ctx_init`].
|
||||
#[no_mangle]
|
||||
pub extern "C" fn librustzcash_sapling_verification_ctx_free(ctx: *mut SaplingVerificationContext) {
|
||||
drop(unsafe { Box::from_raw(ctx) });
|
||||
}
|
||||
|
||||
const GROTH_PROOF_SIZE: usize = 48 // π_A
|
||||
+ 96 // π_B
|
||||
+ 48; // π_C
|
||||
|
||||
/// Check the validity of a Sapling Spend description, accumulating the value
|
||||
/// commitment into the context.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn librustzcash_sapling_check_spend(
|
||||
ctx: *mut SaplingVerificationContext,
|
||||
cv: *const [c_uchar; 32],
|
||||
anchor: *const [c_uchar; 32],
|
||||
nullifier: *const [c_uchar; 32],
|
||||
rk: *const [c_uchar; 32],
|
||||
zkproof: *const [c_uchar; GROTH_PROOF_SIZE],
|
||||
spend_auth_sig: *const [c_uchar; 64],
|
||||
sighash_value: *const [c_uchar; 32],
|
||||
) -> bool {
|
||||
// Deserialize the value commitment
|
||||
let cv = match de_ct(jubjub::ExtendedPoint::from_bytes(unsafe { &*cv })) {
|
||||
Some(p) => p,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// Deserialize the anchor, which should be an element
|
||||
// of Fr.
|
||||
let anchor = match de_ct(bls12_381::Scalar::from_bytes(unsafe { &*anchor })) {
|
||||
Some(a) => a,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// Deserialize rk
|
||||
let rk = match redjubjub::PublicKey::read(&(unsafe { &*rk })[..]) {
|
||||
Ok(p) => p,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
// Deserialize the signature
|
||||
let spend_auth_sig = match Signature::read(&(unsafe { &*spend_auth_sig })[..]) {
|
||||
Ok(sig) => sig,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
// Deserialize the proof
|
||||
let zkproof = match Proof::read(&(unsafe { &*zkproof })[..]) {
|
||||
Ok(p) => p,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
unsafe { &mut *ctx }.check_spend(
|
||||
cv,
|
||||
anchor,
|
||||
unsafe { &*nullifier },
|
||||
rk,
|
||||
unsafe { &*sighash_value },
|
||||
spend_auth_sig,
|
||||
zkproof,
|
||||
unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Check the validity of a Sapling Output description, accumulating the value
|
||||
/// commitment into the context.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn librustzcash_sapling_check_output(
|
||||
ctx: *mut SaplingVerificationContext,
|
||||
cv: *const [c_uchar; 32],
|
||||
cm: *const [c_uchar; 32],
|
||||
epk: *const [c_uchar; 32],
|
||||
zkproof: *const [c_uchar; GROTH_PROOF_SIZE],
|
||||
) -> bool {
|
||||
// Deserialize the value commitment
|
||||
let cv = match de_ct(jubjub::ExtendedPoint::from_bytes(unsafe { &*cv })) {
|
||||
Some(p) => p,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// Deserialize the commitment, which should be an element
|
||||
// of Fr.
|
||||
let cm = match de_ct(bls12_381::Scalar::from_bytes(unsafe { &*cm })) {
|
||||
Some(a) => a,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// Deserialize the ephemeral key
|
||||
let epk = match de_ct(jubjub::ExtendedPoint::from_bytes(unsafe { &*epk })) {
|
||||
Some(p) => p,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// Deserialize the proof
|
||||
let zkproof = match Proof::read(&(unsafe { &*zkproof })[..]) {
|
||||
Ok(p) => p,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
unsafe { &mut *ctx }.check_output(
|
||||
cv,
|
||||
cm,
|
||||
epk,
|
||||
zkproof,
|
||||
unsafe { SAPLING_OUTPUT_VK.as_ref() }.unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Finally checks the validity of the entire Sapling transaction given
|
||||
/// valueBalance and the binding signature.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn librustzcash_sapling_final_check(
|
||||
ctx: *mut SaplingVerificationContext,
|
||||
value_balance: i64,
|
||||
binding_sig: *const [c_uchar; 64],
|
||||
sighash_value: *const [c_uchar; 32],
|
||||
) -> bool {
|
||||
let value_balance = match Amount::from_i64(value_balance) {
|
||||
Ok(vb) => vb,
|
||||
Err(()) => return false,
|
||||
};
|
||||
|
||||
// Deserialize the signature
|
||||
let binding_sig = match Signature::read(&(unsafe { &*binding_sig })[..]) {
|
||||
Ok(sig) => sig,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
unsafe { &*ctx }.final_check(value_balance, unsafe { &*sighash_value }, binding_sig)
|
||||
}
|
||||
|
||||
/// Sprout JoinSplit proof generation.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn librustzcash_sprout_prove(
|
||||
|
@ -1170,7 +1026,7 @@ pub extern "C" fn librustzcash_sapling_diversifier_index(
|
|||
j_ret: *mut [c_uchar; 11],
|
||||
) {
|
||||
let dk = zip32::DiversifierKey(unsafe { *dk });
|
||||
let diversifier = sapling::Diversifier(unsafe { *d });
|
||||
let diversifier = Diversifier(unsafe { *d });
|
||||
let j_ret = unsafe { &mut *j_ret };
|
||||
|
||||
let j = dk.diversifier_index(&diversifier);
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
// Copyright (c) 2020-2022 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
// This is added because `check_spend` takes several arguments over FFI. This
|
||||
// annotation gets removed by the cxx procedural macro so it needs to be enabled
|
||||
// on the entire module.
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
use bellman::groth16::Proof;
|
||||
use group::GroupEncoding;
|
||||
|
||||
use zcash_primitives::{
|
||||
sapling::redjubjub::{self, Signature},
|
||||
transaction::components::Amount,
|
||||
};
|
||||
use zcash_proofs::sapling::SaplingVerificationContext;
|
||||
|
||||
use super::GROTH_PROOF_SIZE;
|
||||
use super::{de_ct, SAPLING_OUTPUT_VK, SAPLING_SPEND_VK};
|
||||
|
||||
#[cxx::bridge(namespace = "sapling")]
|
||||
mod ffi {
|
||||
extern "Rust" {
|
||||
type Verifier;
|
||||
|
||||
fn init_verifier() -> Box<Verifier>;
|
||||
fn check_spend(
|
||||
&mut self,
|
||||
cv: &[u8; 32],
|
||||
anchor: &[u8; 32],
|
||||
nullifier: &[u8; 32],
|
||||
rk: &[u8; 32],
|
||||
zkproof: &[u8; 192], // GROTH_PROOF_SIZE
|
||||
spend_auth_sig: &[u8; 64],
|
||||
sighash_value: &[u8; 32],
|
||||
) -> bool;
|
||||
fn check_output(
|
||||
&mut self,
|
||||
cv: &[u8; 32],
|
||||
cm: &[u8; 32],
|
||||
ephemeral_key: &[u8; 32],
|
||||
zkproof: &[u8; 192], // GROTH_PROOF_SIZE
|
||||
) -> bool;
|
||||
fn final_check(
|
||||
&self,
|
||||
value_balance: i64,
|
||||
binding_sig: &[u8; 64],
|
||||
sighash_value: &[u8; 32],
|
||||
) -> bool;
|
||||
}
|
||||
}
|
||||
|
||||
struct Verifier(SaplingVerificationContext);
|
||||
|
||||
fn init_verifier() -> Box<Verifier> {
|
||||
// We consider ZIP 216 active all of the time because blocks prior to NU5
|
||||
// activation (on mainnet and testnet) did not contain Sapling transactions
|
||||
// that violated its canonicity rule.
|
||||
Box::new(Verifier(SaplingVerificationContext::new(true)))
|
||||
}
|
||||
|
||||
impl Verifier {
|
||||
fn check_spend(
|
||||
&mut self,
|
||||
cv: &[u8; 32],
|
||||
anchor: &[u8; 32],
|
||||
nullifier: &[u8; 32],
|
||||
rk: &[u8; 32],
|
||||
zkproof: &[u8; GROTH_PROOF_SIZE],
|
||||
spend_auth_sig: &[u8; 64],
|
||||
sighash_value: &[u8; 32],
|
||||
) -> bool {
|
||||
// Deserialize the value commitment
|
||||
let cv = match de_ct(jubjub::ExtendedPoint::from_bytes(cv)) {
|
||||
Some(p) => p,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// Deserialize the anchor, which should be an element
|
||||
// of Fr.
|
||||
let anchor = match de_ct(bls12_381::Scalar::from_bytes(anchor)) {
|
||||
Some(a) => a,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// Deserialize rk
|
||||
let rk = match redjubjub::PublicKey::read(&rk[..]) {
|
||||
Ok(p) => p,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
// Deserialize the signature
|
||||
let spend_auth_sig = match Signature::read(&spend_auth_sig[..]) {
|
||||
Ok(sig) => sig,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
// Deserialize the proof
|
||||
let zkproof = match Proof::read(&zkproof[..]) {
|
||||
Ok(p) => p,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
self.0.check_spend(
|
||||
cv,
|
||||
anchor,
|
||||
nullifier,
|
||||
rk,
|
||||
sighash_value,
|
||||
spend_auth_sig,
|
||||
zkproof,
|
||||
unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(),
|
||||
)
|
||||
}
|
||||
fn check_output(
|
||||
&mut self,
|
||||
cv: &[u8; 32],
|
||||
cm: &[u8; 32],
|
||||
ephemeral_key: &[u8; 32],
|
||||
zkproof: &[u8; GROTH_PROOF_SIZE],
|
||||
) -> bool {
|
||||
// Deserialize the value commitment
|
||||
let cv = match de_ct(jubjub::ExtendedPoint::from_bytes(cv)) {
|
||||
Some(p) => p,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// Deserialize the commitment, which should be an element
|
||||
// of Fr.
|
||||
let cm = match de_ct(bls12_381::Scalar::from_bytes(cm)) {
|
||||
Some(a) => a,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// Deserialize the ephemeral key
|
||||
let ephemeral_key = match de_ct(jubjub::ExtendedPoint::from_bytes(ephemeral_key)) {
|
||||
Some(p) => p,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// Deserialize the proof
|
||||
let zkproof = match Proof::read(&zkproof[..]) {
|
||||
Ok(p) => p,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
self.0.check_output(
|
||||
cv,
|
||||
cm,
|
||||
ephemeral_key,
|
||||
zkproof,
|
||||
unsafe { SAPLING_OUTPUT_VK.as_ref() }.unwrap(),
|
||||
)
|
||||
}
|
||||
fn final_check(
|
||||
&self,
|
||||
value_balance: i64,
|
||||
binding_sig: &[u8; 64],
|
||||
sighash_value: &[u8; 32],
|
||||
) -> bool {
|
||||
let value_balance = match Amount::from_i64(value_balance) {
|
||||
Ok(vb) => vb,
|
||||
Err(()) => return false,
|
||||
};
|
||||
|
||||
// Deserialize the signature
|
||||
let binding_sig = match Signature::read(&binding_sig[..]) {
|
||||
Ok(sig) => sig,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
self.0
|
||||
.final_check(value_balance, sighash_value, binding_sig)
|
||||
}
|
||||
}
|
|
@ -89,6 +89,14 @@ public:
|
|||
((uint64_t)ptr[7]) << 56;
|
||||
}
|
||||
|
||||
std::array<uint8_t, WIDTH> GetRawBytes() const
|
||||
{
|
||||
std::array<uint8_t, WIDTH> buf = {};
|
||||
memcpy(buf.data(), this->begin(), WIDTH);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s) const
|
||||
{
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "librustzcash.h"
|
||||
|
||||
#include <rust/ed25519/types.h>
|
||||
#include <rust/sapling.h>
|
||||
|
||||
using namespace libzcash;
|
||||
// This method is based on Shutdown from init.cpp
|
||||
|
@ -797,24 +798,22 @@ double benchmark_verify_sapling_spend()
|
|||
ss >> spend;
|
||||
uint256 dataToBeSigned = uint256S("0x2dbf83fe7b88a7cbd80fac0c719483906bb9a0c4fc69071e4780d5f2c76e592c");
|
||||
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init(true);
|
||||
auto ctx = sapling::init_verifier();
|
||||
|
||||
struct timeval tv_start;
|
||||
timer_start(tv_start);
|
||||
|
||||
bool result = librustzcash_sapling_check_spend(
|
||||
ctx,
|
||||
spend.cv.begin(),
|
||||
spend.anchor.begin(),
|
||||
spend.nullifier.begin(),
|
||||
spend.rk.begin(),
|
||||
spend.zkproof.begin(),
|
||||
spend.spendAuthSig.begin(),
|
||||
dataToBeSigned.begin()
|
||||
);
|
||||
bool result = ctx->check_spend(
|
||||
spend.cv.GetRawBytes(),
|
||||
spend.anchor.GetRawBytes(),
|
||||
spend.nullifier.GetRawBytes(),
|
||||
spend.rk.GetRawBytes(),
|
||||
spend.zkproof,
|
||||
spend.spendAuthSig,
|
||||
dataToBeSigned.GetRawBytes()
|
||||
);
|
||||
|
||||
double t = timer_stop(tv_start);
|
||||
librustzcash_sapling_verification_ctx_free(ctx);
|
||||
if (!result) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_check_spend() should return true");
|
||||
}
|
||||
|
@ -830,21 +829,19 @@ double benchmark_verify_sapling_output()
|
|||
CDataStream ss(ParseHex("edd742af18857e5ec2d71d346a7fe2ac97c137339bd5268eea86d32e0ff4f38f76213fa8cfed3347ac4e8572dd88aff395c0c10a59f8b3f49d2bc539ed6c726667e29d4763f914ddd0abf1cdfa84e44de87c233434c7e69b8b5b8f4623c8aa444163425bae5cef842972fed66046c1c6ce65c866ad894d02e6e6dcaae7a962d9f2ef95757a09c486928e61f0f7aed90ad0a542b0d3dc5fe140dfa7626b9315c77e03b055f19cbacd21a866e46f06c00e0c7792b2a590a611439b510a9aaffcf1073bad23e712a9268b36888e3727033eee2ab4d869f54a843f93b36ef489fb177bf74b41a9644e5d2a0a417c6ac1c8869bc9b83273d453f878ed6fd96b82a5939903f7b64ecaf68ea16e255a7fb7cc0b6d8b5608a1c6b0ed3024cc62c2f0f9c5cfc7b431ae6e9d40815557aa1d010523f9e1960de77b2274cb6710d229d475c87ae900183206ba90cb5bbc8ec0df98341b82726c705e0308ca5dc08db4db609993a1046dfb43dfd8c760be506c0bed799bb2205fc29dc2e654dce731034a23b0aaf6da0199248702ee0523c159f41f4cbfff6c35ace4dd9ae834e44e09c76a0cbdda1d3f6a2c75ad71212daf9575ab5f09ca148718e667f29ddf18c8a330a86ace18a86e89454653902aa393c84c6b694f27d0d42e24e7ac9fe34733de5ec15f5066081ce912c62c1a804a2bb4dedcef7cc80274f6bb9e89e2fce91dc50d6a73c8aefb9872f1cf3524a92626a0b8f39bbf7bf7d96ca2f770fc04d7f457021c536a506a187a93b2245471ddbfb254a71bc4a0d72c8d639a31c7b1920087ffca05c24214157e2e7b28184e91989ef0b14f9b34c3dc3cc0ac64226b9e337095870cb0885737992e120346e630a416a9b217679ce5a778fb15779c136bcecca5efe79012013d77d90b4e99dd22c8f35bc77121716e160d05bd30d288ee8886390ee436f85bdc9029df888a3a3326d9d4ddba5cb5318b3274928829d662e96fea1d601f7a306251ed8c6cc4e5a3a7a98c35a3650482a0eee08f3b4c2da9b22947c96138f1505c2f081f8972d429f3871f32bef4aaa51aa6945df8e9c9760531ac6f627d17c1518202818a91ca304fb4037875c666060597976144fcbbc48a776a2c61beb9515fa8f3ae6d3a041d320a38a8ac75cb47bb9c866ee497fc3cd13299970c4b369c1c2ceb4220af082fbecdd8114492a8e4d713b5a73396fd224b36c1185bd5e20d683e6c8db35346c47ae7401988255da7cfffdced5801067d4d296688ee8fe424b4a8a69309ce257eefb9345ebfda3f6de46bb11ec94133e1f72cd7ac54934d6cf17b3440800e70b80ebc7c7bfc6fb0fc2c"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> output;
|
||||
|
||||
auto ctx = librustzcash_sapling_verification_ctx_init(true);
|
||||
auto ctx = sapling::init_verifier();
|
||||
|
||||
struct timeval tv_start;
|
||||
timer_start(tv_start);
|
||||
|
||||
bool result = librustzcash_sapling_check_output(
|
||||
ctx,
|
||||
output.cv.begin(),
|
||||
output.cmu.begin(),
|
||||
output.ephemeralKey.begin(),
|
||||
output.zkproof.begin()
|
||||
);
|
||||
bool result = ctx->check_output(
|
||||
output.cv.GetRawBytes(),
|
||||
output.cmu.GetRawBytes(),
|
||||
output.ephemeralKey.GetRawBytes(),
|
||||
output.zkproof
|
||||
);
|
||||
|
||||
double t = timer_stop(tv_start);
|
||||
librustzcash_sapling_verification_ctx_free(ctx);
|
||||
if (!result) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "librustzcash_sapling_check_output() should return true");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue