PRCYCoin  2.0.0.7rc1
P2P Digital Currency
tests_impl.h
Go to the documentation of this file.
1 /**********************************************************************
2  * Copyright (c) 2016 Andrew Poelstra *
3  * Distributed under the MIT software license, see the accompanying *
4  * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
5  **********************************************************************/
6 
7 #ifndef SECP256K1_MODULE_SURJECTIONPROOF_TESTS
8 #define SECP256K1_MODULE_SURJECTIONPROOF_TESTS
9 
10 #include "testrand.h"
11 #include "group.h"
15 
16 static void test_surjectionproof_api(void) {
17  unsigned char seed[32];
22  secp256k1_fixed_asset_tag fixed_input_tags[10];
23  secp256k1_fixed_asset_tag fixed_output_tag;
24  secp256k1_generator ephemeral_input_tags[10];
25  secp256k1_generator ephemeral_output_tag;
26  unsigned char input_blinding_key[10][32];
27  unsigned char output_blinding_key[32];
28  unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX];
29  size_t serialized_len;
31  size_t n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]);
32  size_t input_index;
33  int32_t ecount = 0;
34  size_t i;
35 
36  secp256k1_rand256(seed);
37  secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
38  secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
39  secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
40  secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
41  secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
42  secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
43  secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
44  secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
45 
46  for (i = 0; i < n_inputs; i++) {
47  secp256k1_rand256(input_blinding_key[i]);
48  secp256k1_rand256(fixed_input_tags[i].data);
49  CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_input_tags[i], fixed_input_tags[i].data, input_blinding_key[i]));
50  }
51  secp256k1_rand256(output_blinding_key);
52  memcpy(&fixed_output_tag, &fixed_input_tags[0], sizeof(fixed_input_tags[0]));
53  CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_output_tag, fixed_output_tag.data, output_blinding_key));
54 
55  /* check initialize */
56  CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, seed) == 0);
57  CHECK(ecount == 0);
58  CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0);
59  CHECK(ecount == 0);
60  CHECK(secp256k1_surjectionproof_initialize(none, NULL, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0);
61  CHECK(ecount == 1);
62  CHECK(secp256k1_surjectionproof_initialize(none, &proof, NULL, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0);
63  CHECK(ecount == 2);
64  CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, NULL, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0);
65  CHECK(ecount == 3);
66  CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS + 1, 3, &fixed_input_tags[0], 100, seed) == 0);
67  CHECK(ecount == 4);
68  CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], 100, seed) != 0);
69  CHECK(ecount == 4);
70  CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs + 1, &fixed_input_tags[0], 100, seed) == 0);
71  CHECK(ecount == 5);
72  CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, NULL, 100, seed) == 0);
73  CHECK(ecount == 6);
74  CHECK((secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 0, seed) & 1) == 0);
75  CHECK(ecount == 6);
76  CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, NULL) == 0);
77  CHECK(ecount == 7);
78 
79  CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0);
80  /* check generate */
81  CHECK(secp256k1_surjectionproof_generate(none, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
82  CHECK(ecount == 8);
83  CHECK(secp256k1_surjectionproof_generate(vrfy, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
84  CHECK(ecount == 9);
85 
86  CHECK(secp256k1_surjectionproof_generate(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
87  CHECK(ecount == 10);
88  CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0);
89  CHECK(ecount == 10);
90 
91  CHECK(secp256k1_surjectionproof_generate(both, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
92  CHECK(ecount == 11);
93  CHECK(secp256k1_surjectionproof_generate(both, &proof, NULL, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
94  CHECK(ecount == 12);
95  CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs + 1, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
96  CHECK(ecount == 12);
97  CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs - 1, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
98  CHECK(ecount == 12);
99  CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, 0, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0);
100  CHECK(ecount == 12);
101  CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, NULL, 0, input_blinding_key[0], output_blinding_key) == 0);
102  CHECK(ecount == 13);
103  CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 1, input_blinding_key[0], output_blinding_key) != 0);
104  CHECK(ecount == 13); /* the above line "succeeds" but generates an invalid proof as the input_index is wrong. it is fairly expensive to detect this. should we? */
105  CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, n_inputs + 1, input_blinding_key[0], output_blinding_key) != 0);
106  CHECK(ecount == 13);
107  CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, NULL, output_blinding_key) == 0);
108  CHECK(ecount == 14);
109  CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], NULL) == 0);
110  CHECK(ecount == 15);
111 
112  CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0);
113  /* check verify */
114  CHECK(secp256k1_surjectionproof_verify(none, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0);
115  CHECK(ecount == 16);
116  CHECK(secp256k1_surjectionproof_verify(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0);
117  CHECK(ecount == 17);
118  CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) != 0);
119  CHECK(ecount == 17);
120 
121  CHECK(secp256k1_surjectionproof_verify(vrfy, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0);
122  CHECK(ecount == 18);
123  CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, NULL, n_inputs, &ephemeral_output_tag) == 0);
124  CHECK(ecount == 19);
125  CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs - 1, &ephemeral_output_tag) == 0);
126  CHECK(ecount == 19);
127  CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs + 1, &ephemeral_output_tag) == 0);
128  CHECK(ecount == 19);
129  CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs, NULL) == 0);
130  CHECK(ecount == 20);
131 
132  /* Check serialize */
133  serialized_len = sizeof(serialized_proof);
134  CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, &serialized_len, &proof) != 0);
135  CHECK(ecount == 20);
136  serialized_len = sizeof(serialized_proof);
137  CHECK(secp256k1_surjectionproof_serialize(none, NULL, &serialized_len, &proof) == 0);
138  CHECK(ecount == 21);
139  serialized_len = sizeof(serialized_proof);
140  CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, NULL, &proof) == 0);
141  CHECK(ecount == 22);
142  serialized_len = sizeof(serialized_proof);
143  CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, &serialized_len, NULL) == 0);
144  CHECK(ecount == 23);
145 
146  serialized_len = sizeof(serialized_proof);
147  CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, &serialized_len, &proof) != 0);
148  /* Check parse */
149  CHECK(secp256k1_surjectionproof_parse(none, &proof, serialized_proof, serialized_len) != 0);
150  CHECK(ecount == 23);
151  CHECK(secp256k1_surjectionproof_parse(none, NULL, serialized_proof, serialized_len) == 0);
152  CHECK(ecount == 24);
153  CHECK(secp256k1_surjectionproof_parse(none, &proof, NULL, serialized_len) == 0);
154  CHECK(ecount == 25);
155  CHECK(secp256k1_surjectionproof_parse(none, &proof, serialized_proof, 0) == 0);
156  CHECK(ecount == 25);
157 
162 }
163 
164 static void test_input_selection(size_t n_inputs) {
165  unsigned char seed[32];
166  size_t i;
167  size_t result;
168  size_t input_index;
169  size_t try_count = n_inputs * 100;
171  secp256k1_fixed_asset_tag fixed_input_tags[1000];
172  const size_t max_n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]) - 1;
173 
174  CHECK(n_inputs < max_n_inputs);
175  secp256k1_rand256(seed);
176 
177  for (i = 0; i < n_inputs + 1; i++) {
178  secp256k1_rand256(fixed_input_tags[i].data);
179  }
180 
181  /* cannot match output when told to use zero keys */
182  result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], try_count, seed);
183  CHECK(result == 0);
185  CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs);
186  CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 34 + (n_inputs + 7) / 8);
187  if (n_inputs > 0) {
188  /* succeed in 100*n_inputs tries (probability of failure e^-100) */
189  result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 1, &fixed_input_tags[0], try_count, seed);
190  CHECK(result > 0);
191  CHECK(result < n_inputs * 10);
193  CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs);
194  CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 66 + (n_inputs + 7) / 8);
195  CHECK(input_index == 0);
196  }
197 
198  if (n_inputs >= 3) {
199  /* succeed in 10*n_inputs tries (probability of failure e^-10) */
200  result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[1], try_count, seed);
201  CHECK(result > 0);
203  CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs);
204  CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 130 + (n_inputs + 7) / 8);
205  CHECK(input_index == 1);
206 
207  /* fail, key not found */
208  result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[n_inputs], try_count, seed);
209  CHECK(result == 0);
210 
211  /* succeed on first try when told to use all keys */
212  result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], try_count, seed);
213  CHECK(result == 1);
214  CHECK(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == n_inputs);
215  CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs);
216  CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 2 + 32 * (n_inputs + 1) + (n_inputs + 7) / 8);
217  CHECK(input_index == 0);
218 
219  /* succeed in less than 64 tries when told to use half keys. (probability of failure 2^-64) */
220  result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs / 2, &fixed_input_tags[0], 64, seed);
221  CHECK(result > 0);
222  CHECK(result < 64);
223  CHECK(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == n_inputs / 2);
224  CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs);
225  CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 2 + 32 * (n_inputs / 2 + 1) + (n_inputs + 7) / 8);
226  CHECK(input_index == 0);
227  }
228 }
229 
232 static void test_input_selection_distribution_helper(const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, size_t *used_inputs) {
234  size_t input_index;
235  size_t i;
236  size_t j;
237  unsigned char seed[32];
238  size_t result;
239  for (i = 0; i < n_input_tags; i++) {
240  used_inputs[i] = 0;
241  }
242  for(j = 0; j < 10000; j++) {
243  secp256k1_rand256(seed);
244  result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_input_tags, n_input_tags_to_use, &fixed_input_tags[0], 64, seed);
245  CHECK(result > 0);
246 
247  for (i = 0; i < n_input_tags; i++) {
248  if (proof.used_inputs[i / 8] & (1 << (i % 8))) {
249  used_inputs[i] += 1;
250  }
251  }
252  }
253 }
254 
258 static void test_input_selection_distribution(void) {
259  size_t i;
260  size_t n_input_tags_to_use;
261  const size_t n_inputs = 4;
262  secp256k1_fixed_asset_tag fixed_input_tags[4];
263  size_t used_inputs[4];
264 
265  for (i = 0; i < n_inputs; i++) {
266  secp256k1_rand256(fixed_input_tags[i].data);
267  }
268 
269  /* If there is one input tag to use, initialize must choose the one equal to fixed_output_tag. */
270  n_input_tags_to_use = 1;
271  test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs);
272  CHECK(used_inputs[0] == 10000);
273  CHECK(used_inputs[1] == 0);
274  CHECK(used_inputs[2] == 0);
275  CHECK(used_inputs[3] == 0);
276 
277  n_input_tags_to_use = 2;
278  /* The input equal to the fixed_output_tag must be included in all used_inputs sets.
279  * For each fixed_input_tag != fixed_output_tag the probability that it's included
280  * in the used_inputs set is P(used_input|not fixed_output_tag) = 1/3.
281  */
282  test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs);
283  CHECK(used_inputs[0] == 10000);
284  CHECK(used_inputs[1] > 2725 && used_inputs[1] < 3961);
285  CHECK(used_inputs[2] > 2725 && used_inputs[2] < 3961);
286  CHECK(used_inputs[3] > 2725 && used_inputs[3] < 3961);
287 
288  n_input_tags_to_use = 3;
289  /* P(used_input|not fixed_output_tag) = 2/3 */
290  test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs);
291  CHECK(used_inputs[0] == 10000);
292  CHECK(used_inputs[1] > 6039 && used_inputs[1] < 7275);
293  CHECK(used_inputs[2] > 6039 && used_inputs[2] < 7275);
294  CHECK(used_inputs[3] > 6039 && used_inputs[3] < 7275);
295 
296 
297  n_input_tags_to_use = 1;
298  /* Create second input tag that is equal to the output tag. Therefore, when using only
299  * one input we have P(used_input|fixed_output_tag) = 1/2 and P(used_input|not fixed_output_tag) = 0
300  */
301  memcpy(fixed_input_tags[0].data, fixed_input_tags[1].data, 32);
302  test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs);
303  CHECK(used_inputs[0] > 4345 && used_inputs[0] < 5655);
304  CHECK(used_inputs[1] > 4345 && used_inputs[1] < 5655);
305  CHECK(used_inputs[2] == 0);
306  CHECK(used_inputs[3] == 0);
307 
308  n_input_tags_to_use = 2;
309  /* When choosing 2 inputs in initialization there are 5 possible combinations of
310  * input indexes {(0, 1), (1, 2), (0, 3), (1, 3), (0, 2)}. Therefore we have
311  * P(used_input|fixed_output_tag) = 3/5 and P(used_input|not fixed_output_tag) = 2/5.
312  */
313  test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs);
314  CHECK(used_inputs[0] > 5352 && used_inputs[0] < 6637);
315  CHECK(used_inputs[1] > 5352 && used_inputs[1] < 6637);
316  CHECK(used_inputs[2] > 3363 && used_inputs[2] < 4648);
317  CHECK(used_inputs[3] > 3363 && used_inputs[3] < 4648);
318 
319  n_input_tags_to_use = 3;
320  /* There are 4 combinations, each with all inputs except one. Therefore we have
321  * P(used_input|fixed_output_tag) = 3/4 and P(used_input|not fixed_output_tag) = 3/4.
322  */
323  test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs);
324  CHECK(used_inputs[0] > 6918 && used_inputs[0] < 8053);
325  CHECK(used_inputs[1] > 6918 && used_inputs[1] < 8053);
326  CHECK(used_inputs[2] > 6918 && used_inputs[2] < 8053);
327  CHECK(used_inputs[3] > 6918 && used_inputs[3] < 8053);
328 }
329 
330 static void test_gen_verify(size_t n_inputs, size_t n_used) {
331  unsigned char seed[32];
333  unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX];
334  unsigned char serialized_proof_trailing[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX + 1];
336  secp256k1_fixed_asset_tag fixed_input_tags[1000];
337  secp256k1_generator ephemeral_input_tags[1000];
338  unsigned char *input_blinding_key[1000];
339  const size_t max_n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]) - 1;
340  size_t try_count = n_inputs * 100;
341  size_t key_index;
342  size_t input_index;
343  size_t i;
344  int result;
345 
346  /* setup */
347  CHECK(n_used <= n_inputs);
348  CHECK(n_inputs < max_n_inputs);
349  secp256k1_rand256(seed);
350 
351  key_index = (((size_t) seed[0] << 8) + seed[1]) % n_inputs;
352 
353  for (i = 0; i < n_inputs + 1; i++) {
354  input_blinding_key[i] = malloc(32);
355  secp256k1_rand256(input_blinding_key[i]);
356  /* choose random fixed tag, except that for the output one copy from the key_index */
357  if (i < n_inputs) {
358  secp256k1_rand256(fixed_input_tags[i].data);
359  } else {
360  memcpy(&fixed_input_tags[i], &fixed_input_tags[key_index], sizeof(fixed_input_tags[i]));
361  }
362  CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_input_tags[i], fixed_input_tags[i].data, input_blinding_key[i]));
363  }
364 
365  /* test */
366  result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_used, &fixed_input_tags[key_index], try_count, seed);
367  if (n_used == 0) {
368  CHECK(result == 0);
369  return;
370  }
371  CHECK(result > 0);
372  CHECK(input_index == key_index);
373 
374  result = secp256k1_surjectionproof_generate(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs], input_index, input_blinding_key[input_index], input_blinding_key[n_inputs]);
375  CHECK(result == 1);
376 
377  CHECK(secp256k1_surjectionproof_serialize(ctx, serialized_proof, &serialized_len, &proof));
378  CHECK(serialized_len == secp256k1_surjectionproof_serialized_size(ctx, &proof));
379  CHECK(serialized_len == SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(n_inputs, n_used));
380 
381  /* trailing garbage */
382  memcpy(&serialized_proof_trailing, &serialized_proof, serialized_len);
383  serialized_proof_trailing[serialized_len] = seed[0];
384  CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof, serialized_len + 1) == 0);
385 
386  CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof, serialized_len));
387  result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs]);
388  CHECK(result == 1);
389  /* various fail cases */
390  if (n_inputs > 1) {
391  result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs - 1]);
392  CHECK(result == 0);
393 
394  /* number of entries in ephemeral_input_tags array is less than proof.n_inputs */
395  n_inputs -= 1;
396  result = secp256k1_surjectionproof_generate(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs], input_index, input_blinding_key[input_index], input_blinding_key[n_inputs]);
397  CHECK(result == 0);
398  result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs - 1]);
399  CHECK(result == 0);
400  n_inputs += 1;
401  }
402 
403  /* cleanup */
404  for (i = 0; i < n_inputs + 1; i++) {
405  free(input_blinding_key[i]);
406  }
407 }
408 
409 /* check that a proof with empty n_used_inputs is invalid */
410 static void test_no_used_inputs_verify(void) {
412  secp256k1_fixed_asset_tag fixed_input_tag;
413  secp256k1_fixed_asset_tag fixed_output_tag;
414  secp256k1_generator ephemeral_input_tags[1];
415  size_t n_ephemeral_input_tags = 1;
416  secp256k1_generator ephemeral_output_tag;
417  unsigned char blinding_key[32];
418  secp256k1_ge inputs[1];
419  secp256k1_ge output;
420  secp256k1_sha256 sha256_e0;
421  int result;
422 
423  /* Create proof that doesn't use inputs. secp256k1_surjectionproof_initialize
424  * will not work here since it insists on selecting an input that matches the output. */
425  proof.n_inputs = 1;
427 
428  /* create different fixed input and output tags */
429  secp256k1_rand256(fixed_input_tag.data);
430  secp256k1_rand256(fixed_output_tag.data);
431 
432  /* blind fixed output tags with random blinding key */
433  secp256k1_rand256(blinding_key);
434  CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_input_tags[0], fixed_input_tag.data, blinding_key));
435  CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_output_tag, fixed_output_tag.data, blinding_key));
436 
437  /* create "borromean signature" which is just a hash of metadata (pubkeys, etc) in this case */
438  secp256k1_generator_load(&output, &ephemeral_output_tag);
439  secp256k1_generator_load(&inputs[0], &ephemeral_input_tags[0]);
440  secp256k1_surjection_genmessage(proof.data, inputs, 1, &output);
441  secp256k1_sha256_initialize(&sha256_e0);
442  secp256k1_sha256_write(&sha256_e0, proof.data, 32);
443  secp256k1_sha256_finalize(&sha256_e0, proof.data);
444 
445  result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_ephemeral_input_tags, &ephemeral_output_tag);
446  CHECK(result == 0);
447 }
448 
449 void test_bad_serialize(void) {
451  unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX];
452  size_t serialized_len;
453 
454  proof.n_inputs = 0;
455  serialized_len = 2 + 31;
456  /* e0 is one byte too short */
457  CHECK(secp256k1_surjectionproof_serialize(ctx, serialized_proof, &serialized_len, &proof) == 0);
458 }
459 
460 void test_bad_parse(void) {
462  unsigned char serialized_proof0[] = { 0x00 };
463  unsigned char serialized_proof1[] = { 0x01, 0x00 };
464  unsigned char serialized_proof2[33] = { 0 };
465 
466  /* Missing total input count */
467  CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof0, sizeof(serialized_proof0)) == 0);
468  /* Missing bitmap */
469  CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof1, sizeof(serialized_proof1)) == 0);
470  /* Missing e0 value */
471  CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof2, sizeof(serialized_proof2)) == 0);
472 }
473 
475  int i;
476  for (i = 0; i < count; i++) {
477  test_surjectionproof_api();
478  }
479 
480  test_input_selection(0);
481  test_input_selection(1);
482  test_input_selection(5);
483  test_input_selection(100);
484  test_input_selection(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
485 
486  test_input_selection_distribution();
487  test_gen_verify(10, 3);
489  test_no_used_inputs_verify();
491  test_bad_parse();
492 }
493 
494 #endif
test_bad_serialize
void test_bad_serialize(void)
Definition: tests_impl.h:449
SECP256K1_CONTEXT_NONE
#define SECP256K1_CONTEXT_NONE
Definition: secp256k1_2.h:169
secp256k1_surjectionproof::used_inputs
unsigned char used_inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS/8]
Bitmap of which input tags are used in the surjection proof.
Definition: secp256k1_surjectionproof.h:47
secp256k1_generator_generate_blinded
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate_blinded(const secp256k1_context2 *ctx, secp256k1_generator *gen, const unsigned char *key32, const unsigned char *blind32) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
Generate a blinded generator for the curve.
Definition: main_impl.h:238
secp256k1_context_set_error_callback
SECP256K1_API void secp256k1_context_set_error_callback(secp256k1_context2 *ctx, void(*fun)(const char *message, void *data), const void *data) SECP256K1_ARG_NONNULL(1)
Set a callback function to be called when an internal consistency check fails.
Definition: secp256k1_2.c:127
memcpy
void * memcpy(void *a, const void *b, size_t c)
Definition: glibc_compat.cpp:15
secp256k1_surjectionproof.h
secp256k1_sha256
Definition: hash.h:13
secp256k1_context_destroy
SECP256K1_API void secp256k1_context_destroy(secp256k1_context2 *ctx)
Destroy a secp256k1 context object.
Definition: secp256k1_2.c:110
SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS
#define SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS
Maximum number of inputs that may be given in a surjection proof.
Definition: secp256k1_surjectionproof.h:12
secp256k1_fixed_asset_tag::data
unsigned char data[32]
Definition: secp256k1_surjectionproof.h:100
secp256k1_surjectionproof_generate
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_generate(const secp256k1_context2 *ctx, secp256k1_surjectionproof *proof, const secp256k1_generator *ephemeral_input_tags, size_t n_ephemeral_input_tags, const secp256k1_generator *ephemeral_output_tag, size_t input_index, const unsigned char *input_blinding_key, const unsigned char *output_blinding_key) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8)
Surjection proof generation function Returns 0: proof could not be created 1: proof was successfully ...
Definition: main_impl.h:211
secp256k1_generator
Opaque data structure that stores a base point.
Definition: secp256k1_generator.h:20
SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX
#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX
Maximum number of bytes a serialized surjection proof requires.
Definition: secp256k1_surjectionproof.h:21
SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES
#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(n_inputs, n_used_inputs)
Number of bytes a serialized surjection proof requires given the number of inputs and the number of u...
Definition: secp256k1_surjectionproof.h:17
secp256k1_surjectionproof_verify
SECP256K1_API int secp256k1_surjectionproof_verify(const secp256k1_context2 *ctx, const secp256k1_surjectionproof *proof, const secp256k1_generator *ephemeral_input_tags, size_t n_ephemeral_input_tags, const secp256k1_generator *ephemeral_output_tag) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5)
Surjection proof verification function Returns 0: proof was invalid 1: proof was valid.
Definition: main_impl.h:292
secp256k1_surjectionproof::data
unsigned char data[32 *(1+SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS)]
Borromean signature: e0, scalars.
Definition: secp256k1_surjectionproof.h:49
secp256k1_rangeproof.h
secp256k1_surjectionproof
Opaque data structure that holds a parsed surjection proof.
Definition: secp256k1_surjectionproof.h:39
secp256k1_surjectionproof_parse
SECP256K1_API int secp256k1_surjectionproof_parse(const secp256k1_context2 *ctx, secp256k1_surjectionproof *proof, const unsigned char *input, size_t inputlen) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Parse a surjection proof.
Definition: main_impl.h:38
secp256k1_surjectionproof_n_used_inputs
SECP256K1_API size_t secp256k1_surjectionproof_n_used_inputs(const secp256k1_context2 *ctx, const secp256k1_surjectionproof *proof) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2)
Returns the actual number of inputs that a proof uses.
Definition: main_impl.h:101
secp256k1_surjectionproof_serialize
SECP256K1_API int secp256k1_surjectionproof_serialize(const secp256k1_context2 *ctx, unsigned char *output, size_t *outputlen, const secp256k1_surjectionproof *proof) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
Serialize a surjection proof.
Definition: main_impl.h:69
secp256k1_context_struct2
Definition: secp256k1_types.h:15
run_surjection_tests
void run_surjection_tests(void)
Definition: tests_impl.h:474
secp256k1_generator.h
secp256k1_context_set_illegal_callback
SECP256K1_API void secp256k1_context_set_illegal_callback(secp256k1_context2 *ctx, void(*fun)(const char *message, void *data), const void *data) SECP256K1_ARG_NONNULL(1)
Set a callback function to be called when an illegal argument is passed to an API call.
Definition: secp256k1_2.c:119
secp256k1_context_create2
SECP256K1_API secp256k1_context2 * secp256k1_context_create2(unsigned int flags) SECP256K1_WARN_UNUSED_RESULT
Create a secp256k1 context object.
Definition: secp256k1_2.c:75
secp256k1_surjectionproof_initialize
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_initialize(const secp256k1_context2 *ctx, secp256k1_surjectionproof *proof, size_t *input_index, const secp256k1_fixed_asset_tag *fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, const secp256k1_fixed_asset_tag *fixed_output_tag, const size_t n_max_iterations, const unsigned char *random_seed32) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7)
Surjection proof initialization function; decides on inputs to use Returns 0: inputs could not be sel...
Definition: main_impl.h:154
secp256k1_surjectionproof_serialized_size
SECP256K1_API size_t secp256k1_surjectionproof_serialized_size(const secp256k1_context2 *ctx, const secp256k1_surjectionproof *proof) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2)
Returns the total size this proof would take, in bytes, when serialized.
Definition: main_impl.h:108
test_bad_parse
void test_bad_parse(void)
Definition: tests_impl.h:460
SECP256K1_CONTEXT_VERIFY
#define SECP256K1_CONTEXT_VERIFY
Flags to pass to secp256k1_context_create2.
Definition: secp256k1_2.h:167
secp256k1_fixed_asset_tag
Data structure that holds a fixed asset tag.
Definition: secp256k1_surjectionproof.h:99
CHECK
#define CHECK(cond)
Definition: util.h:43
secp256k1_ge
A group element of the secp256k1 curve, in affine coordinates.
Definition: group.h:14
secp256k1_surjectionproof_n_total_inputs
SECP256K1_API size_t secp256k1_surjectionproof_n_total_inputs(const secp256k1_context2 *ctx, const secp256k1_surjectionproof *proof) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2)
Returns the total number of inputs a proof expects to be over.
Definition: main_impl.h:94
secp256k1_surjectionproof::n_inputs
size_t n_inputs
Total number of input asset tags.
Definition: secp256k1_surjectionproof.h:45
SECP256K1_CONTEXT_SIGN
#define SECP256K1_CONTEXT_SIGN
Definition: secp256k1_2.h:168