Browse Source

zkSNARK: Foundations of circuit design and verification logic.

pull/145/head
Sean Bowe 8 years ago
parent
commit
074eb3a2cf
  1. 4
      src/zcash/JoinSplit.cpp
  2. 125
      src/zcash/circuit/gadget.tcc
  3. 29
      src/zcash/circuit/utils.tcc

4
src/zcash/JoinSplit.cpp

@ -2,6 +2,10 @@
#include "prf.h"
#include "sodium.h"
#include "zerocash/utils/util.h"
#include <memory>
#include <boost/format.hpp>
#include <boost/optional.hpp>
#include <fstream>

125
src/zcash/circuit/gadget.tcc

@ -1,16 +1,66 @@
#include "zcash/circuit/utils.tcc"
template<typename FieldT, size_t NumInputs, size_t NumOutputs>
class joinsplit_gadget : gadget<FieldT> {
private:
// Verifier inputs
pb_variable_array<FieldT> zk_packed_inputs;
pb_variable_array<FieldT> zk_unpacked_inputs;
std::shared_ptr<multipacking_gadget<FieldT>> unpacker;
std::shared_ptr<digest_variable<FieldT>> zk_merkle_root;
std::shared_ptr<digest_variable<FieldT>> zk_h_sig;
boost::array<std::shared_ptr<digest_variable<FieldT>>, NumInputs> zk_input_nullifiers;
boost::array<std::shared_ptr<digest_variable<FieldT>>, NumInputs> zk_input_hmacs;
boost::array<std::shared_ptr<digest_variable<FieldT>>, NumOutputs> zk_output_commitments;
pb_variable_array<FieldT> zk_vpub_old;
pb_variable_array<FieldT> zk_vpub_new;
public:
joinsplit_gadget(protoboard<FieldT> &pb) : gadget<FieldT>(pb) {
pb_variable_array<FieldT> test;
test.allocate(pb, 1);
pb.set_input_sizes(1);
// Verification
{
// The verification inputs are all bit-strings of various
// lengths (256-bit digests and 64-bit integers) and so we
// pack them into as few field elements as possible. (The
// more verification inputs you have, the more expensive
// verification is.)
zk_packed_inputs.allocate(pb, verifying_field_element_size());
pb.set_input_sizes(verifying_field_element_size());
alloc_uint256(zk_unpacked_inputs, zk_merkle_root);
alloc_uint256(zk_unpacked_inputs, zk_h_sig);
for (size_t i = 0; i < NumInputs; i++) {
alloc_uint256(zk_unpacked_inputs, zk_input_nullifiers[i]);
alloc_uint256(zk_unpacked_inputs, zk_input_hmacs[i]);
}
for (size_t i = 0; i < NumOutputs; i++) {
alloc_uint256(zk_unpacked_inputs, zk_output_commitments[i]);
}
// TODO!
alloc_uint64(zk_unpacked_inputs, zk_vpub_old);
alloc_uint64(zk_unpacked_inputs, zk_vpub_new);
assert(zk_unpacked_inputs.size() == verifying_input_bit_size());
// This gadget will ensure that all of the inputs we provide are
// boolean constrained.
unpacker.reset(new multipacking_gadget<FieldT>(
pb,
zk_unpacked_inputs,
zk_packed_inputs,
FieldT::capacity(),
"unpacker"
));
}
}
void generate_r1cs_constraints() {
// TODO!
// The true passed here ensures all the inputs
// are boolean constrained.
unpacker->generate_r1cs_constraints(true);
}
void generate_r1cs_witness(
@ -22,7 +72,9 @@ public:
uint64_t vpub_old,
uint64_t vpub_new
) {
// TODO!
// This happens last, because only by now are all the
// verifier inputs resolved.
unpacker->generate_r1cs_witness_from_bits();
}
static r1cs_primary_input<FieldT> witness_map(
@ -34,11 +86,64 @@ public:
uint64_t vpub_old,
uint64_t vpub_new
) {
// todo
std::vector<bool> verify_inputs;
insert_uint256(verify_inputs, uint256()); // TODO: rt
insert_uint256(verify_inputs, uint256()); // TODO: h_sig
for (size_t i = 0; i < NumInputs; i++) {
insert_uint256(verify_inputs, uint256()); // TODO: nullifier
insert_uint256(verify_inputs, uint256()); // TODO: hmac
}
for (size_t i = 0; i < NumOutputs; i++) {
insert_uint256(verify_inputs, uint256()); // TODO: commitment
}
insert_uint64(verify_inputs, 0); // TODO: vpub_old
insert_uint64(verify_inputs, 0); // TODO: vpub_new
std::vector<FieldT> input_as_field_elements;
input_as_field_elements.push_back(FieldT::zero());
assert(verify_inputs.size() == verifying_input_bit_size());
auto verify_field_elements = pack_bit_vector_into_field_element_vector<FieldT>(verify_inputs);
assert(verify_field_elements.size() == verifying_field_element_size());
return verify_field_elements;
}
static size_t verifying_input_bit_size() {
size_t acc = 0;
acc += 256; // the merkle root (anchor)
acc += 256; // h_sig
for (size_t i = 0; i < NumInputs; i++) {
acc += 256; // nullifier
acc += 256; // hmac
}
for (size_t i = 0; i < NumOutputs; i++) {
acc += 256; // new commitment
}
acc += 64; // vpub_old
acc += 64; // vpub_new
return input_as_field_elements;
return acc;
}
static size_t verifying_field_element_size() {
return div_ceil(verifying_input_bit_size(), FieldT::capacity());
}
void alloc_uint256(
pb_variable_array<FieldT>& packed_into,
std::shared_ptr<digest_variable<FieldT>>& var
) {
var.reset(new digest_variable<FieldT>(this->pb, 256, ""));
packed_into.insert(packed_into.end(), var->bits.begin(), var->bits.end());
}
void alloc_uint64(
pb_variable_array<FieldT>& packed_into,
pb_variable_array<FieldT>& integer
) {
integer.allocate(this->pb, 64, "");
packed_into.insert(packed_into.end(), integer.begin(), integer.end());
}
};

29
src/zcash/circuit/utils.tcc

@ -0,0 +1,29 @@
std::vector<bool> uint256_to_bool_vector(uint256 input) {
std::vector<unsigned char> input_v(input.begin(), input.end());
std::vector<bool> output_bv(256, 0);
libzerocash::convertBytesVectorToVector(
input_v,
output_bv
);
return output_bv;
}
std::vector<bool> uint64_to_bool_vector(uint64_t input) {
std::vector<unsigned char> num_bv(8, 0);
libzerocash::convertIntToBytesVector(input, num_bv);
std::vector<bool> num_v(64, 0);
libzerocash::convertBytesVectorToVector(num_bv, num_v);
return num_v;
}
void insert_uint256(std::vector<bool>& into, uint256 from) {
std::vector<bool> blob = uint256_to_bool_vector(from);
into.insert(into.end(), blob.begin(), blob.end());
}
void insert_uint64(std::vector<bool>& into, uint64_t from) {
std::vector<bool> num = uint64_to_bool_vector(from);
into.insert(into.end(), num.begin(), num.end());
}
Loading…
Cancel
Save