22#include < gtest/gtest.h>
33#include < vector>
44#include < type_traits>
5+ #include < random>
56
67#include < libff/algebra/fields/binary/gf64.hpp>
78#include " libiop/algebra/utils.hpp"
@@ -108,14 +109,17 @@ TEST(MerkleTreeTest, SimpleTest) {
108109 typedef libff::gf64 FieldT;
109110
110111 const size_t size = 16 ;
111- const size_t cap_size = 2 ;
112+ const std::vector< size_t > cap_sizes = { 2 , 4 , 8 , 16 }; // Test all possible cap sizes.
112113 const size_t digest_len_bytes = 256 /8 ;
113114 const size_t security_parameter = 128 ;
114115
115- run_simple_MT_test<FieldT, binary_hash_digest>(size, digest_len_bytes, false ,
116- security_parameter, cap_size);
117- run_simple_MT_test<FieldT, FieldT>(size, digest_len_bytes, false ,
118- security_parameter, cap_size);
116+ for (size_t cap_size : cap_sizes)
117+ {
118+ run_simple_MT_test<FieldT, binary_hash_digest>(size, digest_len_bytes, false ,
119+ security_parameter, cap_size);
120+ run_simple_MT_test<FieldT, FieldT>(size, digest_len_bytes, false ,
121+ security_parameter, cap_size);
122+ }
119123}
120124
121125TEST (MerkleTreeZKTest, SimpleTest) {
@@ -132,10 +136,14 @@ TEST(MerkleTreeZKTest, SimpleTest) {
132136 security_parameter, cap_size);
133137}
134138
135- void run_multi_test (const bool make_zk) {
139+ /* * Constructs a merkle tree with 8 leaves each of size 2, and cap size 4. Generates and verifies
140+ * membership proofs for every possible subset of leaves. */
141+ void run_fixed_multi_test (const bool make_zk) {
136142 typedef libff::gf64 FieldT;
137143
144+ // The size is fixed because large values would quickly cause the program run out of memory.
138145 const size_t size = 8 ;
146+ const size_t cap_size = 4 ;
139147 const size_t security_parameter = 128 ;
140148 const size_t digest_len_bytes = 256 /8 ;
141149 const bool algebraic_hash = false ;
@@ -144,7 +152,8 @@ void run_multi_test(const bool make_zk) {
144152 size,
145153 digest_len_bytes,
146154 make_zk,
147- security_parameter);
155+ security_parameter,
156+ cap_size);
148157
149158 const std::vector<FieldT> vec1 = random_vector<FieldT>(size);
150159 const std::vector<FieldT> vec2 = random_vector<FieldT>(size);
@@ -153,23 +162,25 @@ void run_multi_test(const bool make_zk) {
153162
154163 const binary_hash_digest root = tree.get_root ();
155164
156- std::vector<std::vector<FieldT>> leafs ;
165+ std::vector<std::vector<FieldT>> leaves ;
157166 for (size_t i = 0 ; i < size; ++i)
158167 {
159168 std::vector<FieldT> leaf ({ vec1[i], vec2[i] });
160- leafs .emplace_back (leaf);
169+ leaves .emplace_back (leaf);
161170 }
162171
172+ /* This code generates every possible subset. `subset` is a binary string that encodes for each
173+ element, whether it is in this subset. */
163174 for (size_t subset = 0 ; subset < (1ull <<size); ++subset)
164175 {
165176 std::vector<size_t > subset_elements;
166- std::vector<std::vector<FieldT>> subset_leafs ;
177+ std::vector<std::vector<FieldT>> subset_leaves ;
167178 for (size_t k = 0 ; k < size; ++k)
168179 {
169180 if (subset & (1ull <<k))
170181 {
171182 subset_elements.emplace_back (k);
172- subset_leafs .emplace_back (leafs [k]);
183+ subset_leaves .emplace_back (leaves [k]);
173184 }
174185 }
175186
@@ -178,20 +189,110 @@ void run_multi_test(const bool make_zk) {
178189
179190 const bool is_valid = tree.validate_set_membership_proof (root,
180191 subset_elements,
181- subset_leafs,
192+ subset_leaves,
193+ mp);
194+ EXPECT_TRUE (is_valid);
195+ }
196+ }
197+
198+ TEST (MerkleTreeTest, FixedMultiTest) {
199+ const bool make_zk = false ;
200+ run_fixed_multi_test (make_zk);
201+ }
202+
203+ TEST (MerkleTreeZKTest, FixedMultiTest) {
204+ const bool make_zk = true ;
205+ run_fixed_multi_test (make_zk);
206+ }
207+
208+ /* * Constructs a merkle tree with leaf size 2. Generates and verifies membership proofs for some
209+ * randomly generated sorted subset of leaves of specified size, with no duplicates. Queries with
210+ * unsorted, duplicated lists of leaves currently only work when it is not zero knowledge. */
211+ void run_random_multi_test (const size_t size, const size_t digest_len_bytes, const bool make_zk,
212+ const size_t security_parameter, const size_t cap_size,
213+ const size_t subset_size) {
214+ typedef libff::gf64 FieldT;
215+
216+ const bool algebraic_hash = false ;
217+ const size_t num_iterations = 1 ; // The number of randomly generated subsets to test.
218+
219+ merkle_tree<FieldT, binary_hash_digest> tree = new_MT<FieldT, binary_hash_digest>(
220+ size,
221+ digest_len_bytes,
222+ make_zk,
223+ security_parameter,
224+ cap_size);
225+
226+ const std::vector<FieldT> vec1 = random_vector<FieldT>(size);
227+ const std::vector<FieldT> vec2 = random_vector<FieldT>(size);
228+
229+ tree.construct ({ vec1, vec2 });
230+
231+ const binary_hash_digest root = tree.get_root ();
232+
233+ std::vector<std::vector<FieldT>> leaves;
234+ leaves.reserve (size);
235+ std::vector<size_t > shuffled_leaf_indices;
236+ shuffled_leaf_indices.reserve (size);
237+ for (size_t i = 0 ; i < size; ++i)
238+ {
239+ std::vector<FieldT> leaf ({ vec1[i], vec2[i] });
240+ leaves.emplace_back (leaf);
241+ shuffled_leaf_indices.emplace_back (i);
242+ }
243+
244+ for (size_t i = 0 ; i < num_iterations; i++)
245+ {
246+ std::vector<size_t > subset_elements;
247+ std::vector<std::vector<FieldT>> subset_leaves;
248+ /* The commented-out code generates subsets that are unsorted and may be repeats.
249+ They are not used because the code currently cannot handle these cases if it is
250+ zero knowledge. */
251+ // for (size_t j = 0; j < subset_size; j++)
252+ // {
253+ // size_t k = randombytes_uniform(size);
254+ // subset_elements.emplace_back(k);
255+ // subset_leaves.emplace_back(leaves[k]);
256+ // }
257+
258+ // Generate a random sorted subset of indices at the beginning of shuffled_leaf_indices.
259+ std::shuffle (shuffled_leaf_indices.begin (), shuffled_leaf_indices.end (),
260+ std::default_random_engine (i));
261+ std::sort (shuffled_leaf_indices.begin (), shuffled_leaf_indices.begin () + subset_size);
262+ for (size_t j = 0 ; j < subset_size; j++)
263+ {
264+ size_t k = shuffled_leaf_indices[j];
265+ subset_elements.emplace_back (k);
266+ subset_leaves.emplace_back (leaves[k]);
267+ }
268+
269+ const merkle_tree_set_membership_proof<binary_hash_digest> mp =
270+ tree.get_set_membership_proof (subset_elements);
271+
272+ const bool is_valid = tree.validate_set_membership_proof (root,
273+ subset_elements,
274+ subset_leaves,
182275 mp);
183276 EXPECT_TRUE (is_valid);
184277 }
185278}
186279
187- TEST (MerkleTreeTest, MultiTest) {
280+ TEST (MerkleTreeTest, RandomMultiTest) {
281+ const size_t security_parameter = 128 ;
282+ const size_t digest_len_bytes = 256 /8 ;
188283 const bool make_zk = false ;
189- run_multi_test (make_zk);
284+ // Test a small and a large tree.
285+ run_random_multi_test (16 , digest_len_bytes, make_zk, security_parameter, 4 , 5 );
286+ run_random_multi_test (1ull << 16 , digest_len_bytes, make_zk, security_parameter, 256 , 100 );
190287}
191288
192- TEST (MerkleTreeZKTest, MultiTest) {
289+ TEST (MerkleTreeZKTest, RandomMultiTest) {
290+ const size_t security_parameter = 128 ;
291+ const size_t digest_len_bytes = 256 /8 ;
193292 const bool make_zk = true ;
194- run_multi_test (make_zk);
293+ // Test a small and a large tree.
294+ run_random_multi_test (16 , digest_len_bytes, make_zk, security_parameter, 4 , 5 );
295+ run_random_multi_test (1ull << 16 , digest_len_bytes, make_zk, security_parameter, 256 , 100 );
195296}
196297
197298TEST (MerkleTreeHashCountTest, SimpleTest)
0 commit comments