Zeth - Zerocash on Ethereum  0.8
Reference implementation of the Zeth protocol by Clearmatics
mimc_input_hasher.tcc
Go to the documentation of this file.
1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
2 //
3 // SPDX-License-Identifier: LGPL-3.0+
4 
5 #ifndef __ZETH_CIRCUITS_MIMC_MIMC_INPUT_HASHER_TCC__
6 #define __ZETH_CIRCUITS_MIMC_MIMC_INPUT_HASHER_TCC__
7 
8 #include "mimc_input_hasher.hpp"
9 
10 namespace libzeth
11 {
12 
13 template<typename FieldT, typename compFnT>
14 mimc_input_hasher<FieldT, compFnT>::mimc_input_hasher(
15  libsnark::protoboard<FieldT> &pb,
16  const libsnark::pb_linear_combination_array<FieldT> &inputs,
17  const libsnark::pb_variable<FieldT> result,
18  const std::string &annotation_prefix)
19  : libsnark::gadget<FieldT>(pb, annotation_prefix), _result(result)
20 {
21  const size_t num_inputs = inputs.size();
22  if (num_inputs < 2) {
23  // Although it would be superfluous, we could support 1 entry. However
24  // it would add some complexity to the code below. For now, assume
25  // strictly more than 1 entry.
26  throw std::invalid_argument(
27  "inputs array must have at least 2 entries");
28  }
29 
30  // Require one compression function invocation per element in the array,
31  // followed by the finalization step. Each invocation except the last
32  // requires an intermediate output variable.
33  _compression_functions.reserve(num_inputs + 1);
34  _intermediate_values.allocate(
35  pb, num_inputs, FMT(annotation_prefix, "intermediate_values"));
36 
37  libsnark::pb_linear_combination<FieldT> iv;
38  iv.assign(pb, get_iv());
39 
40  // First step:
41  // intermediate[0] <- mimc_mp(iv, inputs[0])
42  _compression_functions.emplace_back(new compFnT(
43  pb,
44  iv,
45  inputs[0],
46  _intermediate_values[0],
47  FMT(annotation_prefix, " compression_functions[0]")));
48 
49  // Intermediate invocations of the compression function.
50  for (size_t i = 1; i < num_inputs; ++i) {
51  // intermediate[i] <- mimc_mp(intermediate[i-1], inputs[i])
52  _compression_functions.emplace_back(new compFnT(
53  pb,
54  _intermediate_values[i - 1],
55  inputs[i],
56  _intermediate_values[i],
57  FMT(annotation_prefix, " compression_functions[%zu]", i)));
58  }
59 
60  // Last invocation of compression function to finalize.
61  // result <- mimc_mp(intermediate[num_inputs - 1], num_inputs)
62  libsnark::pb_linear_combination<FieldT> num_inputs_lc;
63  num_inputs_lc.assign(pb, FieldT(num_inputs));
64  _compression_functions.emplace_back(new compFnT(
65  pb,
66  _intermediate_values[num_inputs - 1],
67  num_inputs_lc,
68  result,
69  FMT(annotation_prefix, " compression_functions[%zu]", num_inputs)));
70 
71  assert(_compression_functions.size() == num_inputs + 1);
72 }
73 
74 template<typename FieldT, typename compFnT>
75 void mimc_input_hasher<FieldT, compFnT>::generate_r1cs_constraints()
76 {
77  for (const std::shared_ptr<compFnT> &cf : _compression_functions) {
78  cf->generate_r1cs_constraints();
79  }
80 }
81 
82 template<typename FieldT, typename compFnT>
83 void mimc_input_hasher<FieldT, compFnT>::generate_r1cs_witness() const
84 {
85  for (const std::shared_ptr<compFnT> &cf : _compression_functions) {
86  cf->generate_r1cs_witness();
87  }
88 }
89 
90 template<typename FieldT, typename compFnT>
91 FieldT mimc_input_hasher<FieldT, compFnT>::get_iv()
92 {
93  // IV generated as:
94  // zeth.core.mimc._keccak_256(
95  // zeth.core.mimc._str_to_bytes("clearmatics_hash_seed"))
96  // See: client/zeth/core/mimc.py
97  return FieldT(
98  "1319653706411738841819622385631198771438854383955240040834092139"
99  "7545324034315");
100 }
101 
102 template<typename FieldT, typename compFnT>
103 FieldT mimc_input_hasher<FieldT, compFnT>::compute_hash(
104  const std::vector<FieldT> &values)
105 {
106  FieldT h = get_iv();
107  for (const FieldT &v : values) {
108  h = compFnT::get_hash(h, v);
109  }
110  return compFnT::get_hash(h, FieldT(values.size()));
111 }
112 
113 } // namespace libzeth
114 
115 #endif // __ZETH_CIRCUITS_MIMC_MIMC_INPUT_HASHER_TCC__