]> Git Repo - VerusCoin.git/commitdiff
zkSNARK: Enforce disclosure of commitments to output notes.
authorSean Bowe <[email protected]>
Thu, 5 May 2016 00:26:02 +0000 (18:26 -0600)
committerSean Bowe <[email protected]>
Thu, 12 May 2016 22:44:30 +0000 (16:44 -0600)
src/zcash/JoinSplit.cpp
src/zcash/circuit/commitment.tcc [new file with mode: 0644]
src/zcash/circuit/gadget.tcc
src/zcash/circuit/note.tcc
src/zcash/circuit/utils.tcc

index f797ea859f133e9dd29dc8f76d1497d3adea9015..37b57fb963e00805356772f641bd81687a917115 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include <boost/foreach.hpp>
 #include <boost/format.hpp>
 #include <boost/optional.hpp>
 #include <fstream>
diff --git a/src/zcash/circuit/commitment.tcc b/src/zcash/circuit/commitment.tcc
new file mode 100644 (file)
index 0000000..769749a
--- /dev/null
@@ -0,0 +1,104 @@
+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();
+    }
+};
index 2f9e4e42c15fec3e1e06bb1db7b50dd9cfa4a381..9ce14214308ad7962220f96868a8e0365b7f1d63 100644 (file)
@@ -1,5 +1,6 @@
 #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>
@@ -114,7 +115,8 @@ public:
                 ZERO,
                 zk_phi->bits,
                 zk_h_sig->bits,
-                i ? true : false
+                i ? true : false,
+                zk_output_commitments[i]
             ));
         }
     }
@@ -206,7 +208,7 @@ public:
         }
 
         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
index e4efb763b2d4484947eb2d8bbe294fb8c550b9b8..5133e26ffcaedb558c05428bf2c9d4dddd9f97b3 100644 (file)
@@ -110,8 +110,10 @@ template<typename FieldT>
 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(
@@ -119,9 +121,11 @@ public:
         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
@@ -135,16 +139,32 @@ public:
             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) {
@@ -158,5 +178,12 @@ public:
             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();
     }
 };
index 1cc6bb9e9b4a004665e2f1d43886d173ba1c207f..3088362cb220adacec0c28d99aec109258683065 100644 (file)
@@ -1,3 +1,14 @@
+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");
This page took 0.032911 seconds and 4 git commands to generate.