2
2
#include < gtest/gtest.h>
3
3
#include < vector>
4
4
#include < type_traits>
5
+ #include < random>
5
6
6
7
#include < libff/algebra/fields/binary/gf64.hpp>
7
8
#include " libiop/algebra/utils.hpp"
@@ -108,14 +109,17 @@ TEST(MerkleTreeTest, SimpleTest) {
108
109
typedef libff::gf64 FieldT;
109
110
110
111
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.
112
113
const size_t digest_len_bytes = 256 /8 ;
113
114
const size_t security_parameter = 128 ;
114
115
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
+ }
119
123
}
120
124
121
125
TEST (MerkleTreeZKTest, SimpleTest) {
@@ -132,10 +136,14 @@ TEST(MerkleTreeZKTest, SimpleTest) {
132
136
security_parameter, cap_size);
133
137
}
134
138
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) {
136
142
typedef libff::gf64 FieldT;
137
143
144
+ // The size is fixed because large values would quickly cause the program run out of memory.
138
145
const size_t size = 8 ;
146
+ const size_t cap_size = 4 ;
139
147
const size_t security_parameter = 128 ;
140
148
const size_t digest_len_bytes = 256 /8 ;
141
149
const bool algebraic_hash = false ;
@@ -144,7 +152,8 @@ void run_multi_test(const bool make_zk) {
144
152
size,
145
153
digest_len_bytes,
146
154
make_zk,
147
- security_parameter);
155
+ security_parameter,
156
+ cap_size);
148
157
149
158
const std::vector<FieldT> vec1 = random_vector<FieldT>(size);
150
159
const std::vector<FieldT> vec2 = random_vector<FieldT>(size);
@@ -153,23 +162,25 @@ void run_multi_test(const bool make_zk) {
153
162
154
163
const binary_hash_digest root = tree.get_root ();
155
164
156
- std::vector<std::vector<FieldT>> leafs ;
165
+ std::vector<std::vector<FieldT>> leaves ;
157
166
for (size_t i = 0 ; i < size; ++i)
158
167
{
159
168
std::vector<FieldT> leaf ({ vec1[i], vec2[i] });
160
- leafs .emplace_back (leaf);
169
+ leaves .emplace_back (leaf);
161
170
}
162
171
172
+ /* This code generates every possible subset. `subset` is a binary string that encodes for each
173
+ element, whether it is in this subset. */
163
174
for (size_t subset = 0 ; subset < (1ull <<size); ++subset)
164
175
{
165
176
std::vector<size_t > subset_elements;
166
- std::vector<std::vector<FieldT>> subset_leafs ;
177
+ std::vector<std::vector<FieldT>> subset_leaves ;
167
178
for (size_t k = 0 ; k < size; ++k)
168
179
{
169
180
if (subset & (1ull <<k))
170
181
{
171
182
subset_elements.emplace_back (k);
172
- subset_leafs .emplace_back (leafs [k]);
183
+ subset_leaves .emplace_back (leaves [k]);
173
184
}
174
185
}
175
186
@@ -178,20 +189,110 @@ void run_multi_test(const bool make_zk) {
178
189
179
190
const bool is_valid = tree.validate_set_membership_proof (root,
180
191
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,
182
275
mp);
183
276
EXPECT_TRUE (is_valid);
184
277
}
185
278
}
186
279
187
- TEST (MerkleTreeTest, MultiTest) {
280
+ TEST (MerkleTreeTest, RandomMultiTest) {
281
+ const size_t security_parameter = 128 ;
282
+ const size_t digest_len_bytes = 256 /8 ;
188
283
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 );
190
287
}
191
288
192
- TEST (MerkleTreeZKTest, MultiTest) {
289
+ TEST (MerkleTreeZKTest, RandomMultiTest) {
290
+ const size_t security_parameter = 128 ;
291
+ const size_t digest_len_bytes = 256 /8 ;
193
292
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 );
195
296
}
196
297
197
298
TEST (MerkleTreeHashCountTest, SimpleTest)
0 commit comments