PRCYCoin  2.0.0.7rc1
P2P Digital Currency
main_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 #ifndef SECP256K1_MODULE_SURJECTION_MAIN
7 #define SECP256K1_MODULE_SURJECTION_MAIN
8 
9 #include <assert.h>
10 #include <string.h>
11 
14 #include "hash.h"
17 
18 static size_t secp256k1_count_bits_set(const unsigned char* data, size_t count) {
19  size_t ret = 0;
20  size_t i;
21  for (i = 0; i < count; i++) {
22 #ifdef HAVE_BUILTIN_POPCOUNT
23  ret += __builtin_popcount(data[i]);
24 #else
25  ret += !!(data[i] & 0x1);
26  ret += !!(data[i] & 0x2);
27  ret += !!(data[i] & 0x4);
28  ret += !!(data[i] & 0x8);
29  ret += !!(data[i] & 0x10);
30  ret += !!(data[i] & 0x20);
31  ret += !!(data[i] & 0x40);
32  ret += !!(data[i] & 0x80);
33 #endif
34  }
35  return ret;
36 }
37 
38 int secp256k1_surjectionproof_parse(const secp256k1_context2* ctx, secp256k1_surjectionproof *proof, const unsigned char *input, size_t inputlen) {
39  size_t n_inputs;
40  size_t signature_len;
41 
42  VERIFY_CHECK(ctx != NULL);
43  ARG_CHECK(proof != NULL);
44  ARG_CHECK(input != NULL);
45  (void) ctx;
46 
47  if (inputlen < 2) {
48  return 0;
49  }
50  n_inputs = ((size_t) (input[1] << 8)) + input[0];
52  return 0;
53  }
54  if (inputlen < 2 + (n_inputs + 7) / 8) {
55  return 0;
56  }
57 
58  signature_len = 32 * (1 + secp256k1_count_bits_set(&input[2], (n_inputs + 7) / 8));
59  if (inputlen != 2 + (n_inputs + 7) / 8 + signature_len) {
60  return 0;
61  }
62  proof->n_inputs = n_inputs;
63  memcpy(proof->used_inputs, &input[2], (n_inputs + 7) / 8);
64  memcpy(proof->data, &input[2 + (n_inputs + 7) / 8], signature_len);
65 
66  return 1;
67 }
68 
69 int secp256k1_surjectionproof_serialize(const secp256k1_context2* ctx, unsigned char *output, size_t *outputlen, const secp256k1_surjectionproof *proof) {
70  size_t signature_len;
71  size_t serialized_len;
72 
73  VERIFY_CHECK(ctx != NULL);
74  ARG_CHECK(output != NULL);
75  ARG_CHECK(outputlen != NULL);
76  ARG_CHECK(proof != NULL);
77  (void) ctx;
78 
79  signature_len = 32 * (1 + secp256k1_count_bits_set(proof->used_inputs, (proof->n_inputs + 7) / 8));
80  serialized_len = 2 + (proof->n_inputs + 7) / 8 + signature_len;
81  if (*outputlen < serialized_len) {
82  return 0;
83  }
84 
85  output[0] = proof->n_inputs % 0x100;
86  output[1] = proof->n_inputs / 0x100;
87  memcpy(&output[2], proof->used_inputs, (proof->n_inputs + 7) / 8);
88  memcpy(&output[2 + (proof->n_inputs + 7) / 8], proof->data, signature_len);
89  *outputlen = serialized_len;
90 
91  return 1;
92 }
93 
95  VERIFY_CHECK(ctx != NULL);
96  ARG_CHECK(proof != NULL);
97  (void) ctx;
98  return proof->n_inputs;
99 }
100 
102  VERIFY_CHECK(ctx != NULL);
103  ARG_CHECK(proof != NULL);
104  (void) ctx;
105  return secp256k1_count_bits_set(proof->used_inputs, (proof->n_inputs + 7) / 8);
106 }
107 
109  VERIFY_CHECK(ctx != NULL);
110  ARG_CHECK(proof != NULL);
111  return 2 + (proof->n_inputs + 7) / 8 + 32 * (1 + secp256k1_surjectionproof_n_used_inputs(ctx, proof));
112 }
113 
114 typedef struct {
115  unsigned char state[32];
116  size_t state_i;
118 
119 static void secp256k1_surjectionproof_csprng_init(secp256k1_surjectionproof_csprng *csprng, const unsigned char* state) {
120  memcpy(csprng->state, state, 32);
121  csprng->state_i = 0;
122 }
123 
124 static size_t secp256k1_surjectionproof_csprng_next(secp256k1_surjectionproof_csprng *csprng, size_t rand_max) {
125  /* The number of random bytes to read for each random sample */
126  const size_t increment = rand_max > 256 ? 2 : 1;
127  /* The maximum value expressable by the number of random bytes we read */
128  const size_t selection_range = rand_max > 256 ? 0xffff : 0xff;
129  /* The largest multiple of rand_max that fits within selection_range */
130  const size_t limit = ((selection_range + 1) / rand_max) * rand_max;
131 
132  while (1) {
133  size_t val;
134  if (csprng->state_i + increment >= 32) {
135  secp256k1_sha256 sha;
136  secp256k1_sha256_initialize(&sha);
137  secp256k1_sha256_write(&sha, csprng->state, 32);
138  secp256k1_sha256_finalize(&sha, csprng->state);
139  csprng->state_i = 0;
140  }
141  val = csprng->state[csprng->state_i];
142  if (increment > 1) {
143  val = (val << 8) + csprng->state[csprng->state_i + 1];
144  }
145  csprng->state_i += increment;
146  /* Accept only values below our limit. Values equal to or above the limit are
147  * biased because they comprise only a subset of the range (0, rand_max - 1) */
148  if (val < limit) {
149  return val % rand_max;
150  }
151  }
152 }
153 
154 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) {
156  size_t n_iterations = 0;
157 
158  VERIFY_CHECK(ctx != NULL);
159  ARG_CHECK(proof != NULL);
160  ARG_CHECK(input_index != NULL);
161  ARG_CHECK(fixed_input_tags != NULL);
162  ARG_CHECK(fixed_output_tag != NULL);
163  ARG_CHECK(random_seed32 != NULL);
165  ARG_CHECK(n_input_tags_to_use <= n_input_tags);
166  (void) ctx;
167 
168  secp256k1_surjectionproof_csprng_init(&csprng, random_seed32);
169  memset(proof->data, 0, sizeof(proof->data));
170  proof->n_inputs = n_input_tags;
171 
172  while (1) {
173  int has_output_tag = 0;
174  size_t i;
175 
176  /* obtain a random set of indices */
177  memset(proof->used_inputs, 0, sizeof(proof->used_inputs));
178  for (i = 0; i < n_input_tags_to_use; i++) {
179  while (1) {
180  size_t next_input_index;
181  next_input_index = secp256k1_surjectionproof_csprng_next(&csprng, n_input_tags);
182  if (memcmp(&fixed_input_tags[next_input_index], fixed_output_tag, sizeof(*fixed_output_tag)) == 0) {
183  *input_index = next_input_index;
184  has_output_tag = 1;
185  }
186 
187  if (!(proof->used_inputs[next_input_index / 8] & (1 << (next_input_index % 8)))) {
188  proof->used_inputs[next_input_index / 8] |= (1 << (next_input_index % 8));
189  break;
190  }
191  }
192  }
193 
194  /* Check if we succeeded */
195  n_iterations++;
196  if (has_output_tag) {
197 #ifdef VERIFY
198  proof->initialized = 1;
199 #endif
200  return n_iterations;
201  }
202  if (n_iterations >= n_max_iterations) {
203 #ifdef VERIFY
204  proof->initialized = 0;
205 #endif
206  return 0;
207  }
208  }
209 }
210 
211 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) {
212  secp256k1_scalar blinding_key;
213  secp256k1_scalar tmps;
214  secp256k1_scalar nonce;
215  int overflow = 0;
216  size_t rsizes[1]; /* array needed for borromean sig API */
217  size_t indices[1]; /* array needed for borromean sig API */
218  size_t i;
219  size_t n_total_pubkeys;
220  size_t n_used_pubkeys;
221  size_t ring_input_index = 0;
225  secp256k1_ge output;
226  unsigned char msg32[32];
227 
228  VERIFY_CHECK(ctx != NULL);
229  ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
230  ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
231  ARG_CHECK(proof != NULL);
232  ARG_CHECK(ephemeral_input_tags != NULL);
233  ARG_CHECK(ephemeral_output_tag != NULL);
234  ARG_CHECK(input_blinding_key != NULL);
235  ARG_CHECK(output_blinding_key != NULL);
236 #ifdef VERIFY
237  CHECK(proof->initialized == 1);
238 #endif
239 
240  /* Compute secret key */
241  secp256k1_scalar_set_b32(&tmps, input_blinding_key, &overflow);
242  if (overflow) {
243  return 0;
244  }
245  secp256k1_scalar_set_b32(&blinding_key, output_blinding_key, &overflow);
246  if (overflow) {
247  return 0;
248  }
249  /* The only time the input may equal the output is if neither one was blinded in the first place,
250  * i.e. both blinding keys are zero. Otherwise this is a privacy leak. */
251  if (secp256k1_scalar_eq(&tmps, &blinding_key) && !secp256k1_scalar_is_zero(&blinding_key)) {
252  return 0;
253  }
254  secp256k1_scalar_negate(&tmps, &tmps);
255  secp256k1_scalar_add(&blinding_key, &blinding_key, &tmps);
256 
257  /* Compute public keys */
258  n_total_pubkeys = secp256k1_surjectionproof_n_total_inputs(ctx, proof);
259  n_used_pubkeys = secp256k1_surjectionproof_n_used_inputs(ctx, proof);
260  if (n_used_pubkeys > n_total_pubkeys || n_total_pubkeys != n_ephemeral_input_tags) {
261  return 0;
262  }
263 
264  secp256k1_generator_load(&output, ephemeral_output_tag);
265  for (i = 0; i < n_total_pubkeys; i++) {
266  secp256k1_generator_load(&inputs[i], &ephemeral_input_tags[i]);
267  }
268 
269  secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, inputs, n_total_pubkeys, proof->used_inputs, &output, input_index, &ring_input_index);
270 
271  /* Produce signature */
272  rsizes[0] = (int) n_used_pubkeys;
273  indices[0] = (int) ring_input_index;
274  secp256k1_surjection_genmessage(msg32, inputs, n_total_pubkeys, &output);
275  if (secp256k1_surjection_genrand(borromean_s, n_used_pubkeys, &blinding_key) == 0) {
276  return 0;
277  }
278  /* Borromean sign will overwrite one of the s values we just generated, so use
279  * it as a nonce instead. This avoids extra random generation and also is an
280  * homage to the rangeproof code which does this very cleverly to encode messages. */
281  nonce = borromean_s[ring_input_index];
282  secp256k1_scalar_clear(&borromean_s[ring_input_index]);
283  if (secp256k1_borromean_sign(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, &proof->data[0], borromean_s, ring_pubkeys, &nonce, &blinding_key, rsizes, indices, 1, msg32, 32) == 0) {
284  return 0;
285  }
286  for (i = 0; i < n_used_pubkeys; i++) {
287  secp256k1_scalar_get_b32(&proof->data[32 + 32 * i], &borromean_s[i]);
288  }
289  return 1;
290 }
291 
292 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) {
293  size_t rsizes[1]; /* array needed for borromean sig API */
294  size_t i;
295  size_t n_total_pubkeys;
296  size_t n_used_pubkeys;
300  secp256k1_ge output;
301  unsigned char msg32[32];
302 
303  VERIFY_CHECK(ctx != NULL);
304  ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
305  ARG_CHECK(proof != NULL);
306  ARG_CHECK(ephemeral_input_tags != NULL);
307  ARG_CHECK(ephemeral_output_tag != NULL);
308 
309  /* Compute public keys */
310  n_total_pubkeys = secp256k1_surjectionproof_n_total_inputs(ctx, proof);
311  n_used_pubkeys = secp256k1_surjectionproof_n_used_inputs(ctx, proof);
312  if (n_used_pubkeys == 0 || n_used_pubkeys > n_total_pubkeys || n_total_pubkeys != n_ephemeral_input_tags) {
313  return 0;
314  }
315 
316  secp256k1_generator_load(&output, ephemeral_output_tag);
317  for (i = 0; i < n_total_pubkeys; i++) {
318  secp256k1_generator_load(&inputs[i], &ephemeral_input_tags[i]);
319  }
320 
321  if (secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, inputs, n_total_pubkeys, proof->used_inputs, &output, 0, NULL) == 0) {
322  return 0;
323  }
324 
325  /* Verify signature */
326  rsizes[0] = (int) n_used_pubkeys;
327  for (i = 0; i < n_used_pubkeys; i++) {
328  int overflow = 0;
329  secp256k1_scalar_set_b32(&borromean_s[i], &proof->data[32 + 32 * i], &overflow);
330  if (overflow == 1) {
331  return 0;
332  }
333  }
334  secp256k1_surjection_genmessage(msg32, inputs, n_total_pubkeys, &output);
335  return secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, &proof->data[0], borromean_s, ring_pubkeys, rsizes, 1, msg32, 32);
336 }
337 
338 #endif
VERIFY_CHECK
#define VERIFY_CHECK(cond)
Definition: util.h:61
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
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_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_surjectionproof_initialize
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)
Surjection proof initialization function; decides on inputs to use Returns 0: inputs could not be sel...
Definition: main_impl.h:154
secp256k1_context_struct2::ecmult_ctx
secp256k1_ecmult_context ecmult_ctx
Definition: secp256k1_types.h:16
secp256k1_surjectionproof_generate
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)
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_scalar
A scalar modulo the group order of the secp256k1 curve.
Definition: scalar_4x64.h:13
secp256k1_surjectionproof_serialize
int secp256k1_surjectionproof_serialize(const secp256k1_context2 *ctx, unsigned char *output, size_t *outputlen, const secp256k1_surjectionproof *proof)
Serialize a surjection proof.
Definition: main_impl.h:69
secp256k1_borromean_sign
int secp256k1_borromean_sign(const secp256k1_ecmult_context *ecmult_ctx, const secp256k1_ecmult_gen_context *ecmult_gen_ctx, unsigned char *e0, secp256k1_scalar *s, const secp256k1_gej *pubs, const secp256k1_scalar *k, const secp256k1_scalar *sec, const size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen)
Definition: borromean_impl.h:112
secp256k1_gej
A group element of the secp256k1 curve, in jacobian coordinates.
Definition: group.h:24
secp256k1_surjectionproof_csprng
Definition: main_impl.h:114
secp256k1_borromean_verify
int secp256k1_borromean_verify(const secp256k1_ecmult_context *ecmult_ctx, secp256k1_scalar *evalues, const unsigned char *e0, const secp256k1_scalar *s, const secp256k1_gej *pubs, const size_t *rsizes, size_t nrings, const unsigned char *m, size_t mlen)
"Borromean" ring signature.
Definition: borromean_impl.h:58
secp256k1_surjectionproof::data
unsigned char data[32 *(1+SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS)]
Borromean signature: e0, scalars.
Definition: secp256k1_surjectionproof.h:49
borromean.h
secp256k1_rangeproof.h
secp256k1_surjectionproof_csprng::state
unsigned char state[32]
Definition: main_impl.h:115
surjection_impl.h
secp256k1_surjectionproof
Opaque data structure that holds a parsed surjection proof.
Definition: secp256k1_surjectionproof.h:39
secp256k1_context_struct2
Definition: secp256k1_types.h:15
secp256k1_surjectionproof_serialized_size
size_t secp256k1_surjectionproof_serialized_size(const secp256k1_context2 *ctx, const secp256k1_surjectionproof *proof)
Returns the total size this proof would take, in bytes, when serialized.
Definition: main_impl.h:108
secp256k1_surjectionproof_n_used_inputs
size_t secp256k1_surjectionproof_n_used_inputs(const secp256k1_context2 *ctx, const secp256k1_surjectionproof *proof)
Returns the actual number of inputs that a proof uses.
Definition: main_impl.h:101
secp256k1_surjectionproof_n_total_inputs
size_t secp256k1_surjectionproof_n_total_inputs(const secp256k1_context2 *ctx, const secp256k1_surjectionproof *proof)
Returns the total number of inputs a proof expects to be over.
Definition: main_impl.h:94
secp256k1_surjectionproof_verify
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)
Surjection proof verification function Returns 0: proof was invalid 1: proof was valid.
Definition: main_impl.h:292
secp256k1_surjectionproof_parse
int secp256k1_surjectionproof_parse(const secp256k1_context2 *ctx, secp256k1_surjectionproof *proof, const unsigned char *input, size_t inputlen)
Parse a surjection proof.
Definition: main_impl.h:38
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_context_struct2::ecmult_gen_ctx
secp256k1_ecmult_gen_context ecmult_gen_ctx
Definition: secp256k1_types.h:17
ARG_CHECK
#define ARG_CHECK(cond)
Definition: secp256k1_2.c:38
secp256k1_surjectionproof::n_inputs
size_t n_inputs
Total number of input asset tags.
Definition: secp256k1_surjectionproof.h:45
secp256k1_surjectionproof_csprng::state_i
size_t state_i
Definition: main_impl.h:116