1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
3 // SPDX-License-Identifier: LGPL-3.0+
5 #ifndef __ZETH_CIRCUITS_MIMC_MIMC_INPUT_HASHER_TCC__
6 #define __ZETH_CIRCUITS_MIMC_MIMC_INPUT_HASHER_TCC__
8 #include "mimc_input_hasher.hpp"
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)
21 const size_t num_inputs = inputs.size();
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");
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"));
37 libsnark::pb_linear_combination<FieldT> iv;
38 iv.assign(pb, get_iv());
41 // intermediate[0] <- mimc_mp(iv, inputs[0])
42 _compression_functions.emplace_back(new compFnT(
46 _intermediate_values[0],
47 FMT(annotation_prefix, " compression_functions[0]")));
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(
54 _intermediate_values[i - 1],
56 _intermediate_values[i],
57 FMT(annotation_prefix, " compression_functions[%zu]", i)));
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(
66 _intermediate_values[num_inputs - 1],
69 FMT(annotation_prefix, " compression_functions[%zu]", num_inputs)));
71 assert(_compression_functions.size() == num_inputs + 1);
74 template<typename FieldT, typename compFnT>
75 void mimc_input_hasher<FieldT, compFnT>::generate_r1cs_constraints()
77 for (const std::shared_ptr<compFnT> &cf : _compression_functions) {
78 cf->generate_r1cs_constraints();
82 template<typename FieldT, typename compFnT>
83 void mimc_input_hasher<FieldT, compFnT>::generate_r1cs_witness() const
85 for (const std::shared_ptr<compFnT> &cf : _compression_functions) {
86 cf->generate_r1cs_witness();
90 template<typename FieldT, typename compFnT>
91 FieldT mimc_input_hasher<FieldT, compFnT>::get_iv()
94 // zeth.core.mimc._keccak_256(
95 // zeth.core.mimc._str_to_bytes("clearmatics_hash_seed"))
96 // See: client/zeth/core/mimc.py
98 "1319653706411738841819622385631198771438854383955240040834092139"
102 template<typename FieldT, typename compFnT>
103 FieldT mimc_input_hasher<FieldT, compFnT>::compute_hash(
104 const std::vector<FieldT> &values)
107 for (const FieldT &v : values) {
108 h = compFnT::get_hash(h, v);
110 return compFnT::get_hash(h, FieldT(values.size()));
113 } // namespace libzeth
115 #endif // __ZETH_CIRCUITS_MIMC_MIMC_INPUT_HASHER_TCC__