#include <memory>
+#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/optional.hpp>
#include <fstream>
--- /dev/null
+template<typename FieldT>
+class note_commitment_gadget : gadget<FieldT> {
+private:
+ std::shared_ptr<block_variable<FieldT>> block1;
+ std::shared_ptr<block_variable<FieldT>> block2;
+ std::shared_ptr<sha256_compression_function_gadget<FieldT>> hasher1;
+ std::shared_ptr<digest_variable<FieldT>> intermediate_hash;
+ std::shared_ptr<sha256_compression_function_gadget<FieldT>> hasher2;
+
+public:
+ note_commitment_gadget(
+ protoboard<FieldT> &pb,
+ pb_variable<FieldT>& ZERO,
+ pb_variable_array<FieldT>& a_pk,
+ pb_variable_array<FieldT>& v,
+ pb_variable_array<FieldT>& rho,
+ pb_variable_array<FieldT>& r,
+ std::shared_ptr<digest_variable<FieldT>> result
+ ) : gadget<FieldT>(pb) {
+ pb_variable_array<FieldT> leading_byte =
+ from_bits({1, 0, 1, 1, 0, 0, 0, 0}, ZERO);
+
+ pb_variable_array<FieldT> first_of_rho(rho.begin(), rho.begin()+184);
+ pb_variable_array<FieldT> last_of_rho(rho.begin()+184, rho.end());
+
+ intermediate_hash.reset(new digest_variable<FieldT>(pb, 256, ""));
+
+ // final padding
+ pb_variable_array<FieldT> length_padding =
+ from_bits({
+ // padding
+ 1,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+
+ // length of message (840 bits)
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,1,1,
+ 0,1,0,0,1,0,0,0
+ }, ZERO);
+
+ block1.reset(new block_variable<FieldT>(pb, {
+ leading_byte,
+ a_pk,
+ v,
+ first_of_rho
+ }, ""));
+
+ block2.reset(new block_variable<FieldT>(pb, {
+ last_of_rho,
+ r,
+ length_padding
+ }, ""));
+
+ pb_linear_combination_array<FieldT> IV = SHA256_default_IV(pb);
+
+ hasher1.reset(new sha256_compression_function_gadget<FieldT>(
+ pb,
+ IV,
+ block1->bits,
+ *intermediate_hash,
+ ""));
+
+ pb_linear_combination_array<FieldT> IV2(intermediate_hash->bits);
+
+ hasher2.reset(new sha256_compression_function_gadget<FieldT>(
+ pb,
+ IV2,
+ block2->bits,
+ *result,
+ ""));
+ }
+
+ void generate_r1cs_constraints() {
+ // TODO: This may not be necessary if SHA256 constrains
+ // its output digests to be boolean anyway.
+ intermediate_hash->generate_r1cs_constraints();
+
+ hasher1->generate_r1cs_constraints();
+ hasher2->generate_r1cs_constraints();
+ }
+
+ void generate_r1cs_witness() {
+ hasher1->generate_r1cs_witness();
+ hasher2->generate_r1cs_witness();
+ }
+};
#include "zcash/circuit/utils.tcc"
#include "zcash/circuit/prfs.tcc"
+#include "zcash/circuit/commitment.tcc"
#include "zcash/circuit/note.tcc"
template<typename FieldT, size_t NumInputs, size_t NumOutputs>
ZERO,
zk_phi->bits,
zk_h_sig->bits,
- i ? true : false
+ i ? true : false,
+ zk_output_commitments[i]
));
}
}
}
for (size_t i = 0; i < NumOutputs; i++) {
- insert_uint256(verify_inputs, uint256()); // TODO: commitment
+ insert_uint256(verify_inputs, commitments[i]);
}
insert_uint64(verify_inputs, 0); // TODO: vpub_old
class output_note_gadget : public note_gadget<FieldT> {
private:
std::shared_ptr<digest_variable<FieldT>> rho;
+ std::shared_ptr<digest_variable<FieldT>> a_pk;
std::shared_ptr<PRF_rho_gadget<FieldT>> prevent_faerie_gold;
+ std::shared_ptr<note_commitment_gadget<FieldT>> commit_to_outputs;
public:
output_note_gadget(
pb_variable<FieldT>& ZERO,
pb_variable_array<FieldT>& phi,
pb_variable_array<FieldT>& h_sig,
- bool nonce
+ bool nonce,
+ std::shared_ptr<digest_variable<FieldT>> commitment
) : note_gadget<FieldT>(pb) {
rho.reset(new digest_variable<FieldT>(pb, 256, ""));
+ a_pk.reset(new digest_variable<FieldT>(pb, 256, ""));
// Do not allow the caller to choose the same "rho"
// for any two valid notes in a given view of the
nonce,
rho
));
+
+ // Commit to the output notes publicly without
+ // disclosing them.
+ commit_to_outputs.reset(new note_commitment_gadget<FieldT>(
+ pb,
+ ZERO,
+ a_pk->bits,
+ this->value,
+ rho->bits,
+ this->r->bits,
+ commitment
+ ));
}
void generate_r1cs_constraints() {
note_gadget<FieldT>::generate_r1cs_constraints();
+ a_pk->generate_r1cs_constraints();
+
// TODO: This constraint may not be necessary if SHA256
// already boolean constrains its outputs.
rho->generate_r1cs_constraints();
prevent_faerie_gold->generate_r1cs_constraints();
+
+ commit_to_outputs->generate_r1cs_constraints();
}
void generate_r1cs_witness(const Note& note) {
this->pb,
uint256_to_bool_vector(note.rho)
);
+
+ a_pk->bits.fill_with_bits(
+ this->pb,
+ uint256_to_bool_vector(note.a_pk)
+ );
+
+ commit_to_outputs->generate_r1cs_witness();
}
};
+template<typename FieldT>
+pb_variable_array<FieldT> from_bits(std::vector<bool> bits, pb_variable<FieldT>& ZERO) {
+ pb_variable_array<FieldT> acc;
+
+ BOOST_FOREACH(bool bit, bits) {
+ acc.emplace_back(bit ? ONE : ZERO);
+ }
+
+ return acc;
+}
+
std::vector<bool> trailing252(std::vector<bool> input) {
if (input.size() != 256) {
throw std::length_error("trailing252 input invalid length");