zkSNARK: Foundations of circuit design and verification logic.
This commit is contained in:
parent
369df06583
commit
074eb3a2cf
|
@ -2,6 +2,10 @@
|
||||||
#include "prf.h"
|
#include "prf.h"
|
||||||
#include "sodium.h"
|
#include "sodium.h"
|
||||||
|
|
||||||
|
#include "zerocash/utils/util.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
|
@ -1,16 +1,66 @@
|
||||||
|
#include "zcash/circuit/utils.tcc"
|
||||||
|
|
||||||
template<typename FieldT, size_t NumInputs, size_t NumOutputs>
|
template<typename FieldT, size_t NumInputs, size_t NumOutputs>
|
||||||
class joinsplit_gadget : gadget<FieldT> {
|
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:
|
public:
|
||||||
joinsplit_gadget(protoboard<FieldT> &pb) : gadget<FieldT>(pb) {
|
joinsplit_gadget(protoboard<FieldT> &pb) : gadget<FieldT>(pb) {
|
||||||
pb_variable_array<FieldT> test;
|
// Verification
|
||||||
test.allocate(pb, 1);
|
{
|
||||||
pb.set_input_sizes(1);
|
// 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());
|
||||||
|
|
||||||
// TODO!
|
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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
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(
|
void generate_r1cs_witness(
|
||||||
|
@ -22,7 +72,9 @@ public:
|
||||||
uint64_t vpub_old,
|
uint64_t vpub_old,
|
||||||
uint64_t vpub_new
|
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(
|
static r1cs_primary_input<FieldT> witness_map(
|
||||||
|
@ -34,11 +86,64 @@ public:
|
||||||
uint64_t vpub_old,
|
uint64_t vpub_old,
|
||||||
uint64_t vpub_new
|
uint64_t vpub_new
|
||||||
) {
|
) {
|
||||||
// todo
|
std::vector<bool> verify_inputs;
|
||||||
|
|
||||||
std::vector<FieldT> input_as_field_elements;
|
insert_uint256(verify_inputs, uint256()); // TODO: rt
|
||||||
input_as_field_elements.push_back(FieldT::zero());
|
insert_uint256(verify_inputs, uint256()); // TODO: h_sig
|
||||||
|
|
||||||
return input_as_field_elements;
|
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
|
||||||
|
|
||||||
|
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 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());
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -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…
Reference in New Issue