Auto merge of #1919 - ebfull:abstract-verification, r=str4d
Isolate verification to a ProofVerifier context object that allows verification behavior to be tuned by the caller. This is an alternative foundation for #1892, i.e., #1892 will have to be changed if this PR is accepted. I think this is a safer approach because it allows us to isolate verification behavior to a single object. This will come in handy when @arielgabizon finishes the batching code.
This commit is contained in:
@@ -15,6 +15,9 @@ using namespace libzcash;
|
|||||||
|
|
||||||
void test_full_api(ZCJoinSplit* js)
|
void test_full_api(ZCJoinSplit* js)
|
||||||
{
|
{
|
||||||
|
// Create verification context.
|
||||||
|
auto verifier = libzcash::ProofVerifier::Strict();
|
||||||
|
|
||||||
// The recipient's information.
|
// The recipient's information.
|
||||||
SpendingKey recipient_key = SpendingKey::random();
|
SpendingKey recipient_key = SpendingKey::random();
|
||||||
PaymentAddress recipient_addr = recipient_key.address();
|
PaymentAddress recipient_addr = recipient_key.address();
|
||||||
@@ -69,6 +72,7 @@ void test_full_api(ZCJoinSplit* js)
|
|||||||
// Verify the transaction:
|
// Verify the transaction:
|
||||||
ASSERT_TRUE(js->verify(
|
ASSERT_TRUE(js->verify(
|
||||||
proof,
|
proof,
|
||||||
|
verifier,
|
||||||
pubKeyHash,
|
pubKeyHash,
|
||||||
randomSeed,
|
randomSeed,
|
||||||
macs,
|
macs,
|
||||||
@@ -143,6 +147,7 @@ void test_full_api(ZCJoinSplit* js)
|
|||||||
// Verify the transaction:
|
// Verify the transaction:
|
||||||
ASSERT_TRUE(js->verify(
|
ASSERT_TRUE(js->verify(
|
||||||
proof,
|
proof,
|
||||||
|
verifier,
|
||||||
pubKeyHash,
|
pubKeyHash,
|
||||||
randomSeed,
|
randomSeed,
|
||||||
macs,
|
macs,
|
||||||
|
|||||||
@@ -336,6 +336,29 @@ TEST(proofs, zksnark_serializes_properly)
|
|||||||
auto example = libsnark::generate_r1cs_example_with_field_input<curve_Fr>(250, 4);
|
auto example = libsnark::generate_r1cs_example_with_field_input<curve_Fr>(250, 4);
|
||||||
example.constraint_system.swap_AB_if_beneficial();
|
example.constraint_system.swap_AB_if_beneficial();
|
||||||
auto kp = libsnark::r1cs_ppzksnark_generator<curve_pp>(example.constraint_system);
|
auto kp = libsnark::r1cs_ppzksnark_generator<curve_pp>(example.constraint_system);
|
||||||
|
auto vkprecomp = libsnark::r1cs_ppzksnark_verifier_process_vk(kp.vk);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 20; i++) {
|
||||||
|
auto badproof = ZCProof::random_invalid();
|
||||||
|
auto proof = badproof.to_libsnark_proof<libsnark::r1cs_ppzksnark_proof<curve_pp>>();
|
||||||
|
|
||||||
|
auto verifierEnabled = ProofVerifier::Strict();
|
||||||
|
auto verifierDisabled = ProofVerifier::Disabled();
|
||||||
|
// This verifier should catch the bad proof
|
||||||
|
ASSERT_FALSE(verifierEnabled.check(
|
||||||
|
kp.vk,
|
||||||
|
vkprecomp,
|
||||||
|
example.primary_input,
|
||||||
|
proof
|
||||||
|
));
|
||||||
|
// This verifier won't!
|
||||||
|
ASSERT_TRUE(verifierDisabled.check(
|
||||||
|
kp.vk,
|
||||||
|
vkprecomp,
|
||||||
|
example.primary_input,
|
||||||
|
proof
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < 20; i++) {
|
for (size_t i = 0; i < 20; i++) {
|
||||||
auto proof = libsnark::r1cs_ppzksnark_prover<curve_pp>(
|
auto proof = libsnark::r1cs_ppzksnark_prover<curve_pp>(
|
||||||
@@ -345,6 +368,23 @@ TEST(proofs, zksnark_serializes_properly)
|
|||||||
example.constraint_system
|
example.constraint_system
|
||||||
);
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto verifierEnabled = ProofVerifier::Strict();
|
||||||
|
auto verifierDisabled = ProofVerifier::Disabled();
|
||||||
|
ASSERT_TRUE(verifierEnabled.check(
|
||||||
|
kp.vk,
|
||||||
|
vkprecomp,
|
||||||
|
example.primary_input,
|
||||||
|
proof
|
||||||
|
));
|
||||||
|
ASSERT_TRUE(verifierDisabled.check(
|
||||||
|
kp.vk,
|
||||||
|
vkprecomp,
|
||||||
|
example.primary_input,
|
||||||
|
proof
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT_TRUE(libsnark::r1cs_ppzksnark_verifier_strong_IC<curve_pp>(
|
ASSERT_TRUE(libsnark::r1cs_ppzksnark_verifier_strong_IC<curve_pp>(
|
||||||
kp.vk,
|
kp.vk,
|
||||||
example.primary_input,
|
example.primary_input,
|
||||||
|
|||||||
@@ -844,8 +844,9 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
|||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// Ensure that zk-SNARKs verify
|
// Ensure that zk-SNARKs verify
|
||||||
|
auto verifier = libzcash::ProofVerifier::Strict();
|
||||||
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
|
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
|
||||||
if (!joinsplit.Verify(*pzcashParams, tx.joinSplitPubKey)) {
|
if (!joinsplit.Verify(*pzcashParams, verifier, tx.joinSplitPubKey)) {
|
||||||
return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"),
|
return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"),
|
||||||
REJECT_INVALID, "bad-txns-joinsplit-verification-failed");
|
REJECT_INVALID, "bad-txns-joinsplit-verification-failed");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,10 +70,12 @@ JSDescription JSDescription::Randomized(
|
|||||||
|
|
||||||
bool JSDescription::Verify(
|
bool JSDescription::Verify(
|
||||||
ZCJoinSplit& params,
|
ZCJoinSplit& params,
|
||||||
|
libzcash::ProofVerifier& verifier,
|
||||||
const uint256& pubKeyHash
|
const uint256& pubKeyHash
|
||||||
) const {
|
) const {
|
||||||
return params.verify(
|
return params.verify(
|
||||||
proof,
|
proof,
|
||||||
|
verifier,
|
||||||
pubKeyHash,
|
pubKeyHash,
|
||||||
randomSeed,
|
randomSeed,
|
||||||
macs,
|
macs,
|
||||||
|
|||||||
@@ -95,7 +95,11 @@ public:
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Verifies that the JoinSplit proof is correct.
|
// Verifies that the JoinSplit proof is correct.
|
||||||
bool Verify(ZCJoinSplit& params, const uint256& pubKeyHash) const;
|
bool Verify(
|
||||||
|
ZCJoinSplit& params,
|
||||||
|
libzcash::ProofVerifier& verifier,
|
||||||
|
const uint256& pubKeyHash
|
||||||
|
) const;
|
||||||
|
|
||||||
// Returns the calculated h_sig
|
// Returns the calculated h_sig
|
||||||
uint256 h_sig(ZCJoinSplit& params, const uint256& pubKeyHash) const;
|
uint256 h_sig(ZCJoinSplit& params, const uint256& pubKeyHash) const;
|
||||||
|
|||||||
@@ -341,9 +341,11 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
|
|||||||
libzcash::JSOutput(addr, 50)
|
libzcash::JSOutput(addr, 50)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto verifier = libzcash::ProofVerifier::Strict();
|
||||||
|
|
||||||
{
|
{
|
||||||
JSDescription jsdesc(*p, pubKeyHash, rt, inputs, outputs, 0, 0);
|
JSDescription jsdesc(*p, pubKeyHash, rt, inputs, outputs, 0, 0);
|
||||||
BOOST_CHECK(jsdesc.Verify(*p, pubKeyHash));
|
BOOST_CHECK(jsdesc.Verify(*p, verifier, pubKeyHash));
|
||||||
|
|
||||||
CDataStream ss(SER_DISK, CLIENT_VERSION);
|
CDataStream ss(SER_DISK, CLIENT_VERSION);
|
||||||
ss << jsdesc;
|
ss << jsdesc;
|
||||||
@@ -352,7 +354,7 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
|
|||||||
ss >> jsdesc_deserialized;
|
ss >> jsdesc_deserialized;
|
||||||
|
|
||||||
BOOST_CHECK(jsdesc_deserialized == jsdesc);
|
BOOST_CHECK(jsdesc_deserialized == jsdesc);
|
||||||
BOOST_CHECK(jsdesc_deserialized.Verify(*p, pubKeyHash));
|
BOOST_CHECK(jsdesc_deserialized.Verify(*p, verifier, pubKeyHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -365,7 +367,7 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
|
|||||||
// Ensure that it won't verify if the root is changed.
|
// Ensure that it won't verify if the root is changed.
|
||||||
auto test = JSDescription(*p, pubKeyHash, rt, inputs, outputs, 0, 0);
|
auto test = JSDescription(*p, pubKeyHash, rt, inputs, outputs, 0, 0);
|
||||||
test.anchor = GetRandHash();
|
test.anchor = GetRandHash();
|
||||||
BOOST_CHECK(!test.Verify(*p, pubKeyHash));
|
BOOST_CHECK(!test.Verify(*p, verifier, pubKeyHash));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -948,8 +948,11 @@ Object AsyncRPCOperation_sendmany::perform_joinsplit(
|
|||||||
info.vpub_new,
|
info.vpub_new,
|
||||||
!this->testmode);
|
!this->testmode);
|
||||||
|
|
||||||
if (!(jsdesc.Verify(*pzcashParams, joinSplitPubKey_))) {
|
{
|
||||||
throw std::runtime_error("error verifying joinsplit");
|
auto verifier = libzcash::ProofVerifier::Strict();
|
||||||
|
if (!(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey_))) {
|
||||||
|
throw std::runtime_error("error verifying joinsplit");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mtx.vjoinsplit.push_back(jsdesc);
|
mtx.vjoinsplit.push_back(jsdesc);
|
||||||
|
|||||||
@@ -2707,7 +2707,10 @@ Value zc_raw_joinsplit(const json_spirit::Array& params, bool fHelp)
|
|||||||
vpub_old,
|
vpub_old,
|
||||||
vpub_new);
|
vpub_new);
|
||||||
|
|
||||||
assert(jsdesc.Verify(*pzcashParams, joinSplitPubKey));
|
{
|
||||||
|
auto verifier = libzcash::ProofVerifier::Strict();
|
||||||
|
assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
|
||||||
|
}
|
||||||
|
|
||||||
mtx.vjoinsplit.push_back(jsdesc);
|
mtx.vjoinsplit.push_back(jsdesc);
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
#include "zcash/util.h"
|
#include "zcash/util.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
@@ -25,8 +24,6 @@ namespace libzcash {
|
|||||||
|
|
||||||
#include "zcash/circuit/gadget.tcc"
|
#include "zcash/circuit/gadget.tcc"
|
||||||
|
|
||||||
std::once_flag init_public_params_once_flag;
|
|
||||||
|
|
||||||
CCriticalSection cs_ParamsIO;
|
CCriticalSection cs_ParamsIO;
|
||||||
CCriticalSection cs_LoadKeys;
|
CCriticalSection cs_LoadKeys;
|
||||||
|
|
||||||
@@ -80,10 +77,6 @@ public:
|
|||||||
JoinSplitCircuit() {}
|
JoinSplitCircuit() {}
|
||||||
~JoinSplitCircuit() {}
|
~JoinSplitCircuit() {}
|
||||||
|
|
||||||
static void initialize() {
|
|
||||||
std::call_once (init_public_params_once_flag, ppzksnark_ppT::init_public_params);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setProvingKeyPath(std::string path) {
|
void setProvingKeyPath(std::string path) {
|
||||||
pkPath = path;
|
pkPath = path;
|
||||||
}
|
}
|
||||||
@@ -151,6 +144,7 @@ public:
|
|||||||
|
|
||||||
bool verify(
|
bool verify(
|
||||||
const ZCProof& proof,
|
const ZCProof& proof,
|
||||||
|
ProofVerifier& verifier,
|
||||||
const uint256& pubKeyHash,
|
const uint256& pubKeyHash,
|
||||||
const uint256& randomSeed,
|
const uint256& randomSeed,
|
||||||
const boost::array<uint256, NumInputs>& macs,
|
const boost::array<uint256, NumInputs>& macs,
|
||||||
@@ -179,7 +173,12 @@ public:
|
|||||||
vpub_new
|
vpub_new
|
||||||
);
|
);
|
||||||
|
|
||||||
return r1cs_ppzksnark_online_verifier_strong_IC<ppzksnark_ppT>(*vk_precomp, witness, r1cs_proof);
|
return verifier.check(
|
||||||
|
*vk,
|
||||||
|
*vk_precomp,
|
||||||
|
witness,
|
||||||
|
r1cs_proof
|
||||||
|
);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -358,7 +357,7 @@ public:
|
|||||||
template<size_t NumInputs, size_t NumOutputs>
|
template<size_t NumInputs, size_t NumOutputs>
|
||||||
JoinSplit<NumInputs, NumOutputs>* JoinSplit<NumInputs, NumOutputs>::Generate()
|
JoinSplit<NumInputs, NumOutputs>* JoinSplit<NumInputs, NumOutputs>::Generate()
|
||||||
{
|
{
|
||||||
JoinSplitCircuit<NumInputs, NumOutputs>::initialize();
|
initialize_curve_params();
|
||||||
auto js = new JoinSplitCircuit<NumInputs, NumOutputs>();
|
auto js = new JoinSplitCircuit<NumInputs, NumOutputs>();
|
||||||
js->generate();
|
js->generate();
|
||||||
|
|
||||||
@@ -368,7 +367,7 @@ JoinSplit<NumInputs, NumOutputs>* JoinSplit<NumInputs, NumOutputs>::Generate()
|
|||||||
template<size_t NumInputs, size_t NumOutputs>
|
template<size_t NumInputs, size_t NumOutputs>
|
||||||
JoinSplit<NumInputs, NumOutputs>* JoinSplit<NumInputs, NumOutputs>::Unopened()
|
JoinSplit<NumInputs, NumOutputs>* JoinSplit<NumInputs, NumOutputs>::Unopened()
|
||||||
{
|
{
|
||||||
JoinSplitCircuit<NumInputs, NumOutputs>::initialize();
|
initialize_curve_params();
|
||||||
return new JoinSplitCircuit<NumInputs, NumOutputs>();
|
return new JoinSplitCircuit<NumInputs, NumOutputs>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ public:
|
|||||||
|
|
||||||
virtual bool verify(
|
virtual bool verify(
|
||||||
const ZCProof& proof,
|
const ZCProof& proof,
|
||||||
|
ProofVerifier& verifier,
|
||||||
const uint256& pubKeyHash,
|
const uint256& pubKeyHash,
|
||||||
const uint256& randomSeed,
|
const uint256& randomSeed,
|
||||||
const boost::array<uint256, NumInputs>& hmacs,
|
const boost::array<uint256, NumInputs>& hmacs,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "Proof.hpp"
|
#include "Proof.hpp"
|
||||||
|
|
||||||
#include <boost/static_assert.hpp>
|
#include <boost/static_assert.hpp>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "crypto/common.h"
|
#include "crypto/common.h"
|
||||||
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
|
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
|
||||||
@@ -211,4 +212,36 @@ ZCProof ZCProof::random_invalid()
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::once_flag init_public_params_once_flag;
|
||||||
|
|
||||||
|
void initialize_curve_params()
|
||||||
|
{
|
||||||
|
std::call_once (init_public_params_once_flag, curve_pp::init_public_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProofVerifier ProofVerifier::Strict() {
|
||||||
|
initialize_curve_params();
|
||||||
|
return ProofVerifier(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProofVerifier ProofVerifier::Disabled() {
|
||||||
|
initialize_curve_params();
|
||||||
|
return ProofVerifier(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool ProofVerifier::check(
|
||||||
|
const r1cs_ppzksnark_verification_key<curve_pp>& vk,
|
||||||
|
const r1cs_ppzksnark_processed_verification_key<curve_pp>& pvk,
|
||||||
|
const r1cs_primary_input<curve_Fr>& primary_input,
|
||||||
|
const r1cs_ppzksnark_proof<curve_pp>& proof
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (perform_verification) {
|
||||||
|
return r1cs_ppzksnark_online_verifier_strong_IC<curve_pp>(pvk, primary_input, proof);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -235,6 +235,42 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void initialize_curve_params();
|
||||||
|
|
||||||
|
class ProofVerifier {
|
||||||
|
private:
|
||||||
|
bool perform_verification;
|
||||||
|
|
||||||
|
ProofVerifier(bool perform_verification) : perform_verification(perform_verification) { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
// ProofVerifier should never be copied
|
||||||
|
ProofVerifier(const ProofVerifier&) = delete;
|
||||||
|
ProofVerifier& operator=(const ProofVerifier&) = delete;
|
||||||
|
ProofVerifier(ProofVerifier&&);
|
||||||
|
ProofVerifier& operator=(ProofVerifier&&);
|
||||||
|
|
||||||
|
// Creates a verification context that strictly verifies
|
||||||
|
// all proofs using libsnark's API.
|
||||||
|
static ProofVerifier Strict();
|
||||||
|
|
||||||
|
// Creates a verification context that performs no
|
||||||
|
// verification, used when avoiding duplicate effort
|
||||||
|
// such as during reindexing.
|
||||||
|
static ProofVerifier Disabled();
|
||||||
|
|
||||||
|
template <typename VerificationKey,
|
||||||
|
typename ProcessedVerificationKey,
|
||||||
|
typename PrimaryInput,
|
||||||
|
typename Proof
|
||||||
|
>
|
||||||
|
bool check(
|
||||||
|
const VerificationKey& vk,
|
||||||
|
const ProcessedVerificationKey& pvk,
|
||||||
|
const PrimaryInput& pi,
|
||||||
|
const Proof& p
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,8 @@ double benchmark_create_joinsplit()
|
|||||||
0);
|
0);
|
||||||
double ret = timer_stop(tv_start);
|
double ret = timer_stop(tv_start);
|
||||||
|
|
||||||
assert(jsdesc.Verify(*pzcashParams, pubKeyHash));
|
auto verifier = libzcash::ProofVerifier::Strict();
|
||||||
|
assert(jsdesc.Verify(*pzcashParams, verifier, pubKeyHash));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +99,8 @@ double benchmark_verify_joinsplit(const JSDescription &joinsplit)
|
|||||||
struct timeval tv_start;
|
struct timeval tv_start;
|
||||||
timer_start(tv_start);
|
timer_start(tv_start);
|
||||||
uint256 pubKeyHash;
|
uint256 pubKeyHash;
|
||||||
joinsplit.Verify(*pzcashParams, pubKeyHash);
|
auto verifier = libzcash::ProofVerifier::Strict();
|
||||||
|
joinsplit.Verify(*pzcashParams, verifier, pubKeyHash);
|
||||||
return timer_stop(tv_start);
|
return timer_stop(tv_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user