check_read.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2018-2021 Mikhail Komarov <nemo@nil.foundation>
3 // Copyright (c) 2020-2021 Nikita Kaskov <nbering@nil.foundation>
4 //
5 // MIT License
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in all
15 // copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // SOFTWARE.
24 //---------------------------------------------------------------------------//
25 // @file Declaration of interfaces for the Merkle tree check read component.
26 //
27 // The component checks the following: given a root R, address A, value V, and
28 // authentication path P, check that P is a valid authentication path for the
29 // value V as the A-th leaf in a Merkle tree with root R.
30 //---------------------------------------------------------------------------//
31 
32 #ifndef CRYPTO3_ZK_BLUEPRINT_MERKLE_TREE_CHECK_READ_COMPONENT_HPP
33 #define CRYPTO3_ZK_BLUEPRINT_MERKLE_TREE_CHECK_READ_COMPONENT_HPP
34 
41 
42 namespace nil {
43  namespace crypto3 {
44  namespace zk {
45  namespace components {
46 
47  template<typename FieldType, typename Hash>
48  class merkle_tree_check_read_component : public component<FieldType> {
49  private:
50  std::vector<Hash> hashers;
51  std::vector<block_variable<FieldType>> hasher_inputs;
52  std::vector<digest_selector_component<FieldType>> propagators;
53  std::vector<digest_variable<FieldType>> internal_output;
54 
55  std::shared_ptr<digest_variable<FieldType>> computed_root;
56  std::shared_ptr<bit_vector_copy_component<FieldType>> check_root;
57 
58  public:
59  const std::size_t digest_size;
60  const std::size_t tree_depth;
66 
68  const std::size_t tree_depth,
70  const digest_variable<FieldType> &leaf_digest,
71  const digest_variable<FieldType> &root_digest,
74 
76  void generate_r1cs_witness();
77 
78  static std::size_t root_size_in_bits();
79  /* for debugging purposes */
80  static std::size_t expected_constraints(const std::size_t tree_depth);
81  };
82 
83  template<typename FieldType, typename Hash>
86  const std::size_t tree_depth,
88  const digest_variable<FieldType> &leaf,
89  const digest_variable<FieldType> &root,
91  const blueprint_linear_combination<FieldType> &read_successful) :
92  component<FieldType>(bp),
93  digest_size(Hash::get_digest_len()), tree_depth(tree_depth), address_bits(address_bits), leaf(leaf),
94  root(root), path(path), read_successful(read_successful) {
95  /*
96  The tricky part here is ordering. For Merkle tree
97  authentication paths, path[0] corresponds to one layer below
98  the root (and path[tree_depth-1] corresponds to the layer
99  containing the leaf), while address_bits has the reverse order:
100  address_bits[0] is LSB, and corresponds to layer containing the
101  leaf, and address_bits[tree_depth-1] is MSB, and corresponds to
102  the subtree directly under the root.
103  */
104  assert(tree_depth > 0);
105  assert(tree_depth == address_bits.size());
106 
107  for (std::size_t i = 0; i < tree_depth - 1; ++i) {
108  internal_output.emplace_back(digest_variable<FieldType>(bp, digest_size));
109  }
110 
111  computed_root.reset(new digest_variable<FieldType>(bp, digest_size));
112 
113  for (std::size_t i = 0; i < tree_depth; ++i) {
114  block_variable<FieldType> inp(bp, path.left_digests[i], path.right_digests[i]);
115  hasher_inputs.emplace_back(inp);
116  hashers.emplace_back(
117  Hash(bp, 2 * digest_size, inp, (i == 0 ? *computed_root : internal_output[i - 1])));
118  }
119 
120  for (std::size_t i = 0; i < tree_depth; ++i) {
121  /*
122  The propagators take a computed hash value (or leaf in the
123  base case) and propagate it one layer up, either in the left
124  or the right slot of authentication_path_variable.
125  */
126  propagators.emplace_back(digest_selector_component<FieldType>(
127  bp, digest_size, i < tree_depth - 1 ? internal_output[i] : leaf,
128  address_bits[tree_depth - 1 - i], path.left_digests[i], path.right_digests[i]));
129  }
130 
131  check_root.reset(new bit_vector_copy_component<FieldType>(bp, computed_root->bits, root.bits,
132  read_successful, FieldType::number_bits));
133  }
134 
135  template<typename FieldType, typename Hash>
137  /* ensure correct hash computations */
138  for (std::size_t i = 0; i < tree_depth; ++i) {
139  // Note that we check root outside and have enforced booleanity of
140  // path.left_digests/path.right_digests outside in path.generate_r1cs_constraints
141  hashers[i].generate_r1cs_constraints(false);
142  }
143 
144  /* ensure consistency of path.left_digests/path.right_digests with internal_output */
145  for (std::size_t i = 0; i < tree_depth; ++i) {
146  propagators[i].generate_r1cs_constraints();
147  }
148 
149  check_root->generate_r1cs_constraints(false, false);
150  }
151 
152  template<typename FieldType, typename Hash>
154  /* do the hash computations bottom-up */
155  for (int i = tree_depth - 1; i >= 0; --i) {
156  /* propagate previous input */
157  propagators[i].generate_r1cs_witness();
158 
159  /* compute hash */
160  hashers[i].generate_r1cs_witness();
161  }
162 
163  check_root->generate_r1cs_witness();
164  }
165 
166  template<typename FieldType, typename Hash>
168  return Hash::get_digest_len();
169  }
170 
171  template<typename FieldType, typename Hash>
173  const std::size_t tree_depth) {
174  /* NB: this includes path constraints */
175  const std::size_t hasher_constraints = tree_depth * Hash::expected_constraints(false);
176  const std::size_t propagator_constraints = tree_depth * Hash::get_digest_len();
177  const std::size_t authentication_path_constraints = 2 * tree_depth * Hash::get_digest_len();
178  const std::size_t check_root_constraints =
179  3 * (Hash::get_digest_len() + (FieldType::capacity()) - 1) / FieldType::capacity();
180 
181  return hasher_constraints + propagator_constraints + authentication_path_constraints +
182  check_root_constraints;
183  }
184 
185  } // namespace components
186  } // namespace zk
187  } // namespace crypto3
188 } // namespace nil
189 
190 #endif // CRYPTO3_ZK_BLUEPRINT_MERKLE_TREE_CHECK_READ_COMPONENT_HPP
Definition: blueprint_linear_combination.hpp:115
Definition: blueprint_linear_combination.hpp:47
Definition: blueprint.hpp:46
Definition: component.hpp:37
blueprint< FieldType > & bp
Definition: component.hpp:39
Definition: digest_selector_component.hpp:39
const std::size_t digest_size
Definition: check_read.hpp:59
const std::size_t tree_depth
Definition: check_read.hpp:60
digest_variable< FieldType > leaf
Definition: check_read.hpp:62
void generate_r1cs_witness()
Definition: check_read.hpp:153
void generate_r1cs_constraints()
Definition: check_read.hpp:136
merkle_tree_check_read_component(blueprint< FieldType > &bp, const std::size_t tree_depth, const blueprint_linear_combination_vector< FieldType > &address_bits, const digest_variable< FieldType > &leaf_digest, const digest_variable< FieldType > &root_digest, const merkle_authentication_path_variable< FieldType, Hash > &path, const blueprint_linear_combination< FieldType > &read_successful)
Definition: check_read.hpp:84
static std::size_t root_size_in_bits()
Definition: check_read.hpp:167
blueprint_linear_combination_vector< FieldType > address_bits
Definition: check_read.hpp:61
static std::size_t expected_constraints(const std::size_t tree_depth)
Definition: check_read.hpp:172
merkle_authentication_path_variable< FieldType, Hash > path
Definition: check_read.hpp:64
digest_variable< FieldType > root
Definition: check_read.hpp:63
blueprint_linear_combination< FieldType > read_successful
Definition: check_read.hpp:65
Definition: pair.hpp:31