Browse Source

Remove crusty old "loadVerifyingKey"/"loadProvingKey" APIs and associated invariants.

pull/4/head
Sean Bowe 7 years ago
committed by Ariel Gabizon
parent
commit
1a9543d064
  1. 7
      src/gtest/main.cpp
  2. 52
      src/gtest/test_joinsplit.cpp
  3. 4
      src/gtest/utils.cpp
  4. 6
      src/init.cpp
  5. 3
      src/primitives/transaction.cpp
  6. 28
      src/test/test_bitcoin.cpp
  7. 6
      src/test/test_bitcoin.h
  8. 20
      src/test/transaction_tests.cpp
  9. 6
      src/wallet/rpcwallet.cpp
  10. 8
      src/zcash/CreateJoinSplit.cpp
  11. 8
      src/zcash/GenerateParams.cpp
  12. 111
      src/zcash/JoinSplit.cpp
  13. 17
      src/zcash/JoinSplit.hpp
  14. 6
      src/zcbenchmarks.cpp

7
src/gtest/main.cpp

@ -4,6 +4,8 @@
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include "zcash/JoinSplit.hpp"
#include "util.h"
struct ECCryptoClosure
{
@ -12,11 +14,16 @@ struct ECCryptoClosure
ECCryptoClosure instance_of_eccryptoclosure;
ZCJoinSplit* params;
int main(int argc, char **argv) {
assert(init_and_check_sodium() != -1);
libsnark::default_r1cs_ppzksnark_pp::init_public_params();
libsnark::inhibit_profiling_info = true;
libsnark::inhibit_profiling_counters = true;
boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key";
boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key";
params = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string());
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();

52
src/gtest/test_joinsplit.cpp

@ -5,6 +5,7 @@
#include <boost/foreach.hpp>
#include "zcash/prf.h"
#include "util.h"
#include "zcash/JoinSplit.hpp"
#include "zcash/Note.hpp"
@ -13,6 +14,8 @@
using namespace libzcash;
extern ZCJoinSplit* params;
void test_full_api(ZCJoinSplit* js)
{
// Create verification context.
@ -219,8 +222,6 @@ void invokeAPIFailure(
TEST(joinsplit, h_sig)
{
auto js = ZCJoinSplit::Unopened();
/*
// by Taylor Hornby
@ -284,7 +285,7 @@ for test_input in TEST_VECTORS:
};
BOOST_FOREACH(std::vector<std::string>& v, tests) {
auto expected = js->h_sig(
auto expected = ZCJoinSplit::h_sig(
uint256S(v[0]),
{uint256S(v[1]), uint256S(v[2])},
uint256S(v[3])
@ -292,8 +293,6 @@ for test_input in TEST_VECTORS:
EXPECT_EQ(expected, uint256S(v[4]));
}
delete js;
}
void increment_note_witnesses(
@ -311,8 +310,6 @@ void increment_note_witnesses(
TEST(joinsplit, full_api_test)
{
auto js = ZCJoinSplit::Generate();
{
std::vector<ZCIncrementalWitness> witnesses;
ZCIncrementalMerkleTree tree;
@ -331,7 +328,7 @@ TEST(joinsplit, full_api_test)
increment_note_witnesses(note5.cm(), witnesses, tree);
// Should work
invokeAPI(js,
invokeAPI(params,
{
JSInput(),
JSInput()
@ -345,7 +342,7 @@ TEST(joinsplit, full_api_test)
tree.root());
// lhs > MAX_MONEY
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@ -360,7 +357,7 @@ TEST(joinsplit, full_api_test)
"nonsensical vpub_old value");
// rhs > MAX_MONEY
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@ -375,7 +372,7 @@ TEST(joinsplit, full_api_test)
"nonsensical vpub_new value");
// input witness for the wrong element
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[0], note1, sk),
JSInput()
@ -391,7 +388,7 @@ TEST(joinsplit, full_api_test)
// input witness doesn't match up with
// real root
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[1], note1, sk),
JSInput()
@ -406,7 +403,7 @@ TEST(joinsplit, full_api_test)
"joinsplit not anchored to the correct root");
// input is in the tree now! this should work
invokeAPI(js,
invokeAPI(params,
{
JSInput(witnesses[1], note1, sk),
JSInput()
@ -420,7 +417,7 @@ TEST(joinsplit, full_api_test)
tree.root());
// Wrong secret key
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[1], note1, SpendingKey::random()),
JSInput()
@ -435,7 +432,7 @@ TEST(joinsplit, full_api_test)
"input note not authorized to spend with given key");
// Absurd input value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[3], note3, sk),
JSInput()
@ -450,7 +447,7 @@ TEST(joinsplit, full_api_test)
"nonsensical input note value");
// Absurd total input value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(witnesses[4], note4, sk),
JSInput(witnesses[5], note5, sk)
@ -465,7 +462,7 @@ TEST(joinsplit, full_api_test)
"nonsensical left hand size of joinsplit balance");
// Absurd output value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@ -480,7 +477,7 @@ TEST(joinsplit, full_api_test)
"nonsensical output value");
// Absurd total output value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@ -495,7 +492,7 @@ TEST(joinsplit, full_api_test)
"nonsensical right hand side of joinsplit balance");
// Absurd total output value
invokeAPIFailure(js,
invokeAPIFailure(params,
{
JSInput(),
JSInput()
@ -510,22 +507,7 @@ TEST(joinsplit, full_api_test)
"invalid joinsplit balance");
}
test_full_api(js);
js->saveProvingKey("./zcashTest.pk");
js->saveVerifyingKey("./zcashTest.vk");
delete js;
js = ZCJoinSplit::Unopened();
js->setProvingKeyPath("./zcashTest.pk");
js->loadProvingKey();
js->loadVerifyingKey("./zcashTest.vk");
test_full_api(js);
delete js;
test_full_api(params);
}
TEST(joinsplit, note_plaintexts)

4
src/gtest/utils.cpp

@ -1,7 +1,3 @@
#include "zcash/JoinSplit.hpp"
ZCJoinSplit* params = ZCJoinSplit::Unopened();
int GenZero(int n)
{
return 0;

6
src/init.cpp

@ -688,18 +688,14 @@ static void ZC_LoadParams()
return;
}
pzcashParams = ZCJoinSplit::Unopened();
LogPrintf("Loading verifying key from %s\n", vk_path.string().c_str());
gettimeofday(&tv_start, 0);
pzcashParams->loadVerifyingKey(vk_path.string());
pzcashParams = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string());
gettimeofday(&tv_end, 0);
elapsed = float(tv_end.tv_sec-tv_start.tv_sec) + (tv_end.tv_usec-tv_start.tv_usec)/float(1000000);
LogPrintf("Loaded verifying key in %fs seconds.\n", elapsed);
pzcashParams->setProvingKeyPath(pk_path.string());
}
bool AppInitServers(boost::thread_group& threadGroup)

3
src/primitives/transaction.cpp

@ -20,9 +20,6 @@ JSDescription::JSDescription(ZCJoinSplit& params,
{
boost::array<libzcash::Note, ZC_NUM_JS_OUTPUTS> notes;
if (computeProof) {
params.loadProvingKey();
}
proof = params.prove(
inputs,
outputs,

28
src/test/test_bitcoin.cpp

@ -30,20 +30,30 @@ ZCJoinSplit *pzcashParams;
extern bool fPrintToConsole;
extern void noui_connect();
JoinSplitTestingSetup::JoinSplitTestingSetup()
{
boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key";
boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key";
pzcashParams = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string());
}
JoinSplitTestingSetup::~JoinSplitTestingSetup()
{
delete pzcashParams;
}
BasicTestingSetup::BasicTestingSetup()
{
assert(init_and_check_sodium() != -1);
ECC_Start();
pzcashParams = ZCJoinSplit::Unopened();
SetupEnvironment();
fPrintToDebugLog = false; // don't want to write to debug.log file
fCheckBlockIndex = true;
SelectParams(CBaseChainParams::MAIN);
assert(init_and_check_sodium() != -1);
ECC_Start();
SetupEnvironment();
fPrintToDebugLog = false; // don't want to write to debug.log file
fCheckBlockIndex = true;
SelectParams(CBaseChainParams::MAIN);
}
BasicTestingSetup::~BasicTestingSetup()
{
ECC_Stop();
delete pzcashParams;
ECC_Stop();
}
TestingSetup::TestingSetup()

6
src/test/test_bitcoin.h

@ -30,4 +30,10 @@ struct TestingSetup: public BasicTestingSetup {
~TestingSetup();
};
// Setup w.r.t. zk-SNARK API
struct JoinSplitTestingSetup: public BasicTestingSetup {
JoinSplitTestingSetup();
~JoinSplitTestingSetup();
};
#endif

20
src/test/transaction_tests.cpp

@ -6,6 +6,7 @@
#include "data/tx_valid.json.h"
#include "test/test_bitcoin.h"
#include "init.h"
#include "clientversion.h"
#include "consensus/validation.h"
#include "core_io.h"
@ -85,7 +86,7 @@ string FormatScriptFlags(unsigned int flags)
return ret.substr(0, ret.size() - 1);
}
BOOST_FIXTURE_TEST_SUITE(transaction_tests, BasicTestingSetup)
BOOST_FIXTURE_TEST_SUITE(transaction_tests, JoinSplitTestingSetup)
BOOST_AUTO_TEST_CASE(tx_valid)
{
@ -326,9 +327,6 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
// Also, it's generally libzcash's job to ensure the
// integrity of the scheme through its own tests.
// construct the r1cs keypair
auto p = ZCJoinSplit::Generate();
// construct a merkle tree
ZCIncrementalMerkleTree merkleTree;
@ -362,8 +360,8 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
auto verifier = libzcash::ProofVerifier::Strict();
{
JSDescription jsdesc(*p, pubKeyHash, rt, inputs, outputs, 0, 0);
BOOST_CHECK(jsdesc.Verify(*p, verifier, pubKeyHash));
JSDescription jsdesc(*pzcashParams, pubKeyHash, rt, inputs, outputs, 0, 0);
BOOST_CHECK(jsdesc.Verify(*pzcashParams, verifier, pubKeyHash));
CDataStream ss(SER_DISK, CLIENT_VERSION);
ss << jsdesc;
@ -372,20 +370,20 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
ss >> jsdesc_deserialized;
BOOST_CHECK(jsdesc_deserialized == jsdesc);
BOOST_CHECK(jsdesc_deserialized.Verify(*p, verifier, pubKeyHash));
BOOST_CHECK(jsdesc_deserialized.Verify(*pzcashParams, verifier, pubKeyHash));
}
{
// Ensure that the balance equation is working.
BOOST_CHECK_THROW(JSDescription(*p, pubKeyHash, rt, inputs, outputs, 10, 0), std::invalid_argument);
BOOST_CHECK_THROW(JSDescription(*p, pubKeyHash, rt, inputs, outputs, 0, 10), std::invalid_argument);
BOOST_CHECK_THROW(JSDescription(*pzcashParams, pubKeyHash, rt, inputs, outputs, 10, 0), std::invalid_argument);
BOOST_CHECK_THROW(JSDescription(*pzcashParams, pubKeyHash, rt, inputs, outputs, 0, 10), std::invalid_argument);
}
{
// Ensure that it won't verify if the root is changed.
auto test = JSDescription(*p, pubKeyHash, rt, inputs, outputs, 0, 0);
auto test = JSDescription(*pzcashParams, pubKeyHash, rt, inputs, outputs, 0, 0);
test.anchor = GetRandHash();
BOOST_CHECK(!test.Verify(*p, verifier, pubKeyHash));
BOOST_CHECK(!test.Verify(*pzcashParams, verifier, pubKeyHash));
}
}

6
src/wallet/rpcwallet.cpp

@ -2543,12 +2543,6 @@ UniValue zc_benchmark(const UniValue& params, bool fHelp)
std::vector<double> sample_times;
if (benchmarktype == "createjoinsplit") {
/* Load the proving now key so that it doesn't happen as part of the
* first joinsplit. */
pzcashParams->loadProvingKey();
}
JSDescription samplejoinsplit;
if (benchmarktype == "verifyjoinsplit") {

8
src/zcash/CreateJoinSplit.cpp

@ -13,10 +13,8 @@ int main(int argc, char **argv)
{
libsnark::start_profiling();
auto p = ZCJoinSplit::Unopened();
p->loadVerifyingKey((ZC_GetParamsDir() / "sprout-verifying.key").string());
p->setProvingKeyPath((ZC_GetParamsDir() / "sprout-proving.key").string());
p->loadProvingKey();
auto p = ZCJoinSplit::Prepared((ZC_GetParamsDir() / "sprout-verifying.key").string(),
(ZC_GetParamsDir() / "sprout-proving.key").string());
// construct a proof.
@ -32,4 +30,6 @@ int main(int argc, char **argv)
0,
0);
}
delete p; // not that it matters
}

8
src/zcash/GenerateParams.cpp

@ -18,13 +18,7 @@ int main(int argc, char **argv)
std::string vkFile = argv[2];
std::string r1csFile = argv[3];
auto p = ZCJoinSplit::Generate();
p->saveProvingKey(pkFile);
p->saveVerifyingKey(vkFile);
p->saveR1CS(r1csFile);
delete p;
ZCJoinSplit::Generate(r1csFile, vkFile, pkFile);
return 0;
}

111
src/zcash/JoinSplit.cpp

@ -28,7 +28,7 @@ CCriticalSection cs_ParamsIO;
CCriticalSection cs_LoadKeys;
template<typename T>
void saveToFile(std::string path, T& obj) {
void saveToFile(const std::string path, T& obj) {
LOCK(cs_ParamsIO);
std::stringstream ss;
@ -42,7 +42,7 @@ void saveToFile(std::string path, T& obj) {
}
template<typename T>
void loadFromFile(std::string path, boost::optional<T>& objIn) {
void loadFromFile(const std::string path, T& objIn) {
LOCK(cs_ParamsIO);
std::stringstream ss;
@ -69,77 +69,33 @@ public:
typedef default_r1cs_ppzksnark_pp ppzksnark_ppT;
typedef Fr<ppzksnark_ppT> FieldT;
boost::optional<r1cs_ppzksnark_proving_key<ppzksnark_ppT>> pk;
boost::optional<r1cs_ppzksnark_verification_key<ppzksnark_ppT>> vk;
boost::optional<r1cs_ppzksnark_processed_verification_key<ppzksnark_ppT>> vk_precomp;
boost::optional<std::string> pkPath;
r1cs_ppzksnark_verification_key<ppzksnark_ppT> vk;
r1cs_ppzksnark_processed_verification_key<ppzksnark_ppT> vk_precomp;
std::string pkPath;
JoinSplitCircuit() {}
~JoinSplitCircuit() {}
void setProvingKeyPath(std::string path) {
pkPath = path;
}
void loadProvingKey() {
LOCK(cs_LoadKeys);
if (!pk) {
if (!pkPath) {
throw std::runtime_error("proving key path unknown");
}
loadFromFile(*pkPath, pk);
}
}
void saveProvingKey(std::string path) {
if (pk) {
saveToFile(path, *pk);
} else {
throw std::runtime_error("cannot save proving key; key doesn't exist");
}
}
void loadVerifyingKey(std::string path) {
LOCK(cs_LoadKeys);
loadFromFile(path, vk);
processVerifyingKey();
}
void processVerifyingKey() {
vk_precomp = r1cs_ppzksnark_verifier_process_vk(*vk);
}
void saveVerifyingKey(std::string path) {
if (vk) {
saveToFile(path, *vk);
} else {
throw std::runtime_error("cannot save verifying key; key doesn't exist");
}
}
void saveR1CS(std::string path) {
auto r1cs = generate_r1cs();
saveToFile(path, r1cs);
JoinSplitCircuit(const std::string vkPath, const std::string pkPath) : pkPath(pkPath) {
loadFromFile(vkPath, vk);
vk_precomp = r1cs_ppzksnark_verifier_process_vk(vk);
}
~JoinSplitCircuit() {}
r1cs_constraint_system<FieldT> generate_r1cs() {
static void generate(const std::string r1csPath,
const std::string vkPath,
const std::string pkPath)
{
protoboard<FieldT> pb;
joinsplit_gadget<FieldT, NumInputs, NumOutputs> g(pb);
g.generate_r1cs_constraints();
return pb.get_constraint_system();
}
auto r1cs = pb.get_constraint_system();
void generate() {
LOCK(cs_LoadKeys);
saveToFile(r1csPath, r1cs);
const r1cs_constraint_system<FieldT> constraint_system = generate_r1cs();
r1cs_ppzksnark_keypair<ppzksnark_ppT> keypair = r1cs_ppzksnark_generator<ppzksnark_ppT>(constraint_system);
r1cs_ppzksnark_keypair<ppzksnark_ppT> keypair = r1cs_ppzksnark_generator<ppzksnark_ppT>(r1cs);
pk = keypair.pk;
vk = keypair.vk;
processVerifyingKey();
saveToFile(vkPath, keypair.vk);
saveToFile(pkPath, keypair.pk);
}
bool verify(
@ -154,10 +110,6 @@ public:
uint64_t vpub_new,
const uint256& rt
) {
if (!vk || !vk_precomp) {
throw std::runtime_error("JoinSplit verifying key not loaded");
}
try {
auto r1cs_proof = proof.to_libsnark_proof<r1cs_ppzksnark_proof<ppzksnark_ppT>>();
@ -174,8 +126,8 @@ public:
);
return verifier.check(
*vk,
*vk_precomp,
vk,
vk_precomp,
witness,
r1cs_proof
);
@ -200,10 +152,6 @@ public:
const uint256& rt,
bool computeProof
) {
if (computeProof && !pk) {
throw std::runtime_error("JoinSplit proving key not loaded");
}
if (vpub_old > MAX_MONEY) {
throw std::invalid_argument("nonsensical vpub_old value");
}
@ -345,8 +293,11 @@ public:
// estimate that it doesn't matter if we check every time.
pb.constraint_system.swap_AB_if_beneficial();
r1cs_ppzksnark_proving_key<ppzksnark_ppT> pk;
loadFromFile(pkPath, pk);
return ZCProof(r1cs_ppzksnark_prover<ppzksnark_ppT>(
*pk,
pk,
primary_input,
aux_input,
pb.constraint_system
@ -355,20 +306,20 @@ public:
};
template<size_t NumInputs, size_t NumOutputs>
JoinSplit<NumInputs, NumOutputs>* JoinSplit<NumInputs, NumOutputs>::Generate()
void JoinSplit<NumInputs, NumOutputs>::Generate(const std::string r1csPath,
const std::string vkPath,
const std::string pkPath)
{
initialize_curve_params();
auto js = new JoinSplitCircuit<NumInputs, NumOutputs>();
js->generate();
return js;
JoinSplitCircuit<NumInputs, NumOutputs>::generate(r1csPath, vkPath, pkPath);
}
template<size_t NumInputs, size_t NumOutputs>
JoinSplit<NumInputs, NumOutputs>* JoinSplit<NumInputs, NumOutputs>::Unopened()
JoinSplit<NumInputs, NumOutputs>* JoinSplit<NumInputs, NumOutputs>::Prepared(const std::string vkPath,
const std::string pkPath)
{
initialize_curve_params();
return new JoinSplitCircuit<NumInputs, NumOutputs>();
return new JoinSplitCircuit<NumInputs, NumOutputs>(vkPath, pkPath);
}
template<size_t NumInputs, size_t NumOutputs>

17
src/zcash/JoinSplit.hpp

@ -48,22 +48,17 @@ class JoinSplit {
public:
virtual ~JoinSplit() {}
static JoinSplit<NumInputs, NumOutputs>* Generate();
static JoinSplit<NumInputs, NumOutputs>* Unopened();
static void Generate(const std::string r1csPath,
const std::string vkPath,
const std::string pkPath);
static JoinSplit<NumInputs, NumOutputs>* Prepared(const std::string vkPath,
const std::string pkPath);
static uint256 h_sig(const uint256& randomSeed,
const boost::array<uint256, NumInputs>& nullifiers,
const uint256& pubKeyHash
);
// TODO: #789
virtual void setProvingKeyPath(std::string) = 0;
virtual void loadProvingKey() = 0;
virtual void saveProvingKey(std::string path) = 0;
virtual void loadVerifyingKey(std::string path) = 0;
virtual void saveVerifyingKey(std::string path) = 0;
virtual void saveR1CS(std::string path) = 0;
virtual ZCProof prove(
const boost::array<JSInput, NumInputs>& inputs,
const boost::array<JSOutput, NumOutputs>& outputs,

6
src/zcbenchmarks.cpp

@ -97,11 +97,7 @@ double benchmark_parameter_loading()
struct timeval tv_start;
timer_start(tv_start);
auto newParams = ZCJoinSplit::Unopened();
newParams->loadVerifyingKey(vk_path.string());
newParams->setProvingKeyPath(pk_path.string());
newParams->loadProvingKey();
auto newParams = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string());
double ret = timer_stop(tv_start);

Loading…
Cancel
Save