A bunch more libsnark deletions/updates
This commit is contained in:
@@ -5,9 +5,6 @@
|
||||
#include "zcash/JoinSplit.hpp"
|
||||
#include "util.h"
|
||||
|
||||
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
|
||||
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
|
||||
|
||||
#include "librustzcash.h"
|
||||
|
||||
struct ECCryptoClosure
|
||||
@@ -23,12 +20,7 @@ int main(int argc, char **argv) {
|
||||
assert(init_and_check_sodium() != -1);
|
||||
ECC_Start();
|
||||
|
||||
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());
|
||||
params = ZCJoinSplit::Prepared();
|
||||
|
||||
boost::filesystem::path sapling_spend = ZC_GetParamsDir() / "sapling-spend.params";
|
||||
boost::filesystem::path sapling_output = ZC_GetParamsDir() / "sapling-output.params";
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "uint256.h"
|
||||
|
||||
#include "zcash/util.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
|
||||
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
|
||||
#include <libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp>
|
||||
#include <libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp>
|
||||
|
||||
#include "zcash/IncrementalMerkleTree.hpp"
|
||||
|
||||
using namespace libsnark;
|
||||
using namespace libzcash;
|
||||
|
||||
#include "zcash/circuit/utils.tcc"
|
||||
#include "zcash/circuit/merkle.tcc"
|
||||
|
||||
template<typename FieldT>
|
||||
void test_value_equals(uint64_t i) {
|
||||
protoboard<FieldT> pb;
|
||||
pb_variable_array<FieldT> num;
|
||||
num.allocate(pb, 64, "");
|
||||
num.fill_with_bits(pb, uint64_to_bool_vector(i));
|
||||
pb.add_r1cs_constraint(r1cs_constraint<FieldT>(
|
||||
packed_addition(num),
|
||||
FieldT::one(),
|
||||
FieldT::one() * i
|
||||
), "");
|
||||
ASSERT_TRUE(pb.is_satisfied());
|
||||
}
|
||||
|
||||
TEST(circuit, values)
|
||||
{
|
||||
typedef Fr<default_r1cs_ppzksnark_pp> FieldT;
|
||||
test_value_equals<FieldT>(0);
|
||||
test_value_equals<FieldT>(1);
|
||||
test_value_equals<FieldT>(3);
|
||||
test_value_equals<FieldT>(5391);
|
||||
test_value_equals<FieldT>(883128374);
|
||||
test_value_equals<FieldT>(173419028459);
|
||||
test_value_equals<FieldT>(2205843009213693953);
|
||||
}
|
||||
|
||||
TEST(circuit, endianness)
|
||||
{
|
||||
std::vector<unsigned char> before = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63
|
||||
};
|
||||
auto result = swap_endianness_u64(before);
|
||||
|
||||
std::vector<unsigned char> after = {
|
||||
56, 57, 58, 59, 60, 61, 62, 63,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7
|
||||
};
|
||||
|
||||
EXPECT_EQ(after, result);
|
||||
|
||||
std::vector<unsigned char> bad = {0, 1, 2, 3};
|
||||
|
||||
ASSERT_THROW(swap_endianness_u64(bad), std::length_error);
|
||||
}
|
||||
|
||||
template<typename FieldT>
|
||||
bool test_merkle_gadget(
|
||||
bool enforce_a,
|
||||
bool enforce_b,
|
||||
bool write_root_first
|
||||
)
|
||||
{
|
||||
protoboard<FieldT> pb;
|
||||
digest_variable<FieldT> root(pb, 256, "root");
|
||||
pb.set_input_sizes(256);
|
||||
|
||||
digest_variable<FieldT> commitment1(pb, 256, "commitment1");
|
||||
digest_variable<FieldT> commitment2(pb, 256, "commitment2");
|
||||
|
||||
pb_variable<FieldT> commitment1_read;
|
||||
commitment1_read.allocate(pb);
|
||||
pb_variable<FieldT> commitment2_read;
|
||||
commitment2_read.allocate(pb);
|
||||
|
||||
merkle_tree_gadget<FieldT> mgadget1(pb, commitment1, root, commitment1_read);
|
||||
merkle_tree_gadget<FieldT> mgadget2(pb, commitment2, root, commitment2_read);
|
||||
|
||||
commitment1.generate_r1cs_constraints();
|
||||
commitment2.generate_r1cs_constraints();
|
||||
root.generate_r1cs_constraints();
|
||||
mgadget1.generate_r1cs_constraints();
|
||||
mgadget2.generate_r1cs_constraints();
|
||||
|
||||
SproutMerkleTree tree;
|
||||
uint256 commitment1_data = uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c");
|
||||
uint256 commitment2_data = uint256S("59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7");
|
||||
tree.append(commitment1_data);
|
||||
auto wit1 = tree.witness();
|
||||
tree.append(commitment2_data);
|
||||
wit1.append(commitment2_data);
|
||||
auto wit2 = tree.witness();
|
||||
auto expected_root = tree.root();
|
||||
tree.append(uint256S("3e243c8798678570bb8d42616c23a536af44be15c4eef073490c2a44ae5f32c3"));
|
||||
auto unexpected_root = tree.root();
|
||||
tree.append(uint256S("26d9b20c7f1c3d2528bbcd43cd63344b0afd3b6a0a8ebd37ec51cba34907bec7"));
|
||||
auto badwit1 = tree.witness();
|
||||
tree.append(uint256S("02c2467c9cd15e0d150f74cd636505ed675b0b71b66a719f6f52fdb49a5937bb"));
|
||||
auto badwit2 = tree.witness();
|
||||
|
||||
// Perform the test
|
||||
|
||||
pb.val(commitment1_read) = enforce_a ? FieldT::one() : FieldT::zero();
|
||||
pb.val(commitment2_read) = enforce_b ? FieldT::one() : FieldT::zero();
|
||||
|
||||
commitment1.bits.fill_with_bits(pb, uint256_to_bool_vector(commitment1_data));
|
||||
commitment2.bits.fill_with_bits(pb, uint256_to_bool_vector(commitment2_data));
|
||||
|
||||
if (write_root_first) {
|
||||
root.bits.fill_with_bits(pb, uint256_to_bool_vector(expected_root));
|
||||
}
|
||||
|
||||
mgadget1.generate_r1cs_witness(wit1.path());
|
||||
mgadget2.generate_r1cs_witness(wit2.path());
|
||||
|
||||
// Overwrite with our expected root
|
||||
root.bits.fill_with_bits(pb, uint256_to_bool_vector(expected_root));
|
||||
|
||||
return pb.is_satisfied();
|
||||
}
|
||||
|
||||
TEST(circuit, merkle_tree_gadget_weirdness)
|
||||
{
|
||||
/*
|
||||
The merkle tree gadget takes a leaf in the merkle tree (the Note commitment),
|
||||
a merkle tree authentication path, and a root (anchor). It also takes a parameter
|
||||
called read_success, which is used to determine if the commitment actually needs to
|
||||
appear in the tree.
|
||||
|
||||
If two input notes use the same root (which our protocol does) then if `read_success`
|
||||
is disabled on the first note but enabled on the second note (i.e., the first note
|
||||
has value of zero and second note has nonzero value) then there is an edge case in
|
||||
the witnessing behavior. The first witness will accidentally constrain the root to
|
||||
equal null (the default value of the anchor) and the second witness will actually
|
||||
copy the bits, violating the constraint system.
|
||||
|
||||
Notice that this edge case is not in the constraint system but in the witnessing
|
||||
behavior.
|
||||
*/
|
||||
|
||||
typedef Fr<default_r1cs_ppzksnark_pp> FieldT;
|
||||
|
||||
// Test the normal case
|
||||
ASSERT_TRUE(test_merkle_gadget<FieldT>(true, true, false));
|
||||
ASSERT_TRUE(test_merkle_gadget<FieldT>(true, true, true));
|
||||
|
||||
// Test the case where the first commitment is enforced but the second isn't
|
||||
// Works because the first read is performed before the second one
|
||||
ASSERT_TRUE(test_merkle_gadget<FieldT>(true, false, false));
|
||||
ASSERT_TRUE(test_merkle_gadget<FieldT>(true, false, true));
|
||||
|
||||
// Test the case where the first commitment isn't enforced but the second is
|
||||
// Doesn't work because the first multipacker witnesses the existing root (which
|
||||
// is null)
|
||||
ASSERT_TRUE(!test_merkle_gadget<FieldT>(false, true, false));
|
||||
|
||||
// Test the last again, except this time write the root first.
|
||||
ASSERT_TRUE(test_merkle_gadget<FieldT>(false, true, true));
|
||||
}
|
||||
@@ -22,10 +22,9 @@ using namespace libzcash;
|
||||
|
||||
extern ZCJoinSplit* params;
|
||||
|
||||
typedef std::array<JSDescription, 2> SproutProofs;
|
||||
// Make both the PHGR and Groth proof for a Sprout statement,
|
||||
// and store the results in JSDescription objects.
|
||||
SproutProofs makeSproutProofs(
|
||||
// Make the Groth proof for a Sprout statement,
|
||||
// and store the result in a JSDescription object.
|
||||
JSDescription makeSproutProof(
|
||||
ZCJoinSplit& js,
|
||||
const std::array<JSInput, 2>& inputs,
|
||||
const std::array<JSOutput, 2>& outputs,
|
||||
@@ -34,25 +33,17 @@ SproutProofs makeSproutProofs(
|
||||
uint64_t vpub_new,
|
||||
const uint256& rt
|
||||
){
|
||||
//Making the PHGR proof
|
||||
JSDescription phgr(false, js, joinSplitPubKey, rt, inputs, outputs, vpub_old, vpub_new);
|
||||
//Making the Groth proof
|
||||
JSDescription groth(true, js, joinSplitPubKey, rt, inputs, outputs, vpub_old, vpub_new);
|
||||
|
||||
return {phgr, groth};
|
||||
|
||||
return JSDescription(js, joinSplitPubKey, rt, inputs, outputs, vpub_old, vpub_new);
|
||||
}
|
||||
|
||||
bool verifySproutProofs(
|
||||
bool verifySproutProof(
|
||||
ZCJoinSplit& js,
|
||||
const SproutProofs& jsdescs,
|
||||
const JSDescription& jsdesc,
|
||||
const uint256& joinSplitPubKey
|
||||
)
|
||||
{
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
bool phgrPassed = jsdescs[0].Verify(js, verifier, joinSplitPubKey);
|
||||
bool grothPassed = jsdescs[1].Verify(js, verifier, joinSplitPubKey);
|
||||
return phgrPassed && grothPassed;
|
||||
return jsdesc.Verify(js, verifier, joinSplitPubKey);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +64,7 @@ void test_full_api(ZCJoinSplit* js)
|
||||
uint64_t vpub_new = 0;
|
||||
uint256 joinSplitPubKey = random_uint256();
|
||||
uint256 rt = tree.root();
|
||||
SproutProofs jsdescs;
|
||||
JSDescription jsdesc;
|
||||
|
||||
{
|
||||
std::array<JSInput, 2> inputs = {
|
||||
@@ -89,7 +80,7 @@ void test_full_api(ZCJoinSplit* js)
|
||||
std::array<SproutNote, 2> output_notes;
|
||||
|
||||
// Perform the proofs
|
||||
jsdescs = makeSproutProofs(
|
||||
jsdesc = makeSproutProof(
|
||||
*js,
|
||||
inputs,
|
||||
outputs,
|
||||
@@ -101,13 +92,11 @@ void test_full_api(ZCJoinSplit* js)
|
||||
}
|
||||
|
||||
// Verify both PHGR and Groth Proof:
|
||||
ASSERT_TRUE(verifySproutProofs(*js, jsdescs, joinSplitPubKey));
|
||||
ASSERT_TRUE(verifySproutProof(*js, jsdesc, joinSplitPubKey));
|
||||
|
||||
// Run tests using both phgr and groth as basis for field values
|
||||
for (auto jsdesc : jsdescs)
|
||||
{
|
||||
SproutMerkleTree tree;
|
||||
SproutProofs jsdescs2;
|
||||
JSDescription jsdesc2;
|
||||
// Recipient should decrypt
|
||||
// Now the recipient should spend the money again
|
||||
auto h_sig = js->h_sig(jsdesc.randomSeed, jsdesc.nullifiers, joinSplitPubKey);
|
||||
@@ -153,7 +142,7 @@ void test_full_api(ZCJoinSplit* js)
|
||||
|
||||
|
||||
// Perform the proofs
|
||||
jsdescs2 = makeSproutProofs(
|
||||
jsdesc2 = makeSproutProof(
|
||||
*js,
|
||||
inputs,
|
||||
outputs,
|
||||
@@ -166,8 +155,8 @@ void test_full_api(ZCJoinSplit* js)
|
||||
}
|
||||
|
||||
|
||||
// Verify both PHGR and Groth Proof:
|
||||
ASSERT_TRUE(verifySproutProofs(*js, jsdescs2, joinSplitPubKey2));
|
||||
// Verify Groth Proof:
|
||||
ASSERT_TRUE(verifySproutProof(*js, jsdesc2, joinSplitPubKey2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,28 +180,8 @@ void invokeAPI(
|
||||
|
||||
std::array<SproutNote, 2> output_notes;
|
||||
|
||||
// PHGR
|
||||
SproutProof proof = js->prove(
|
||||
false,
|
||||
inputs,
|
||||
outputs,
|
||||
output_notes,
|
||||
ciphertexts,
|
||||
ephemeralKey,
|
||||
joinSplitPubKey,
|
||||
randomSeed,
|
||||
macs,
|
||||
nullifiers,
|
||||
commitments,
|
||||
vpub_old,
|
||||
vpub_new,
|
||||
rt,
|
||||
false
|
||||
);
|
||||
|
||||
// Groth
|
||||
proof = js->prove(
|
||||
true,
|
||||
SproutProof proof = js->prove(
|
||||
inputs,
|
||||
outputs,
|
||||
output_notes,
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "test/data/merkle_roots.json.h"
|
||||
#include "test/data/merkle_roots_empty.json.h"
|
||||
#include "test/data/merkle_serialization.json.h"
|
||||
#include "test/data/merkle_witness_serialization.json.h"
|
||||
#include "test/data/merkle_path.json.h"
|
||||
#include "test/data/merkle_commitments.json.h"
|
||||
|
||||
#include "test/data/merkle_roots_sapling.json.h"
|
||||
#include "test/data/merkle_roots_empty_sapling.json.h"
|
||||
#include "test/data/merkle_serialization_sapling.json.h"
|
||||
#include "test/data/merkle_witness_serialization_sapling.json.h"
|
||||
#include "test/data/merkle_path_sapling.json.h"
|
||||
@@ -26,17 +24,11 @@
|
||||
#include "zcash/IncrementalMerkleTree.hpp"
|
||||
#include "zcash/util.h"
|
||||
|
||||
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
|
||||
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
|
||||
#include <libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp>
|
||||
#include <libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "json_test_vectors.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace libsnark;
|
||||
|
||||
template<>
|
||||
void expect_deser_same(const SproutTestingWitness& expected)
|
||||
@@ -58,8 +50,7 @@ void test_tree(
|
||||
UniValue root_tests,
|
||||
UniValue ser_tests,
|
||||
UniValue witness_ser_tests,
|
||||
UniValue path_tests,
|
||||
bool libsnark_test
|
||||
UniValue path_tests
|
||||
)
|
||||
{
|
||||
size_t witness_ser_i = 0;
|
||||
@@ -115,55 +106,6 @@ void test_tree(
|
||||
} else {
|
||||
auto path = wit.path();
|
||||
expect_test_vector(path_tests[path_i++], path);
|
||||
|
||||
if (libsnark_test) {
|
||||
typedef Fr<default_r1cs_ppzksnark_pp> FieldT;
|
||||
|
||||
protoboard<FieldT> pb;
|
||||
pb_variable_array<FieldT> positions;
|
||||
digest_variable<FieldT> commitment(pb, 256, "commitment");
|
||||
digest_variable<FieldT> root(pb, 256, "root");
|
||||
positions.allocate(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "pos");
|
||||
merkle_authentication_path_variable<FieldT, sha256_two_to_one_hash_gadget<FieldT>> authvars(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "auth");
|
||||
merkle_tree_check_read_gadget<FieldT, sha256_two_to_one_hash_gadget<FieldT>> auth(
|
||||
pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, positions, commitment, root, authvars, ONE, "path"
|
||||
);
|
||||
commitment.generate_r1cs_constraints();
|
||||
root.generate_r1cs_constraints();
|
||||
authvars.generate_r1cs_constraints();
|
||||
auth.generate_r1cs_constraints();
|
||||
|
||||
std::vector<bool> commitment_bv;
|
||||
{
|
||||
uint256 witnessed_commitment = wit.element();
|
||||
std::vector<unsigned char> commitment_v(witnessed_commitment.begin(), witnessed_commitment.end());
|
||||
commitment_bv = convertBytesVectorToVector(commitment_v);
|
||||
}
|
||||
|
||||
size_t path_index = convertVectorToInt(path.index);
|
||||
|
||||
commitment.bits.fill_with_bits(pb, bit_vector(commitment_bv));
|
||||
positions.fill_with_bits_of_uint64(pb, path_index);
|
||||
|
||||
authvars.generate_r1cs_witness(path_index, path.authentication_path);
|
||||
auth.generate_r1cs_witness();
|
||||
|
||||
std::vector<bool> root_bv;
|
||||
{
|
||||
uint256 witroot = wit.root();
|
||||
std::vector<unsigned char> root_v(witroot.begin(), witroot.end());
|
||||
root_bv = convertBytesVectorToVector(root_v);
|
||||
}
|
||||
|
||||
root.bits.fill_with_bits(pb, bit_vector(root_bv));
|
||||
|
||||
ASSERT_TRUE(pb.is_satisfied());
|
||||
|
||||
root_bv[0] = !root_bv[0];
|
||||
root.bits.fill_with_bits(pb, bit_vector(root_bv));
|
||||
|
||||
ASSERT_TRUE(!pb.is_satisfied());
|
||||
}
|
||||
}
|
||||
|
||||
// Check witness serialization
|
||||
@@ -200,8 +142,7 @@ TEST(merkletree, vectors) {
|
||||
root_tests,
|
||||
ser_tests,
|
||||
witness_ser_tests,
|
||||
path_tests,
|
||||
true
|
||||
path_tests
|
||||
);
|
||||
}
|
||||
|
||||
@@ -217,18 +158,19 @@ TEST(merkletree, SaplingVectors) {
|
||||
root_tests,
|
||||
ser_tests,
|
||||
witness_ser_tests,
|
||||
path_tests,
|
||||
false
|
||||
path_tests
|
||||
);
|
||||
}
|
||||
|
||||
TEST(merkletree, emptyroots) {
|
||||
UniValue empty_roots = read_json(MAKE_STRING(json_tests::merkle_roots_empty));
|
||||
|
||||
libzcash::EmptyMerkleRoots<64, libzcash::SHA256Compress> emptyroots;
|
||||
std::array<libzcash::SHA256Compress, 65> computed;
|
||||
|
||||
for (size_t depth = 0; depth <= 64; depth++) {
|
||||
expect_test_vector(empty_roots[depth], emptyroots.empty_root(depth));
|
||||
computed.at(0) = libzcash::SHA256Compress::uncommitted();
|
||||
ASSERT_TRUE(emptyroots.empty_root(0) == computed.at(0));
|
||||
for (size_t d = 1; d <= 64; d++) {
|
||||
computed.at(d) = libzcash::SHA256Compress::combine(computed.at(d-1), computed.at(d-1), d-1);
|
||||
ASSERT_TRUE(emptyroots.empty_root(d) == computed.at(d));
|
||||
}
|
||||
|
||||
// Double check that we're testing (at least) all the empty roots we'll use.
|
||||
@@ -236,12 +178,14 @@ TEST(merkletree, emptyroots) {
|
||||
}
|
||||
|
||||
TEST(merkletree, EmptyrootsSapling) {
|
||||
UniValue empty_roots = read_json(MAKE_STRING(json_tests::merkle_roots_empty_sapling));
|
||||
|
||||
libzcash::EmptyMerkleRoots<62, libzcash::PedersenHash> emptyroots;
|
||||
std::array<libzcash::PedersenHash, 63> computed;
|
||||
|
||||
for (size_t depth = 0; depth <= 62; depth++) {
|
||||
expect_test_vector(empty_roots[depth], emptyroots.empty_root(depth));
|
||||
computed.at(0) = libzcash::PedersenHash::uncommitted();
|
||||
ASSERT_TRUE(emptyroots.empty_root(0) == computed.at(0));
|
||||
for (size_t d = 1; d <= 62; d++) {
|
||||
computed.at(d) = libzcash::PedersenHash::combine(computed.at(d-1), computed.at(d-1), d-1);
|
||||
ASSERT_TRUE(emptyroots.empty_root(d) == computed.at(d));
|
||||
}
|
||||
|
||||
// Double check that we're testing (at least) all the empty roots we'll use.
|
||||
@@ -249,7 +193,7 @@ TEST(merkletree, EmptyrootsSapling) {
|
||||
}
|
||||
|
||||
TEST(merkletree, emptyroot) {
|
||||
// This literal is the depth-20 empty tree root with the bytes reversed to
|
||||
// This literal is the depth-29 empty tree root with the bytes reversed to
|
||||
// account for the fact that uint256S() loads a big-endian representation of
|
||||
// an integer which converted to little-endian internally.
|
||||
uint256 expected = uint256S("59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7");
|
||||
@@ -258,7 +202,7 @@ TEST(merkletree, emptyroot) {
|
||||
}
|
||||
|
||||
TEST(merkletree, EmptyrootSapling) {
|
||||
// This literal is the depth-20 empty tree root with the bytes reversed to
|
||||
// This literal is the depth-32 empty tree root with the bytes reversed to
|
||||
// account for the fact that uint256S() loads a big-endian representation of
|
||||
// an integer which converted to little-endian internally.
|
||||
uint256 expected = uint256S("3e49b5f954aa9d3545bc6c37744661eea48d7c34e3000d82b7f0010c30f4c2fb");
|
||||
|
||||
@@ -1,702 +0,0 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "zcash/Proof.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
|
||||
#include <libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp>
|
||||
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
|
||||
|
||||
using namespace libzcash;
|
||||
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp curve_pp;
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp::G1_type curve_G1;
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp::G2_type curve_G2;
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp::GT_type curve_GT;
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp::Fp_type curve_Fr;
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp::Fq_type curve_Fq;
|
||||
typedef libsnark::default_r1cs_ppzksnark_pp::Fqe_type curve_Fq2;
|
||||
|
||||
#include "streams.h"
|
||||
#include "version.h"
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
TEST(proofs, g1_pairing_at_infinity)
|
||||
{
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
auto r1 = curve_G1::random_element();
|
||||
auto r2 = curve_G2::random_element();
|
||||
ASSERT_TRUE(
|
||||
curve_pp::reduced_pairing(curve_G1::zero(), r2) ==
|
||||
curve_GT::one()
|
||||
);
|
||||
ASSERT_TRUE(
|
||||
curve_pp::final_exponentiation(
|
||||
curve_pp::double_miller_loop(
|
||||
curve_pp::precompute_G1(curve_G1::zero()),
|
||||
curve_pp::precompute_G2(r2),
|
||||
curve_pp::precompute_G1(curve_G1::zero()),
|
||||
curve_pp::precompute_G2(r2)
|
||||
)
|
||||
) ==
|
||||
curve_GT::one()
|
||||
);
|
||||
ASSERT_TRUE(
|
||||
curve_pp::final_exponentiation(
|
||||
curve_pp::double_miller_loop(
|
||||
curve_pp::precompute_G1(r1),
|
||||
curve_pp::precompute_G2(r2),
|
||||
curve_pp::precompute_G1(curve_G1::zero()),
|
||||
curve_pp::precompute_G2(r2)
|
||||
)
|
||||
) ==
|
||||
curve_pp::reduced_pairing(r1, r2)
|
||||
);
|
||||
ASSERT_TRUE(
|
||||
curve_pp::final_exponentiation(
|
||||
curve_pp::double_miller_loop(
|
||||
curve_pp::precompute_G1(curve_G1::zero()),
|
||||
curve_pp::precompute_G2(r2),
|
||||
curve_pp::precompute_G1(r1),
|
||||
curve_pp::precompute_G2(r2)
|
||||
)
|
||||
) ==
|
||||
curve_pp::reduced_pairing(r1, r2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, g2_subgroup_check)
|
||||
{
|
||||
// all G2 elements are order r
|
||||
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * curve_G2::random_element() == curve_G2::zero());
|
||||
|
||||
// but that doesn't mean all elements that satisfy the curve equation are in G2...
|
||||
curve_G2 p = curve_G2::one();
|
||||
|
||||
while (1) {
|
||||
// This will construct an order r(2q-r) point with high probability
|
||||
p.X = curve_Fq2::random_element();
|
||||
try {
|
||||
p.Y = ((p.X.squared() * p.X) + libsnark::alt_bn128_twist_coeff_b).sqrt();
|
||||
break;
|
||||
} catch(...) {}
|
||||
}
|
||||
|
||||
ASSERT_TRUE(p.is_well_formed()); // it's on the curve
|
||||
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * p != curve_G2::zero()); // but not the order r subgroup..
|
||||
|
||||
{
|
||||
// libsnark unfortunately doesn't check, and the pairing will complete
|
||||
auto e = curve_Fr("149");
|
||||
auto a = curve_pp::reduced_pairing(curve_G1::one(), p);
|
||||
auto b = curve_pp::reduced_pairing(e * curve_G1::one(), p);
|
||||
|
||||
// though it will not preserve bilinearity
|
||||
ASSERT_TRUE((a^e) != b);
|
||||
}
|
||||
|
||||
{
|
||||
// so, our decompression API should not allow you to decompress G2 elements of that form!
|
||||
CompressedG2 badp(p);
|
||||
try {
|
||||
auto newp = badp.to_libsnark_g2<curve_G2>();
|
||||
FAIL() << "Expected std::runtime_error";
|
||||
} catch (std::runtime_error const & err) {
|
||||
EXPECT_EQ(err.what(), std::string("point is not in G2"));
|
||||
} catch(...) {
|
||||
FAIL() << "Expected std::runtime_error";
|
||||
}
|
||||
}
|
||||
|
||||
// educational purposes: showing that E'(Fp2) is of order r(2q-r),
|
||||
// by multiplying our random point in E' by (2q-r) = (q + q - r) to
|
||||
// get an element in G2
|
||||
{
|
||||
auto p1 = libsnark::alt_bn128_modulus_q * p;
|
||||
p1 = p1 + p1;
|
||||
p1 = p1 - (libsnark::alt_bn128_modulus_r * p);
|
||||
|
||||
ASSERT_TRUE(p1.is_well_formed());
|
||||
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * p1 == curve_G2::zero());
|
||||
|
||||
CompressedG2 goodp(p1);
|
||||
auto newp = goodp.to_libsnark_g2<curve_G2>();
|
||||
|
||||
ASSERT_TRUE(newp == p1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, sqrt_zero)
|
||||
{
|
||||
ASSERT_TRUE(curve_Fq::zero() == curve_Fq::zero().sqrt());
|
||||
ASSERT_TRUE(curve_Fq2::zero() == curve_Fq2::zero().sqrt());
|
||||
}
|
||||
|
||||
TEST(proofs, sqrt_fq)
|
||||
{
|
||||
// Poor man's PRNG
|
||||
curve_Fq acc = curve_Fq("348957923485290374852379485") ^ 1000;
|
||||
|
||||
size_t quadratic_residues = 0;
|
||||
size_t quadratic_nonresidues = 0;
|
||||
|
||||
for (size_t i = 1; i < 1000; i++) {
|
||||
try {
|
||||
acc += curve_Fq("45634563456") ^ i;
|
||||
|
||||
curve_Fq x = acc.sqrt();
|
||||
ASSERT_TRUE((x*x) == acc);
|
||||
quadratic_residues += 1;
|
||||
} catch (std::runtime_error &e) {
|
||||
quadratic_nonresidues += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Half of all nonzero elements in Fp are quadratic residues
|
||||
ASSERT_TRUE(quadratic_residues == 511);
|
||||
ASSERT_TRUE(quadratic_nonresidues == 488);
|
||||
|
||||
for (size_t i = 0; i < 1000; i++) {
|
||||
curve_Fq x = curve_Fq::random_element();
|
||||
curve_Fq x2 = x * x;
|
||||
|
||||
ASSERT_TRUE((x2.sqrt() == x) || (x2.sqrt() == -x));
|
||||
}
|
||||
|
||||
// Test vectors
|
||||
ASSERT_TRUE(
|
||||
curve_Fq("5204065062716160319596273903996315000119019512886596366359652578430118331601")
|
||||
==
|
||||
curve_Fq("348579348568").sqrt()
|
||||
);
|
||||
ASSERT_THROW(curve_Fq("348579348569").sqrt(), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST(proofs, sqrt_fq2)
|
||||
{
|
||||
curve_Fq2 acc = curve_Fq2(
|
||||
curve_Fq("3456293840592348059238409578239048769348760238476029347885092384059238459834") ^ 1000,
|
||||
curve_Fq("2394578084760439457823945729347502374590283479582739485723945729384759823745") ^ 1000
|
||||
);
|
||||
|
||||
size_t quadratic_residues = 0;
|
||||
size_t quadratic_nonresidues = 0;
|
||||
|
||||
for (size_t i = 1; i < 1000; i++) {
|
||||
try {
|
||||
acc = acc + curve_Fq2(
|
||||
curve_Fq("5204065062716160319596273903996315000119019512886596366359652578430118331601") ^ i,
|
||||
curve_Fq("348957923485290374852379485348957923485290374852379485348957923485290374852") ^ i
|
||||
);
|
||||
|
||||
curve_Fq2 x = acc.sqrt();
|
||||
ASSERT_TRUE((x*x) == acc);
|
||||
quadratic_residues += 1;
|
||||
} catch (std::runtime_error &e) {
|
||||
quadratic_nonresidues += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Half of all nonzero elements in Fp^k are quadratic residues as long
|
||||
// as p != 2
|
||||
ASSERT_TRUE(quadratic_residues == 505);
|
||||
ASSERT_TRUE(quadratic_nonresidues == 494);
|
||||
|
||||
for (size_t i = 0; i < 1000; i++) {
|
||||
curve_Fq2 x = curve_Fq2::random_element();
|
||||
curve_Fq2 x2 = x * x;
|
||||
|
||||
ASSERT_TRUE((x2.sqrt() == x) || (x2.sqrt() == -x));
|
||||
}
|
||||
|
||||
// Test vectors
|
||||
ASSERT_THROW(curve_Fq2(
|
||||
curve_Fq("2"),
|
||||
curve_Fq("1")
|
||||
).sqrt(), std::runtime_error);
|
||||
|
||||
ASSERT_THROW(curve_Fq2(
|
||||
curve_Fq("3345897230485723946872934576923485762803457692345760237495682347502347589473"),
|
||||
curve_Fq("1234912378405347958234756902345768290345762348957605678245967234857634857676")
|
||||
).sqrt(), std::runtime_error);
|
||||
|
||||
curve_Fq2 x = curve_Fq2(
|
||||
curve_Fq("12844195307879678418043983815760255909500142247603239203345049921980497041944"),
|
||||
curve_Fq("7476417578426924565731404322659619974551724117137577781074613937423560117731")
|
||||
);
|
||||
|
||||
curve_Fq2 nx = -x;
|
||||
|
||||
curve_Fq2 x2 = curve_Fq2(
|
||||
curve_Fq("3345897230485723946872934576923485762803457692345760237495682347502347589474"),
|
||||
curve_Fq("1234912378405347958234756902345768290345762348957605678245967234857634857676")
|
||||
);
|
||||
|
||||
ASSERT_TRUE(x == x2.sqrt());
|
||||
ASSERT_TRUE(nx == -x2.sqrt());
|
||||
ASSERT_TRUE(x*x == x2);
|
||||
ASSERT_TRUE(nx*nx == x2);
|
||||
}
|
||||
|
||||
TEST(proofs, size_is_expected)
|
||||
{
|
||||
PHGRProof p;
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << p;
|
||||
|
||||
ASSERT_EQ(ss.size(), 296);
|
||||
}
|
||||
|
||||
TEST(proofs, fq_serializes_properly)
|
||||
{
|
||||
for (size_t i = 0; i < 1000; i++) {
|
||||
curve_Fq e = curve_Fq::random_element();
|
||||
|
||||
Fq e2(e);
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << e2;
|
||||
|
||||
Fq e3;
|
||||
ss >> e3;
|
||||
|
||||
curve_Fq e4 = e3.to_libsnark_fq<curve_Fq>();
|
||||
|
||||
ASSERT_TRUE(e == e4);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, fq2_serializes_properly)
|
||||
{
|
||||
for (size_t i = 0; i < 1000; i++) {
|
||||
curve_Fq2 e = curve_Fq2::random_element();
|
||||
|
||||
Fq2 e2(e);
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << e2;
|
||||
|
||||
Fq2 e3;
|
||||
ss >> e3;
|
||||
|
||||
curve_Fq2 e4 = e3.to_libsnark_fq2<curve_Fq2>();
|
||||
|
||||
ASSERT_TRUE(e == e4);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T deserialize_tv(std::string s)
|
||||
{
|
||||
T e;
|
||||
CDataStream ss(ParseHex(s), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> e;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
curve_Fq deserialize_fq(std::string s)
|
||||
{
|
||||
return deserialize_tv<Fq>(s).to_libsnark_fq<curve_Fq>();
|
||||
}
|
||||
|
||||
curve_Fq2 deserialize_fq2(std::string s)
|
||||
{
|
||||
return deserialize_tv<Fq2>(s).to_libsnark_fq2<curve_Fq2>();
|
||||
}
|
||||
|
||||
TEST(proofs, fq_valid)
|
||||
{
|
||||
curve_Fq e = deserialize_fq("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46");
|
||||
|
||||
ASSERT_TRUE(e == curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"));
|
||||
ASSERT_TRUE(e != curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208581"));
|
||||
|
||||
curve_Fq e2 = deserialize_fq("30644e72e131a029b75045b68181585d97816a916871ca8d3c208c16d87cfd46");
|
||||
|
||||
ASSERT_TRUE(e2 == curve_Fq("21888242871839275222221885816603420866962577604863418715751138068690288573766"));
|
||||
}
|
||||
|
||||
TEST(proofs, fq_invalid)
|
||||
{
|
||||
// Should not be able to deserialize the modulus
|
||||
ASSERT_THROW(
|
||||
deserialize_fq("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"),
|
||||
std::logic_error
|
||||
);
|
||||
|
||||
// Should not be able to deserialize the modulus plus one
|
||||
ASSERT_THROW(
|
||||
deserialize_fq("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd48"),
|
||||
std::logic_error
|
||||
);
|
||||
|
||||
// Should not be able to deserialize a ridiculously out of bound int
|
||||
ASSERT_THROW(
|
||||
deserialize_fq("ff644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46"),
|
||||
std::logic_error
|
||||
);
|
||||
}
|
||||
|
||||
TEST(proofs, fq2_valid)
|
||||
{
|
||||
// (q - 1) * q + q
|
||||
curve_Fq2 e = deserialize_fq2("0925c4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b0");
|
||||
ASSERT_TRUE(e.c0 == curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"));
|
||||
ASSERT_TRUE(e.c1 == curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"));
|
||||
|
||||
curve_Fq2 e2 = deserialize_fq2("000000000000000000000000000000000000000000000000010245be1c91e3186bbbe1c430a93fcfc5aada4ab10c3492f70eea97a91c7b29554db55acffa34d2");
|
||||
ASSERT_TRUE(e2.c0 == curve_Fq("238769481237490823"));
|
||||
ASSERT_TRUE(e2.c1 == curve_Fq("384579238459723485"));
|
||||
|
||||
curve_Fq2 e3 = deserialize_fq2("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
|
||||
ASSERT_TRUE(e3.c0 == curve_Fq("0"));
|
||||
ASSERT_TRUE(e3.c1 == curve_Fq("0"));
|
||||
|
||||
curve_Fq2 e4 = deserialize_fq2("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001");
|
||||
ASSERT_TRUE(e4.c0 == curve_Fq("1"));
|
||||
ASSERT_TRUE(e4.c1 == curve_Fq("0"));
|
||||
}
|
||||
|
||||
TEST(proofs, fq2_invalid)
|
||||
{
|
||||
// (q - 1) * q + q is invalid
|
||||
ASSERT_THROW(
|
||||
deserialize_fq2("0925c4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b1"),
|
||||
std::logic_error
|
||||
);
|
||||
|
||||
// q * q + (q - 1) is invalid
|
||||
ASSERT_THROW(
|
||||
deserialize_fq2("0925c4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d34cced085b43e2f202a05e52ef18233a3d8371be725c8b8e7774e4b8ffda66f7"),
|
||||
std::logic_error
|
||||
);
|
||||
|
||||
// Ridiculously out of bounds
|
||||
ASSERT_THROW(
|
||||
deserialize_fq2("0fffc4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b0"),
|
||||
std::logic_error
|
||||
);
|
||||
ASSERT_THROW(
|
||||
deserialize_fq2("ffffffff763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b0"),
|
||||
std::logic_error
|
||||
);
|
||||
}
|
||||
|
||||
TEST(proofs, g1_serializes_properly)
|
||||
{
|
||||
// Cannot serialize zero
|
||||
{
|
||||
ASSERT_THROW({CompressedG1 g = CompressedG1(curve_G1::zero());}, std::domain_error);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 1000; i++) {
|
||||
curve_G1 e = curve_G1::random_element();
|
||||
|
||||
CompressedG1 e2(e);
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << e2;
|
||||
|
||||
CompressedG1 e3;
|
||||
ss >> e3;
|
||||
|
||||
ASSERT_TRUE(e2 == e3);
|
||||
|
||||
curve_G1 e4 = e3.to_libsnark_g1<curve_G1>();
|
||||
|
||||
ASSERT_TRUE(e == e4);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, g2_serializes_properly)
|
||||
{
|
||||
// Cannot serialize zero
|
||||
{
|
||||
ASSERT_THROW({CompressedG2 g = CompressedG2(curve_G2::zero());}, std::domain_error);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 1000; i++) {
|
||||
curve_G2 e = curve_G2::random_element();
|
||||
|
||||
CompressedG2 e2(e);
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << e2;
|
||||
|
||||
CompressedG2 e3;
|
||||
ss >> e3;
|
||||
|
||||
ASSERT_TRUE(e2 == e3);
|
||||
|
||||
curve_G2 e4 = e3.to_libsnark_g2<curve_G2>();
|
||||
|
||||
ASSERT_TRUE(e == e4);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, zksnark_serializes_properly)
|
||||
{
|
||||
auto example = libsnark::generate_r1cs_example_with_field_input<curve_Fr>(250, 4);
|
||||
example.constraint_system.swap_AB_if_beneficial();
|
||||
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 = PHGRProof::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++) {
|
||||
auto proof = libsnark::r1cs_ppzksnark_prover<curve_pp>(
|
||||
kp.pk,
|
||||
example.primary_input,
|
||||
example.auxiliary_input,
|
||||
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>(
|
||||
kp.vk,
|
||||
example.primary_input,
|
||||
proof
|
||||
));
|
||||
|
||||
PHGRProof compressed_proof_0(proof);
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << compressed_proof_0;
|
||||
|
||||
PHGRProof compressed_proof_1;
|
||||
ss >> compressed_proof_1;
|
||||
|
||||
ASSERT_TRUE(compressed_proof_0 == compressed_proof_1);
|
||||
|
||||
auto newproof = compressed_proof_1.to_libsnark_proof<libsnark::r1cs_ppzksnark_proof<curve_pp>>();
|
||||
|
||||
ASSERT_TRUE(proof == newproof);
|
||||
ASSERT_TRUE(libsnark::r1cs_ppzksnark_verifier_strong_IC<curve_pp>(
|
||||
kp.vk,
|
||||
example.primary_input,
|
||||
newproof
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, g1_deserialization)
|
||||
{
|
||||
CompressedG1 g;
|
||||
curve_G1 expected;
|
||||
|
||||
// Valid G1 element.
|
||||
{
|
||||
CDataStream ss(ParseHex("0230644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
expected.X = curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582");
|
||||
expected.Y = curve_Fq("3969792565221544645472939191694882283483352126195956956354061729942568608776");
|
||||
expected.Z = curve_Fq::one();
|
||||
|
||||
ASSERT_TRUE(g.to_libsnark_g1<curve_G1>() == expected);
|
||||
}
|
||||
|
||||
// Its negation.
|
||||
{
|
||||
CDataStream ss(ParseHex("0330644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
expected.X = curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582");
|
||||
expected.Y = curve_Fq("3969792565221544645472939191694882283483352126195956956354061729942568608776");
|
||||
expected.Z = curve_Fq::one();
|
||||
|
||||
ASSERT_TRUE(g.to_libsnark_g1<curve_G1>() == -expected);
|
||||
}
|
||||
|
||||
// Invalid leading bytes
|
||||
{
|
||||
CDataStream ss(ParseHex("ff30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
ASSERT_THROW(ss >> g, std::ios_base::failure);
|
||||
}
|
||||
|
||||
// Invalid point
|
||||
{
|
||||
CDataStream ss(ParseHex("0208c6d2adffacbc8438f09f321874ea66e2fcc29f8dcfec2caefa21ec8c96a77c"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
ASSERT_THROW(g.to_libsnark_g1<curve_G1>(), std::runtime_error);
|
||||
}
|
||||
|
||||
// Point with out of bounds Fq
|
||||
{
|
||||
CDataStream ss(ParseHex("02ffc6d2adffacbc8438f09f321874ea66e2fcc29f8dcfec2caefa21ec8c96a77c"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
ASSERT_THROW(g.to_libsnark_g1<curve_G1>(), std::logic_error);
|
||||
}
|
||||
|
||||
// Randomly produce valid G1 representations and fail/succeed to
|
||||
// turn them into G1 points based on whether they are valid.
|
||||
for (size_t i = 0; i < 5000; i++) {
|
||||
curve_Fq e = curve_Fq::random_element();
|
||||
CDataStream ss(ParseHex("02"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << Fq(e);
|
||||
CompressedG1 g;
|
||||
ss >> g;
|
||||
|
||||
try {
|
||||
curve_G1 g_real = g.to_libsnark_g1<curve_G1>();
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(proofs, g2_deserialization)
|
||||
{
|
||||
CompressedG2 g;
|
||||
curve_G2 expected = curve_G2::random_element();
|
||||
|
||||
// Valid G2 point
|
||||
{
|
||||
CDataStream ss(ParseHex("0a023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
expected.X = curve_Fq2(
|
||||
curve_Fq("5923585509243758863255447226263146374209884951848029582715967108651637186684"),
|
||||
curve_Fq("5336385337059958111259504403491065820971993066694750945459110579338490853570")
|
||||
);
|
||||
expected.Y = curve_Fq2(
|
||||
curve_Fq("10374495865873200088116930399159835104695426846400310764827677226300185211748"),
|
||||
curve_Fq("5256529835065685814318509161957442385362539991735248614869838648137856366932")
|
||||
);
|
||||
expected.Z = curve_Fq2::one();
|
||||
|
||||
ASSERT_TRUE(g.to_libsnark_g2<curve_G2>() == expected);
|
||||
}
|
||||
|
||||
// Its negation
|
||||
{
|
||||
CDataStream ss(ParseHex("0b023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
expected.X = curve_Fq2(
|
||||
curve_Fq("5923585509243758863255447226263146374209884951848029582715967108651637186684"),
|
||||
curve_Fq("5336385337059958111259504403491065820971993066694750945459110579338490853570")
|
||||
);
|
||||
expected.Y = curve_Fq2(
|
||||
curve_Fq("10374495865873200088116930399159835104695426846400310764827677226300185211748"),
|
||||
curve_Fq("5256529835065685814318509161957442385362539991735248614869838648137856366932")
|
||||
);
|
||||
expected.Z = curve_Fq2::one();
|
||||
|
||||
ASSERT_TRUE(g.to_libsnark_g2<curve_G2>() == -expected);
|
||||
}
|
||||
|
||||
// Invalid leading bytes
|
||||
{
|
||||
CDataStream ss(ParseHex("ff023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
ASSERT_THROW(ss >> g, std::ios_base::failure);
|
||||
}
|
||||
|
||||
|
||||
// Invalid point
|
||||
{
|
||||
CDataStream ss(ParseHex("0b023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984b"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
ASSERT_THROW(g.to_libsnark_g2<curve_G2>(), std::runtime_error);
|
||||
}
|
||||
|
||||
// Point with out of bounds Fq2
|
||||
{
|
||||
CDataStream ss(ParseHex("0a0f3aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss >> g;
|
||||
|
||||
ASSERT_THROW(g.to_libsnark_g2<curve_G2>(), std::logic_error);
|
||||
}
|
||||
|
||||
// Randomly produce valid G2 representations and fail/succeed to
|
||||
// turn them into G2 points based on whether they are valid.
|
||||
for (size_t i = 0; i < 5000; i++) {
|
||||
curve_Fq2 e = curve_Fq2::random_element();
|
||||
CDataStream ss(ParseHex("0a"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << Fq2(e);
|
||||
CompressedG2 g;
|
||||
ss >> g;
|
||||
|
||||
try {
|
||||
curve_G2 g_real = g.to_libsnark_g2<curve_G2>();
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "json_test_vectors.h"
|
||||
#include "test/data/g1_compressed.json.h"
|
||||
|
||||
TEST(proofs, g1_test_vectors)
|
||||
{
|
||||
UniValue v = read_json(std::string(json_tests::g1_compressed, json_tests::g1_compressed + sizeof(json_tests::g1_compressed)));
|
||||
|
||||
curve_G1 e = curve_Fr("34958239045823") * curve_G1::one();
|
||||
for (size_t i = 0; i < 10000; i++) {
|
||||
e = (curve_Fr("34958239045823") ^ i) * e;
|
||||
auto expected = CompressedG1(e);
|
||||
|
||||
expect_test_vector(v[i], expected);
|
||||
ASSERT_TRUE(expected.to_libsnark_g1<curve_G1>() == e);
|
||||
}
|
||||
}
|
||||
|
||||
#include "test/data/g2_compressed.json.h"
|
||||
|
||||
TEST(proofs, g2_test_vectors)
|
||||
{
|
||||
UniValue v = read_json(std::string(json_tests::g2_compressed, json_tests::g2_compressed + sizeof(json_tests::g2_compressed)));
|
||||
|
||||
curve_G2 e = curve_Fr("34958239045823") * curve_G2::one();
|
||||
for (size_t i = 0; i < 10000; i++) {
|
||||
e = (curve_Fr("34958239045823") ^ i) * e;
|
||||
auto expected = CompressedG2(e);
|
||||
|
||||
expect_test_vector(v[i], expected);
|
||||
ASSERT_TRUE(expected.to_libsnark_g2<curve_G2>() == e);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user