purify
C++ Purify implementation with native circuit and BPP support
Loading...
Searching...
No Matches
bppp_bridge.c
Go to the documentation of this file.
1// Copyright (c) 2026 Judica, Inc.
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or https://opensource.org/license/mit/.
4
10#define SECP256K1_BUILD
11#define ENABLE_MODULE_GENERATOR 1
12#define ENABLE_MODULE_BPPP 1
13#define ENABLE_MODULE_EXTRAKEYS 1
14#define ENABLE_MODULE_SCHNORRSIG 1
15
16#include "purify.h"
17#include "bppp_bridge.h"
18#include "purify/secp_bridge.h"
19
20#include <limits.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "third_party/secp256k1-zkp/include/secp256k1_extrakeys.h"
25#include "third_party/secp256k1-zkp/include/secp256k1_schnorrsig.h"
26#include "third_party/secp256k1-zkp/src/secp256k1.c"
27#include "third_party/secp256k1-zkp/src/precomputed_ecmult.c"
28#include "third_party/secp256k1-zkp/src/precomputed_ecmult_gen.c"
30
31#undef secp256k1_scratch_alloc
32
33_Static_assert(sizeof(purify_scalar) == sizeof(secp256k1_scalar), "purify_scalar size mismatch");
34_Static_assert(_Alignof(purify_scalar) >= _Alignof(secp256k1_scalar), "purify_scalar alignment mismatch");
35
37 secp256k1_context* ctx;
38};
39
40static void purify_bridge_secure_clear(void* data, size_t size);
41
42static secp256k1_context* purify_context_handle(const purify_secp_context* context) {
43 return context != NULL ? context->ctx : NULL;
44}
45
47 unsigned char seed32[32] = {0};
48 purify_secp_context* context =
49 (purify_secp_context*)calloc(1, sizeof(*context));
50 if (context == NULL) {
51 return NULL;
52 }
53 context->ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
54 if (context->ctx == NULL) {
55 free(context);
56 return NULL;
57 }
58 if (purify_fill_secure_random(seed32, sizeof(seed32)) != PURIFY_ERROR_OK
59 || !secp256k1_context_randomize(context->ctx, seed32)) {
60 purify_bridge_secure_clear(seed32, sizeof(seed32));
61 secp256k1_context_destroy(context->ctx);
62 free(context);
63 return NULL;
64 }
65 purify_bridge_secure_clear(seed32, sizeof(seed32));
66 return context;
67}
68
70 if (context == NULL) {
71 return;
72 }
73 if (context->ctx != NULL) {
74 secp256k1_context_destroy(context->ctx);
75 }
76 free(context);
77}
78
79static void purify_bridge_secure_clear(void* data, size_t size) {
80 if (data != NULL && size != 0u) {
81 secp256k1_memclear_explicit(data, size);
82 }
83}
84
86 size_t n_gates;
87 secp256k1_context* ctx;
88 secp256k1_scratch_space* scratch;
90};
91
94 secp256k1_context* ctx;
95 secp256k1_scratch_space* scratch;
96 secp256k1_bppp_generators* gens;
97 secp256k1_bppp_generators gens_scratch;
99};
100
104
105static int purify_bridge_checked_mul_size(size_t lhs, size_t rhs, size_t* out) {
106 if (out == NULL) {
107 return 0;
108 }
109 if (lhs != 0 && rhs > SIZE_MAX / lhs) {
110 return 0;
111 }
112 *out = lhs * rhs;
113 return 1;
114}
115
116static int purify_bridge_checked_add_size(size_t lhs, size_t rhs, size_t* out) {
117 if (out == NULL) {
118 return 0;
119 }
120 if (rhs > SIZE_MAX - lhs) {
121 return 0;
122 }
123 *out = lhs + rhs;
124 return 1;
125}
126
127static void* purify_malloc_array(size_t count, size_t elem_size) {
128 size_t bytes = 0;
129
130 if (count == 0) {
131 return NULL;
132 }
133 if (!purify_bridge_checked_mul_size(count, elem_size, &bytes)) {
134 return NULL;
135 }
136 return malloc(bytes);
137}
138
139static void* purify_calloc_array(size_t count, size_t elem_size) {
140 size_t bytes = 0;
141
142 if (count == 0) {
143 return NULL;
144 }
145 if (!purify_bridge_checked_mul_size(count, elem_size, &bytes)) {
146 return NULL;
147 }
148 return calloc(1, bytes);
149}
150
151static secp256k1_bppp_generators* purify_bppp_generators_clone(
152 const secp256k1_bppp_generators* generators) {
153 secp256k1_bppp_generators* clone;
154 size_t generator_bytes = 0;
155
156 if (generators == NULL || generators->gens == NULL || generators->n == 0 ||
157 !purify_bridge_checked_mul_size(generators->n, sizeof(*generators->gens), &generator_bytes)) {
158 return NULL;
159 }
160
161 clone = (secp256k1_bppp_generators*)calloc(1, sizeof(*clone));
162 if (clone == NULL) {
163 return NULL;
164 }
165 clone->n = generators->n;
166 clone->gens = (secp256k1_ge*)purify_malloc_array(generators->n, sizeof(*clone->gens));
167 if (clone->gens == NULL) {
168 free(clone);
169 return NULL;
170 }
171 memcpy(clone->gens, generators->gens, generator_bytes);
172 return clone;
173}
174
175/* BPPP proving folds the generator table in place, so cached resources keep one
176 pristine parsed copy and one resettable scratch copy for prove calls. */
178 size_t generator_bytes = 0;
179
180 if (resources == NULL || resources->gens == NULL || resources->gens->gens == NULL ||
181 resources->gens->n != resources->generators_count ||
182 resources->gens_scratch.gens == NULL || resources->gens_scratch.n != resources->generators_count ||
183 !purify_bridge_checked_mul_size(resources->generators_count, sizeof(*resources->gens->gens), &generator_bytes)) {
184 return 0;
185 }
186
187 memcpy(resources->gens_scratch.gens, resources->gens->gens, generator_bytes);
188 return 1;
189}
190
194 if (guard == NULL || resources == NULL || resources->gens_scratch_in_use) {
195 return NULL;
196 }
198 return NULL;
199 }
200 resources->gens_scratch_in_use = 1;
201 guard->resources = resources;
202 return &resources->gens_scratch;
203}
204
207 if (guard != NULL && guard->resources != NULL) {
208 guard->resources->gens_scratch_in_use = 0;
209 guard->resources = NULL;
210 }
211}
212
214 size_t n_gates) {
216 size_t generator_count = 0;
217 secp256k1_context* ctx = purify_context_handle(context);
218
219 if (ctx == NULL || n_gates == 0 || !secp256k1_is_power_of_two(n_gates)) {
220 return NULL;
221 }
223 return NULL;
224 }
225
226 resources = (purify_bulletproof_backend_resources*)calloc(1, sizeof(*resources));
227 if (resources == NULL) {
228 return NULL;
229 }
230
231 resources->ctx = ctx;
232
233 resources->scratch = secp256k1_scratch_space_create(resources->ctx, 1u << 24);
234 if (resources->scratch == NULL) {
236 return NULL;
237 }
238
239 resources->gens = secp256k1_bulletproof_generators_create(resources->ctx, secp256k1_generator_h, generator_count, 1);
240 if (resources->gens == NULL || resources->gens->n < generator_count) {
242 return NULL;
243 }
244
245 resources->n_gates = n_gates;
246 return resources;
247}
248
250 const purify_bulletproof_backend_resources* resources) {
252 size_t generator_count = 0;
253
254 if (resources == NULL || resources->ctx == NULL || resources->n_gates == 0 ||
256 return NULL;
257 }
258
259 clone = (purify_bulletproof_backend_resources*)calloc(1, sizeof(*clone));
260 if (clone == NULL) {
261 return NULL;
262 }
263 clone->ctx = resources->ctx;
264 clone->n_gates = resources->n_gates;
265 clone->scratch = secp256k1_scratch_space_create(clone->ctx, 1u << 24);
266 if (clone->scratch == NULL) {
268 return NULL;
269 }
271 clone->ctx, secp256k1_generator_h, generator_count, 1);
272 if (clone->gens == NULL || clone->gens->n < generator_count) {
274 return NULL;
275 }
276 return clone;
277}
278
280 if (resources == NULL) {
281 return;
282 }
283 if (resources->gens != NULL && resources->ctx != NULL) {
284 secp256k1_bulletproof_generators_destroy(resources->ctx, resources->gens);
285 }
286 if (resources->scratch != NULL && resources->ctx != NULL) {
287 secp256k1_scratch_space_destroy(resources->ctx, resources->scratch);
288 }
289 free(resources);
290}
291
293 const unsigned char* generators33,
294 size_t generators_count) {
296 size_t serialized_len = 0;
297 secp256k1_context* ctx = purify_context_handle(context);
298
299 if (ctx == NULL || generators33 == NULL || generators_count == 0) {
300 return NULL;
301 }
302 if (!purify_bridge_checked_mul_size(generators_count, 33u, &serialized_len)) {
303 return NULL;
304 }
305
306 resources = (purify_bppp_backend_resources*)calloc(1, sizeof(*resources));
307 if (resources == NULL) {
308 return NULL;
309 }
310
311 resources->ctx = ctx;
312
313 resources->scratch = secp256k1_scratch_space_create(resources->ctx, 1u << 24);
314 if (resources->scratch == NULL) {
316 return NULL;
317 }
318
319 resources->gens = secp256k1_bppp_generators_parse(resources->ctx, generators33, serialized_len);
320 if (resources->gens == NULL || resources->gens->n != generators_count) {
322 return NULL;
323 }
324 resources->gens_scratch.n = generators_count;
325 resources->gens_scratch.gens =
326 (secp256k1_ge*)purify_malloc_array(generators_count, sizeof(*resources->gens_scratch.gens));
327 if (resources->gens_scratch.gens == NULL) {
329 return NULL;
330 }
331
332 resources->generators_count = generators_count;
333 return resources;
334}
335
337 const purify_bppp_backend_resources* resources) {
339 size_t generator_bytes = 0;
340
341 if (resources == NULL || resources->ctx == NULL || resources->generators_count == 0 ||
342 resources->gens == NULL || resources->gens->n != resources->generators_count ||
343 !purify_bridge_checked_mul_size(resources->generators_count, sizeof(*resources->gens->gens), &generator_bytes)) {
344 return NULL;
345 }
346
347 clone = (purify_bppp_backend_resources*)calloc(1, sizeof(*clone));
348 if (clone == NULL) {
349 return NULL;
350 }
351 clone->ctx = resources->ctx;
352 clone->generators_count = resources->generators_count;
353 clone->scratch = secp256k1_scratch_space_create(clone->ctx, 1u << 24);
354 if (clone->scratch == NULL) {
356 return NULL;
357 }
358 clone->gens = purify_bppp_generators_clone(resources->gens);
359 if (clone->gens == NULL) {
361 return NULL;
362 }
363 clone->gens_scratch.n = clone->generators_count;
364 clone->gens_scratch.gens =
365 (secp256k1_ge*)purify_malloc_array(clone->generators_count, sizeof(*clone->gens_scratch.gens));
366 if (clone->gens_scratch.gens == NULL) {
368 return NULL;
369 }
370 memcpy(clone->gens_scratch.gens, clone->gens->gens, generator_bytes);
371 return clone;
372}
373
375 if (resources == NULL) {
376 return;
377 }
378 if (resources->gens != NULL && resources->ctx != NULL) {
379 secp256k1_bppp_generators_destroy(resources->ctx, resources->gens);
380 }
381 if (resources->gens_scratch.gens != NULL) {
382 free(resources->gens_scratch.gens);
383 }
384 if (resources->scratch != NULL && resources->ctx != NULL) {
385 secp256k1_scratch_space_destroy(resources->ctx, resources->scratch);
386 }
387 free(resources);
388}
389
390static secp256k1_scalar* purify_scalar_cast(purify_scalar* scalar) {
391 return (secp256k1_scalar*)scalar;
392}
393
394static const secp256k1_scalar* purify_scalar_cast_const(const purify_scalar* scalar) {
395 return (const secp256k1_scalar*)scalar;
396}
397
398void purify_scalar_set_int(purify_scalar* out, unsigned int value) {
399 secp256k1_scalar_set_int(purify_scalar_cast(out), value);
400}
401
402void purify_scalar_set_u64(purify_scalar* out, uint64_t value) {
403 secp256k1_scalar_set_u64(purify_scalar_cast(out), value);
404}
405
406void purify_scalar_set_b32(purify_scalar* out, const unsigned char input32[32], int* overflow) {
407 secp256k1_scalar_set_b32(purify_scalar_cast(out), input32, overflow);
408}
409
410void purify_scalar_get_b32(unsigned char output32[32], const purify_scalar* value) {
411 secp256k1_scalar_get_b32(output32, purify_scalar_cast_const(value));
412}
413
415 return secp256k1_scalar_is_zero(purify_scalar_cast_const(value));
416}
417
419 return secp256k1_scalar_is_one(purify_scalar_cast_const(value));
420}
421
423 return secp256k1_scalar_is_even(purify_scalar_cast_const(value));
424}
425
426int purify_scalar_eq(const purify_scalar* lhs, const purify_scalar* rhs) {
427 return secp256k1_scalar_eq(purify_scalar_cast_const(lhs), purify_scalar_cast_const(rhs));
428}
429
431 secp256k1_scalar_negate(purify_scalar_cast(out), purify_scalar_cast_const(value));
432}
433
435 secp256k1_scalar_inverse(purify_scalar_cast(out), purify_scalar_cast_const(value));
436}
437
439 secp256k1_scalar_inverse_var(purify_scalar_cast(out), purify_scalar_cast_const(value));
440}
441
443 return secp256k1_scalar_add(purify_scalar_cast(out), purify_scalar_cast_const(lhs), purify_scalar_cast_const(rhs));
444}
445
446void purify_scalar_mul(purify_scalar* out, const purify_scalar* lhs, const purify_scalar* rhs) {
447 secp256k1_scalar_mul(purify_scalar_cast(out), purify_scalar_cast_const(lhs), purify_scalar_cast_const(rhs));
448}
449
450void purify_scalar_cmov(purify_scalar* dst, const purify_scalar* src, int flag) {
451 secp256k1_scalar_cmov(purify_scalar_cast(dst), purify_scalar_cast_const(src), flag);
452}
453
454void purify_sha256(unsigned char output32[32], const unsigned char *data,
455 size_t data_len) {
456 static const unsigned char zero = 0;
457 secp256k1_sha256 sha256;
458
459 if (data == NULL && data_len == 0) {
460 data = &zero;
461 }
462
463 secp256k1_sha256_initialize(&sha256);
464 if (data_len != 0) {
465 secp256k1_sha256_write(&sha256, data, data_len);
466 }
467 secp256k1_sha256_finalize(&sha256, output32);
468 secp256k1_sha256_clear(&sha256);
469}
470
471int purify_sha256_many(unsigned char output32[32],
472 const unsigned char *const *items,
473 const size_t *item_lens,
474 size_t items_count) {
475 secp256k1_sha256 sha256;
476 if (output32 == NULL) {
477 return 0;
478 }
479 if (items_count != 0 && (items == NULL || item_lens == NULL)) {
480 memset(output32, 0, 32);
481 return 0;
482 }
483 secp256k1_sha256_initialize(&sha256);
484 for (size_t i = 0; i < items_count; ++i) {
485 const unsigned char *item = items[i];
486 size_t item_len = item_lens[i];
487 if (item == NULL) {
488 if (item_len != 0) {
489 secp256k1_sha256_clear(&sha256);
490 memset(output32, 0, 32);
491 return 0;
492 }
493 continue;
494 }
495 if (item_len != 0) {
496 secp256k1_sha256_write(&sha256, item, item_len);
497 }
498 }
499 secp256k1_sha256_finalize(&sha256, output32);
500 secp256k1_sha256_clear(&sha256);
501 return 1;
502}
503
504void purify_hmac_sha256(unsigned char output32[32],
505 const unsigned char* key, size_t key_len,
506 const unsigned char* data, size_t data_len) {
507 static const unsigned char zero = 0;
508 secp256k1_hmac_sha256 hmac;
509
510 if (key == NULL && key_len == 0) {
511 key = &zero;
512 }
513 if (data == NULL && data_len == 0) {
514 data = &zero;
515 }
516
517 secp256k1_hmac_sha256_initialize(&hmac, key, key_len);
518 if (data_len != 0) {
519 secp256k1_hmac_sha256_write(&hmac, data, data_len);
520 }
521 secp256k1_hmac_sha256_finalize(&hmac, output32);
522 secp256k1_hmac_sha256_clear(&hmac);
523}
524
526 unsigned char seckey32[32],
527 unsigned char xonly_pubkey32[32]) {
528 secp256k1_context* ctx = purify_context_handle(context);
529 secp256k1_keypair keypair;
530 secp256k1_xonly_pubkey xonly;
531 int parity = 0;
532 int ok = 0;
533
534 memset(&keypair, 0, sizeof(keypair));
535 memset(&xonly, 0, sizeof(xonly));
536 if (xonly_pubkey32 != NULL) {
537 memset(xonly_pubkey32, 0, 32);
538 }
539
540 if (ctx == NULL || seckey32 == NULL || xonly_pubkey32 == NULL) {
541 return 0;
542 }
543
544 ok = secp256k1_keypair_create(ctx, &keypair, seckey32);
545 if (ok) {
546 ok = secp256k1_keypair_xonly_pub(ctx, &xonly, &parity, &keypair);
547 }
548 if (ok) {
549 ok = secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey32, &xonly);
550 }
551 if (ok && parity != 0) {
552 ok = secp256k1_ec_seckey_negate(ctx, seckey32);
553 }
554 if (!ok) {
555 purify_bridge_secure_clear(seckey32, 32);
556 memset(xonly_pubkey32, 0, 32);
557 }
558
559 purify_bridge_secure_clear(&keypair, sizeof(keypair));
560 purify_bridge_secure_clear(&xonly, sizeof(xonly));
561 return ok;
562}
563
565 unsigned char scalar32[32],
566 unsigned char xonly_nonce32[32]) {
567 secp256k1_context* ctx = purify_context_handle(context);
568 secp256k1_pubkey pubkey;
569 secp256k1_xonly_pubkey xonly;
570 int parity = 0;
571 int ok = 0;
572
573 memset(&pubkey, 0, sizeof(pubkey));
574 memset(&xonly, 0, sizeof(xonly));
575 if (xonly_nonce32 != NULL) {
576 memset(xonly_nonce32, 0, 32);
577 }
578
579 if (ctx == NULL || scalar32 == NULL || xonly_nonce32 == NULL) {
580 return 0;
581 }
582
583 ok = secp256k1_ec_pubkey_create(ctx, &pubkey, scalar32);
584 if (ok) {
585 ok = secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly, &parity, &pubkey);
586 }
587 if (ok) {
588 ok = secp256k1_xonly_pubkey_serialize(ctx, xonly_nonce32, &xonly);
589 }
590 if (ok && parity != 0) {
591 ok = secp256k1_ec_seckey_negate(ctx, scalar32);
592 }
593 if (!ok) {
594 purify_bridge_secure_clear(scalar32, 32);
595 memset(xonly_nonce32, 0, 32);
596 }
597
598 purify_bridge_secure_clear(&pubkey, sizeof(pubkey));
599 purify_bridge_secure_clear(&xonly, sizeof(xonly));
600 return ok;
601}
602
604 const unsigned char point33[33],
605 unsigned char xonly32[32],
606 int* parity_out) {
607 secp256k1_context* ctx = purify_context_handle(context);
608 secp256k1_pubkey pubkey;
609 secp256k1_xonly_pubkey xonly;
610 int parity = 0;
611 int ok = 0;
612
613 memset(&pubkey, 0, sizeof(pubkey));
614 memset(&xonly, 0, sizeof(xonly));
615 if (xonly32 != NULL) {
616 memset(xonly32, 0, 32);
617 }
618 if (parity_out != NULL) {
619 *parity_out = 0;
620 }
621
622 if (ctx == NULL || point33 == NULL || xonly32 == NULL) {
623 return 0;
624 }
625
626 ok = secp256k1_ec_pubkey_parse(ctx, &pubkey, point33, 33);
627 if (ok) {
628 ok = secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly, &parity, &pubkey);
629 }
630 if (ok) {
631 ok = secp256k1_xonly_pubkey_serialize(ctx, xonly32, &xonly);
632 }
633 if (ok && parity_out != NULL) {
634 *parity_out = parity;
635 }
636 if (!ok) {
637 memset(xonly32, 0, 32);
638 }
639
640 purify_bridge_secure_clear(&pubkey, sizeof(pubkey));
641 purify_bridge_secure_clear(&xonly, sizeof(xonly));
642 return ok;
643}
644
646 const unsigned char xonly_pubkey32[32]) {
647 secp256k1_context* ctx = purify_context_handle(context);
648 secp256k1_xonly_pubkey xonly;
649 int ok = 0;
650
651 memset(&xonly, 0, sizeof(xonly));
652 if (ctx == NULL || xonly_pubkey32 == NULL) {
653 return 0;
654 }
655
656 ok = secp256k1_xonly_pubkey_parse(ctx, &xonly, xonly_pubkey32);
657
658 purify_bridge_secure_clear(&xonly, sizeof(xonly));
659 return ok;
660}
661
663 const unsigned char sig64[64]) {
664 secp256k1_context* ctx = purify_context_handle(context);
665 secp256k1_xonly_pubkey rxonly;
666 secp256k1_scalar s;
667 int overflow = 0;
668 int ok = 0;
669
670 purify_bridge_secure_clear(&rxonly, sizeof(rxonly));
671 purify_bridge_secure_clear(&s, sizeof(s));
672 if (ctx == NULL || sig64 == NULL) {
673 return 0;
674 }
675
676 ok = secp256k1_xonly_pubkey_parse(ctx, &rxonly, sig64);
677 if (ok) {
678 secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow);
679 ok = !overflow;
680 }
681
682 purify_bridge_secure_clear(&rxonly, sizeof(rxonly));
683 secp256k1_scalar_clear(&s);
684 return ok;
685}
686
687static int purify_fixed_nonce_function(unsigned char *nonce32,
688 const unsigned char *msg, size_t msglen,
689 const unsigned char *key32,
690 const unsigned char *xonly_pk32,
691 const unsigned char *algo, size_t algolen,
692 void *data) {
693 (void)msg;
694 (void)msglen;
695 (void)key32;
696 (void)xonly_pk32;
697 (void)algo;
698 (void)algolen;
699
700 if (nonce32 == NULL || data == NULL) {
701 return 0;
702 }
703 memcpy(nonce32, data, 32);
704 return 1;
705}
706
708 unsigned char sig64[64],
709 const unsigned char* msg, size_t msglen,
710 const unsigned char seckey32[32],
711 const unsigned char nonce32[32]) {
712 secp256k1_context* ctx = purify_context_handle(context);
713 secp256k1_keypair keypair;
714 secp256k1_scalar nonce_scalar;
715 secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
716 unsigned char canonical_nonce32[32];
717 unsigned char xonly_nonce32[32];
718 int ok = 0;
719 int overflow = 0;
720
721 purify_bridge_secure_clear(&keypair, sizeof(keypair));
722 purify_bridge_secure_clear(&nonce_scalar, sizeof(nonce_scalar));
723 purify_bridge_secure_clear(canonical_nonce32, sizeof(canonical_nonce32));
724 purify_bridge_secure_clear(xonly_nonce32, sizeof(xonly_nonce32));
725 if (sig64 != NULL) {
726 memset(sig64, 0, 64);
727 }
728
729 if (ctx == NULL || sig64 == NULL || seckey32 == NULL || nonce32 == NULL || (msg == NULL && msglen != 0)) {
730 return 0;
731 }
732
733 memcpy(canonical_nonce32, nonce32, 32);
734 ok = purify_bip340_nonce_from_scalar(context, canonical_nonce32, xonly_nonce32);
735 if (ok) {
736 ok = secp256k1_memcmp_var(canonical_nonce32, nonce32, 32) == 0;
737 }
738 secp256k1_scalar_set_b32(&nonce_scalar, nonce32, &overflow);
739 if (ok && !overflow && !secp256k1_scalar_is_zero(&nonce_scalar)) {
740 ok = secp256k1_keypair_create(ctx, &keypair, seckey32);
741 if (ok) {
742 extraparams.noncefp = purify_fixed_nonce_function;
743 extraparams.ndata = (void*)nonce32;
744 ok = secp256k1_schnorrsig_sign_custom(ctx, sig64, msg, msglen, &keypair, &extraparams);
745 }
746 }
747
748 purify_bridge_secure_clear(&keypair, sizeof(keypair));
749 secp256k1_scalar_clear(&nonce_scalar);
750 purify_bridge_secure_clear(canonical_nonce32, sizeof(canonical_nonce32));
751 purify_bridge_secure_clear(xonly_nonce32, sizeof(xonly_nonce32));
752 if (!ok) {
753 memset(sig64, 0, 64);
754 }
755 return ok;
756}
757
759 const unsigned char sig64[64],
760 const unsigned char* msg, size_t msglen,
761 const unsigned char xonly_pubkey32[32]) {
762 secp256k1_context* ctx = purify_context_handle(context);
763 secp256k1_xonly_pubkey pubkey;
764 int ok = 0;
765
766 memset(&pubkey, 0, sizeof(pubkey));
767 if (ctx == NULL || sig64 == NULL || xonly_pubkey32 == NULL || (msg == NULL && msglen != 0)) {
768 return 0;
769 }
770
771 ok = secp256k1_xonly_pubkey_parse(ctx, &pubkey, xonly_pubkey32);
772 if (ok) {
773 ok = secp256k1_schnorrsig_verify(ctx, sig64, msg, msglen, &pubkey);
774 }
775
776 memset(&pubkey, 0, sizeof(pubkey));
777 return ok;
778}
779
780static int purify_parse_scalar(const unsigned char input32[32], secp256k1_scalar* scalar, int reject_zero) {
781 int overflow = 0;
782 secp256k1_scalar_set_b32(scalar, input32, &overflow);
783 if (overflow) {
784 return 0;
785 }
786 if (reject_zero && secp256k1_scalar_is_zero(scalar)) {
787 return 0;
788 }
789 return 1;
790}
791
792static int purify_parse_scalar_array(const unsigned char* input32, size_t count, secp256k1_scalar* out) {
793 size_t i;
794 for (i = 0; i < count; ++i) {
795 if (!purify_parse_scalar(input32 + 32 * i, &out[i], 0)) {
796 return 0;
797 }
798 }
799 return 1;
800}
801
802static int purify_serialize_point(unsigned char out33[33], secp256k1_ge* point) {
803 secp256k1_fe_normalize_var(&point->x);
804 secp256k1_fe_normalize_var(&point->y);
805 return secp256k1_bppp_serialize_pt(out33, point);
806}
807
808static int purify_parse_fast_scalar(const unsigned char input32[32], secp256k1_fast_scalar* scalar) {
809 secp256k1_scalar one, two, neg_one, neg_two;
810
811 if (!purify_parse_scalar(input32, &scalar->scal, 0)) {
812 return 0;
813 }
814
815 secp256k1_scalar_set_int(&one, 1);
816 secp256k1_scalar_set_int(&two, 2);
817 secp256k1_scalar_negate(&neg_one, &one);
818 secp256k1_scalar_negate(&neg_two, &two);
819
820 scalar->special = 3;
821 if (secp256k1_scalar_is_zero(&scalar->scal)) {
822 scalar->special = 0;
823 } else if (secp256k1_scalar_eq(&scalar->scal, &one)) {
824 scalar->special = 1;
825 } else if (secp256k1_scalar_eq(&scalar->scal, &two)) {
826 scalar->special = 2;
827 } else if (secp256k1_scalar_eq(&scalar->scal, &neg_one)) {
828 scalar->special = -1;
829 } else if (secp256k1_scalar_eq(&scalar->scal, &neg_two)) {
830 scalar->special = -2;
831 }
832 return 1;
833}
834
835static int purify_parse_generator_as_ge(const secp256k1_context* ctx, const unsigned char generator33[33], secp256k1_ge* out) {
836 secp256k1_generator generator;
837 if (ctx == NULL || generator33 == NULL || out == NULL) {
838 return 0;
839 }
840 if (!secp256k1_generator_parse(ctx, &generator, generator33)) {
841 return 0;
842 }
843 secp256k1_generator_load(out, &generator);
844 return 1;
845}
846
847static int purify_parse_point_as_ge(const unsigned char point33[33], secp256k1_ge* out) {
848 if (point33 == NULL || out == NULL) {
849 return 0;
850 }
851 return secp256k1_eckey_pubkey_parse(out, point33, 33);
852}
853
855 if (circuit == NULL) {
856 return;
857 }
858 free(circuit->wl);
859 free(circuit->wr);
860 free(circuit->wo);
861 free(circuit->wv);
862 free(circuit->c);
863 free(circuit->entries);
864 memset(circuit, 0, sizeof(*circuit));
865}
866
868 if (assignment == NULL) {
869 return;
870 }
871 free(assignment->al);
872 free(assignment->ar);
873 free(assignment->ao);
874 free(assignment->v);
875 memset(assignment, 0, sizeof(*assignment));
876}
877
878static size_t purify_total_row_entries(const purify_bulletproof_row_view* rows, size_t count, int* ok) {
879 size_t total = 0;
880 size_t i;
881
882 if (ok != NULL) {
883 *ok = 0;
884 }
885 if (count == 0) {
886 if (ok != NULL) {
887 *ok = 1;
888 }
889 return 0;
890 }
891 if (rows == NULL) {
892 return 0;
893 }
894 for (i = 0; i < count; ++i) {
895 if (rows[i].size != 0 && (rows[i].indices == NULL || rows[i].scalars32 == NULL)) {
896 return 0;
897 }
898 if (!purify_bridge_checked_add_size(total, rows[i].size, &total)) {
899 return 0;
900 }
901 }
902 if (ok != NULL) {
903 *ok = 1;
904 }
905 return total;
906}
907
909 size_t row_count,
910 const purify_bulletproof_row_view* in_rows,
911 size_t n_constraints,
913 size_t* offset) {
914 size_t i;
915 for (i = 0; i < row_count; ++i) {
916 size_t j;
917 out_rows[i].size = in_rows[i].size;
918 out_rows[i].entry = in_rows[i].size == 0 ? NULL : entries + *offset;
919 for (j = 0; j < in_rows[i].size; ++j) {
920 size_t entry_idx = *offset + j;
921 if (in_rows[i].indices[j] >= n_constraints) {
922 return 0;
923 }
924 out_rows[i].entry[j].idx = in_rows[i].indices[j];
925 if (!purify_parse_fast_scalar(in_rows[i].scalars32 + 32 * j, &out_rows[i].entry[j].scal)) {
926 return 0;
927 }
928 entries[entry_idx] = out_rows[i].entry[j];
929 }
930 *offset += in_rows[i].size;
931 }
932 return 1;
933}
934
935static void purify_bulletproof_circuit_evaluate_sum_row(secp256k1_scalar* acc,
937 const secp256k1_scalar* assn) {
938 size_t j;
939 for (j = 0; j < row->size; ++j) {
940 secp256k1_scalar term;
941 secp256k1_fast_scalar_mul(&term, &row->entry[j].scal, assn);
942 secp256k1_scalar_add(&acc[row->entry[j].idx], &acc[row->entry[j].idx], &term);
943 }
944}
945
948 secp256k1_scalar* acc = NULL;
949 size_t i;
950 int ok = 0;
951
952 if (circuit == NULL || assignment == NULL) {
953 return 0;
954 }
955 if (assignment->n_gates != circuit->n_gates || assignment->n_commits != circuit->n_commits) {
956 return 0;
957 }
958
959 acc = circuit->n_constraints == 0 ? NULL : (secp256k1_scalar*)calloc(circuit->n_constraints, sizeof(*acc));
960 if (circuit->n_constraints != 0 && acc == NULL) {
961 return 0;
962 }
963
964 for (i = 0; i < assignment->n_gates; ++i) {
965 secp256k1_scalar product;
966 secp256k1_scalar_mul(&product, &assignment->al[i], &assignment->ar[i]);
967 if (!secp256k1_scalar_eq(&product, &assignment->ao[i])) {
968 goto done;
969 }
970 }
971
972 for (i = 0; i < circuit->n_constraints; ++i) {
973 secp256k1_scalar_clear(&acc[i]);
974 }
975
976 for (i = 0; i < circuit->n_gates; ++i) {
977 purify_bulletproof_circuit_evaluate_sum_row(acc, &circuit->wl[i], &assignment->al[i]);
978 purify_bulletproof_circuit_evaluate_sum_row(acc, &circuit->wr[i], &assignment->ar[i]);
979 purify_bulletproof_circuit_evaluate_sum_row(acc, &circuit->wo[i], &assignment->ao[i]);
980 }
981 for (i = 0; i < circuit->n_commits; ++i) {
982 secp256k1_scalar negated_v;
983 secp256k1_scalar_negate(&negated_v, &assignment->v[i]);
984 purify_bulletproof_circuit_evaluate_sum_row(acc, &circuit->wv[i], &negated_v);
985 }
986 for (i = 0; i < circuit->n_constraints; ++i) {
987 secp256k1_scalar constant_term;
988 secp256k1_scalar one;
989 secp256k1_scalar_set_int(&one, 1);
990 secp256k1_fast_scalar_mul(&constant_term, &circuit->c[i], &one);
991 if (!secp256k1_scalar_eq(&acc[i], &constant_term)) {
992 goto done;
993 }
994 }
995 ok = 1;
996
997done:
998 free(acc);
999 return ok;
1000}
1001
1004 int ok = 0;
1005 size_t row_entries = 0;
1006 size_t total_entries = 0;
1007 size_t offset = 0;
1008 size_t i;
1009
1010 /* Bit/range-style circuits can have no explicit constraint rows, so the
1011 * constant vector is optional when n_constraints == 0.
1012 */
1013 if (view == NULL || out == NULL || (view->n_constraints != 0 && view->c32 == NULL)) {
1014 return 0;
1015 }
1016 if (!secp256k1_is_power_of_two(view->n_gates) || view->n_commits > 1) {
1017 return 0;
1018 }
1019 memset(out, 0, sizeof(*out));
1020
1021 row_entries = purify_total_row_entries(view->wl, view->n_gates, &ok);
1022 if (!ok || !purify_bridge_checked_add_size(total_entries, row_entries, &total_entries)) return 0;
1023 row_entries = purify_total_row_entries(view->wr, view->n_gates, &ok);
1024 if (!ok || !purify_bridge_checked_add_size(total_entries, row_entries, &total_entries)) return 0;
1025 row_entries = purify_total_row_entries(view->wo, view->n_gates, &ok);
1026 if (!ok || !purify_bridge_checked_add_size(total_entries, row_entries, &total_entries)) return 0;
1027 row_entries = purify_total_row_entries(view->wv, view->n_commits, &ok);
1028 if (!ok || !purify_bridge_checked_add_size(total_entries, row_entries, &total_entries)) return 0;
1029
1030 out->n_gates = view->n_gates;
1031 out->n_commits = view->n_commits;
1032 out->n_bits = view->n_bits;
1033 out->n_constraints = view->n_constraints;
1034 out->wl = (secp256k1_bulletproof_wmatrix_row*)purify_calloc_array(view->n_gates, sizeof(*out->wl));
1035 out->wr = (secp256k1_bulletproof_wmatrix_row*)purify_calloc_array(view->n_gates, sizeof(*out->wr));
1036 out->wo = (secp256k1_bulletproof_wmatrix_row*)purify_calloc_array(view->n_gates, sizeof(*out->wo));
1038 /* Mirror the legacy circuit representation: no explicit constraints means
1039 * no c vector allocation either.
1040 */
1041 out->c = (secp256k1_fast_scalar*)purify_malloc_array(view->n_constraints, sizeof(*out->c));
1042 out->entries = (secp256k1_bulletproof_wmatrix_entry*)purify_malloc_array(total_entries, sizeof(*out->entries));
1043 if ((view->n_gates != 0 && (out->wl == NULL || out->wr == NULL || out->wo == NULL)) ||
1044 (view->n_commits != 0 && out->wv == NULL) ||
1045 (view->n_constraints != 0 && out->c == NULL) ||
1046 (total_entries != 0 && out->entries == NULL)) {
1048 return 0;
1049 }
1050
1051 if (!purify_build_row_family(out->wl, view->n_gates, view->wl, view->n_constraints, out->entries, &offset) ||
1052 !purify_build_row_family(out->wr, view->n_gates, view->wr, view->n_constraints, out->entries, &offset) ||
1053 !purify_build_row_family(out->wo, view->n_gates, view->wo, view->n_constraints, out->entries, &offset) ||
1054 !purify_build_row_family(out->wv, view->n_commits, view->wv, view->n_constraints, out->entries, &offset)) {
1056 return 0;
1057 }
1058 for (i = 0; i < view->n_constraints; ++i) {
1059 if (!purify_parse_fast_scalar(view->c32 + 32 * i, &out->c[i])) {
1061 return 0;
1062 }
1063 }
1064 return 1;
1065}
1066
1069 if (view == NULL || out == NULL) {
1070 return 0;
1071 }
1072 if ((view->n_gates != 0 && (view->al32 == NULL || view->ar32 == NULL || view->ao32 == NULL)) ||
1073 (view->n_commits != 0 && view->v32 == NULL) ||
1074 view->n_commits > 1) {
1075 return 0;
1076 }
1077 memset(out, 0, sizeof(*out));
1078 out->n_gates = view->n_gates;
1079 out->n_commits = view->n_commits;
1080 out->al = (secp256k1_scalar*)purify_malloc_array(view->n_gates, sizeof(*out->al));
1081 out->ar = (secp256k1_scalar*)purify_malloc_array(view->n_gates, sizeof(*out->ar));
1082 out->ao = (secp256k1_scalar*)purify_malloc_array(view->n_gates, sizeof(*out->ao));
1083 out->v = (secp256k1_scalar*)purify_malloc_array(view->n_commits, sizeof(*out->v));
1084 if ((view->n_gates != 0 && (out->al == NULL || out->ar == NULL || out->ao == NULL)) ||
1085 (view->n_commits != 0 && out->v == NULL)) {
1087 return 0;
1088 }
1089 if (!purify_parse_scalar_array(view->al32, view->n_gates, out->al) ||
1090 !purify_parse_scalar_array(view->ar32, view->n_gates, out->ar) ||
1091 !purify_parse_scalar_array(view->ao32, view->n_gates, out->ao) ||
1092 !purify_parse_scalar_array(view->v32, view->n_commits, out->v)) {
1094 return 0;
1095 }
1096 return 1;
1097}
1098
1100 size_t proof_size = 0;
1101
1102 if (n_gates == 0) {
1103 return 0;
1104 }
1106 return 0;
1107 }
1108 return proof_size;
1109}
1110
1112 const purify_bulletproof_assignment_view* assignment,
1113 const unsigned char* blind32,
1114 const unsigned char value_gen33[33],
1115 const unsigned char nonce32[32],
1116 const unsigned char* extra_commit,
1117 size_t extra_commit_len,
1118 unsigned char commitment_out33[33],
1119 unsigned char* proof_out,
1120 size_t* proof_len,
1121 int require_valid_assignment,
1122 purify_secp_context* context,
1124 secp256k1_context* ctx = NULL;
1125 secp256k1_scratch_space* scratch = NULL;
1129 secp256k1_ge value_gen;
1130 secp256k1_ge commit_points[1];
1131 secp256k1_scalar blinds[1];
1132 size_t n_commits = 0;
1133 size_t required_generators = 0;
1134 int ok = 0;
1135 int owns_resources = 0;
1136
1137 memset(&bp_circuit, 0, sizeof(bp_circuit));
1138 memset(&bp_assignment, 0, sizeof(bp_assignment));
1139 memset(commit_points, 0, sizeof(commit_points));
1140 memset(blinds, 0, sizeof(blinds));
1141 if (commitment_out33 != NULL) {
1142 memset(commitment_out33, 0, 33);
1143 }
1144
1145 if (circuit == NULL || assignment == NULL || value_gen33 == NULL || nonce32 == NULL || proof_out == NULL || proof_len == NULL) {
1146 return 0;
1147 }
1148 if (extra_commit == NULL && extra_commit_len != 0) {
1149 return 0;
1150 }
1151 if (!purify_build_bulletproof_circuit(circuit, &bp_circuit) ||
1152 !purify_build_bulletproof_assignment(assignment, &bp_assignment)) {
1153 goto done;
1154 }
1155 if (require_valid_assignment && !purify_bulletproof_circuit_evaluate(&bp_circuit, &bp_assignment)) {
1156 goto done;
1157 }
1158 if (resources == NULL) {
1159 resources = purify_bulletproof_backend_resources_create(context, bp_circuit.n_gates);
1160 if (resources == NULL) {
1161 goto done;
1162 }
1163 owns_resources = 1;
1164 }
1165 if (resources->n_gates < bp_circuit.n_gates || resources->ctx == NULL || resources->scratch == NULL || resources->gens == NULL) {
1166 goto done;
1167 }
1168 ctx = resources->ctx;
1169 scratch = resources->scratch;
1170 gens = resources->gens;
1171 if (!purify_bridge_checked_mul_size(2u, bp_circuit.n_gates, &required_generators) ||
1172 gens->n < required_generators) {
1173 goto done;
1174 }
1175 if (!purify_parse_generator_as_ge(ctx, value_gen33, &value_gen)) {
1176 goto done;
1177 }
1178
1179 n_commits = bp_circuit.n_commits;
1180 if (n_commits == 1) {
1181 secp256k1_gej commitj;
1182 if (commitment_out33 == NULL) {
1183 goto done;
1184 }
1185 if (blind32 == NULL) {
1186 secp256k1_scalar_clear(&blinds[0]);
1187 } else if (!purify_parse_scalar(blind32, &blinds[0], 0)) {
1188 goto done;
1189 }
1190 secp256k1_pedersen_ecmult_scalar(&commitj, &blinds[0], &bp_assignment.v[0], &value_gen, gens->blinding_gen);
1191 if (secp256k1_gej_is_infinity(&commitj)) {
1192 goto done;
1193 }
1194 secp256k1_ge_set_gej(&commit_points[0], &commitj);
1195 if (!purify_serialize_point(commitment_out33, &commit_points[0])) {
1196 goto done;
1197 }
1198 } else if (n_commits > 1) {
1199 goto done;
1200 }
1201
1203 &ctx->error_callback,
1204 scratch,
1205 proof_out,
1206 proof_len,
1207 &bp_assignment,
1208 n_commits == 0 ? NULL : commit_points,
1209 n_commits == 0 ? NULL : blinds,
1210 n_commits,
1211 &value_gen,
1212 &bp_circuit,
1213 gens,
1214 nonce32,
1215 extra_commit,
1216 extra_commit_len
1217 );
1218
1219done:
1220 purify_free_bulletproof_assignment(&bp_assignment);
1222 if (owns_resources) {
1224 }
1225 return ok;
1226}
1227
1229 const purify_bulletproof_circuit_view* circuit,
1230 const purify_bulletproof_assignment_view* assignment,
1231 const unsigned char* blind32,
1232 const unsigned char value_gen33[33],
1233 const unsigned char nonce32[32],
1234 const unsigned char* extra_commit,
1235 size_t extra_commit_len,
1236 unsigned char commitment_out33[33],
1237 unsigned char* proof_out,
1238 size_t* proof_len) {
1239 return purify_bulletproof_prove_circuit_impl(circuit, assignment, blind32, value_gen33, nonce32,
1240 extra_commit, extra_commit_len, commitment_out33,
1241 proof_out, proof_len, 1, context, NULL);
1242}
1243
1245 const purify_bulletproof_circuit_view* circuit,
1246 const purify_bulletproof_assignment_view* assignment,
1247 const unsigned char* blind32,
1248 const unsigned char value_gen33[33],
1249 const unsigned char nonce32[32],
1250 const unsigned char* extra_commit,
1251 size_t extra_commit_len,
1252 unsigned char commitment_out33[33],
1253 unsigned char* proof_out,
1254 size_t* proof_len) {
1255 return purify_bulletproof_prove_circuit_impl(circuit, assignment, blind32, value_gen33, nonce32,
1256 extra_commit, extra_commit_len, commitment_out33,
1257 proof_out, proof_len, 1, NULL, resources);
1258}
1259
1261 const purify_bulletproof_circuit_view* circuit,
1262 const purify_bulletproof_assignment_view* assignment,
1263 const unsigned char* blind32,
1264 const unsigned char value_gen33[33],
1265 const unsigned char nonce32[32],
1266 const unsigned char* extra_commit,
1267 size_t extra_commit_len,
1268 unsigned char commitment_out33[33],
1269 unsigned char* proof_out,
1270 size_t* proof_len) {
1271 return purify_bulletproof_prove_circuit_impl(circuit, assignment, blind32, value_gen33, nonce32,
1272 extra_commit, extra_commit_len, commitment_out33,
1273 proof_out, proof_len, 0, context, NULL);
1274}
1275
1277 const purify_bulletproof_circuit_view* circuit,
1278 const purify_bulletproof_assignment_view* assignment,
1279 const unsigned char* blind32,
1280 const unsigned char value_gen33[33],
1281 const unsigned char nonce32[32],
1282 const unsigned char* extra_commit,
1283 size_t extra_commit_len,
1284 unsigned char commitment_out33[33],
1285 unsigned char* proof_out,
1286 size_t* proof_len) {
1287 return purify_bulletproof_prove_circuit_impl(circuit, assignment, blind32, value_gen33, nonce32,
1288 extra_commit, extra_commit_len, commitment_out33,
1289 proof_out, proof_len, 0, NULL, resources);
1290}
1291
1294 const purify_bulletproof_circuit_view* circuit,
1295 const unsigned char commitment33[33],
1296 const unsigned char value_gen33[33],
1297 const unsigned char* extra_commit,
1298 size_t extra_commit_len,
1299 const unsigned char* proof,
1300 size_t proof_len);
1301
1303 const purify_bulletproof_circuit_view* circuit,
1304 const unsigned char commitment33[33],
1305 const unsigned char value_gen33[33],
1306 const unsigned char* extra_commit,
1307 size_t extra_commit_len,
1308 const unsigned char* proof,
1309 size_t proof_len) {
1310 return purify_bulletproof_verify_circuit_impl(context, NULL, circuit, commitment33, value_gen33,
1311 extra_commit, extra_commit_len, proof, proof_len);
1312}
1313
1316 const purify_bulletproof_circuit_view* circuit,
1317 const unsigned char commitment33[33],
1318 const unsigned char value_gen33[33],
1319 const unsigned char* extra_commit,
1320 size_t extra_commit_len,
1321 const unsigned char* proof,
1322 size_t proof_len) {
1323 secp256k1_context* ctx = NULL;
1324 secp256k1_scratch_space* scratch = NULL;
1327 secp256k1_ge value_gen;
1328 secp256k1_ge commit_points[1];
1329 const secp256k1_ge* commit_ptr = NULL;
1330 const secp256k1_bulletproof_circuit* circuit_ptr = NULL;
1331 const unsigned char* proof_ptr = NULL;
1332 const unsigned char* extra_commit_ptr = NULL;
1333 size_t n_commits = 0;
1334 size_t required_generators = 0;
1335 int ok = 0;
1336 int owns_resources = 0;
1337
1338 memset(&bp_circuit, 0, sizeof(bp_circuit));
1339 memset(commit_points, 0, sizeof(commit_points));
1340 if (circuit == NULL || value_gen33 == NULL || proof == NULL) {
1341 return 0;
1342 }
1343 if (extra_commit == NULL && extra_commit_len != 0) {
1344 return 0;
1345 }
1346 if (!purify_build_bulletproof_circuit(circuit, &bp_circuit)) {
1347 goto done;
1348 }
1349 if (resources == NULL) {
1350 resources = purify_bulletproof_backend_resources_create(context, bp_circuit.n_gates);
1351 if (resources == NULL) {
1352 goto done;
1353 }
1354 owns_resources = 1;
1355 }
1356 if (resources->n_gates < bp_circuit.n_gates || resources->ctx == NULL || resources->scratch == NULL || resources->gens == NULL) {
1357 goto done;
1358 }
1359 ctx = resources->ctx;
1360 scratch = resources->scratch;
1361 gens = resources->gens;
1362 if (!purify_bridge_checked_mul_size(2u, bp_circuit.n_gates, &required_generators) ||
1363 gens->n < required_generators) {
1364 goto done;
1365 }
1366 if (!purify_parse_generator_as_ge(ctx, value_gen33, &value_gen)) {
1367 goto done;
1368 }
1369
1370 n_commits = bp_circuit.n_commits;
1371 if (n_commits == 1) {
1372 if (commitment33 == NULL || !purify_parse_point_as_ge(commitment33, &commit_points[0])) {
1373 goto done;
1374 }
1375 commit_ptr = commit_points;
1376 } else if (n_commits > 1) {
1377 goto done;
1378 }
1379
1380 circuit_ptr = &bp_circuit;
1381 proof_ptr = proof;
1382 extra_commit_ptr = extra_commit;
1384 &ctx->error_callback,
1385 scratch,
1386 &proof_ptr,
1387 1,
1388 proof_len,
1389 n_commits == 0 ? NULL : &commit_ptr,
1390 n_commits == 0 ? NULL : &n_commits,
1391 &value_gen,
1392 &circuit_ptr,
1393 gens,
1394 &extra_commit_ptr,
1395 &extra_commit_len
1396 );
1397
1398done:
1400 if (owns_resources) {
1402 }
1403 return ok;
1404}
1405
1407 const purify_bulletproof_circuit_view* circuit,
1408 const unsigned char commitment33[33],
1409 const unsigned char value_gen33[33],
1410 const unsigned char* extra_commit,
1411 size_t extra_commit_len,
1412 const unsigned char* proof,
1413 size_t proof_len) {
1414 return purify_bulletproof_verify_circuit_impl(NULL, resources, circuit, commitment33, value_gen33,
1415 extra_commit, extra_commit_len, proof, proof_len);
1416}
1417
1418static void purify_norm_arg_commit_initial_data(secp256k1_sha256* transcript, const secp256k1_scalar* rho,
1419 const secp256k1_bppp_generators* gens_vec, size_t g_len,
1420 const secp256k1_scalar* c_vec, size_t c_vec_len,
1421 const secp256k1_ge* commit) {
1422 unsigned char ser_commit[33], ser_scalar[32], ser_le64[8];
1423 size_t i;
1424 secp256k1_ge comm = *commit;
1425
1426 secp256k1_bppp_sha256_tagged_commitment_init(transcript);
1427 purify_serialize_point(ser_commit, &comm);
1428 secp256k1_sha256_write(transcript, ser_commit, sizeof(ser_commit));
1429 secp256k1_scalar_get_b32(ser_scalar, rho);
1430 secp256k1_sha256_write(transcript, ser_scalar, sizeof(ser_scalar));
1431 secp256k1_bppp_le64(ser_le64, g_len);
1432 secp256k1_sha256_write(transcript, ser_le64, sizeof(ser_le64));
1433 secp256k1_bppp_le64(ser_le64, gens_vec->n);
1434 secp256k1_sha256_write(transcript, ser_le64, sizeof(ser_le64));
1435 for (i = 0; i < gens_vec->n; ++i) {
1436 secp256k1_ge gen = gens_vec->gens[i];
1437 purify_serialize_point(ser_commit, &gen);
1438 secp256k1_sha256_write(transcript, ser_commit, sizeof(ser_commit));
1439 }
1440 secp256k1_bppp_le64(ser_le64, c_vec_len);
1441 secp256k1_sha256_write(transcript, ser_le64, sizeof(ser_le64));
1442 for (i = 0; i < c_vec_len; ++i) {
1443 secp256k1_scalar_get_b32(ser_scalar, &c_vec[i]);
1444 secp256k1_sha256_write(transcript, ser_scalar, sizeof(ser_scalar));
1445 }
1446}
1447
1448static int purify_copy_vectors_into_scratch(const secp256k1_context* ctx, secp256k1_scratch_space* scratch,
1449 secp256k1_scalar** ns, secp256k1_scalar** ls, secp256k1_scalar** cs,
1450 secp256k1_ge** gs, const secp256k1_scalar* n_vec,
1451 const secp256k1_scalar* l_vec, const secp256k1_scalar* c_vec,
1452 const secp256k1_ge* gens_vec, size_t g_len, size_t h_len) {
1453 size_t scalar_g_bytes = 0;
1454 size_t scalar_h_bytes = 0;
1455 size_t ge_count = 0;
1456 size_t ge_bytes = 0;
1457
1458 if (!purify_bridge_checked_mul_size(g_len, sizeof(secp256k1_scalar), &scalar_g_bytes) ||
1459 !purify_bridge_checked_mul_size(h_len, sizeof(secp256k1_scalar), &scalar_h_bytes) ||
1460 !purify_bridge_checked_add_size(g_len, h_len, &ge_count) ||
1461 !purify_bridge_checked_mul_size(ge_count, sizeof(secp256k1_ge), &ge_bytes)) {
1462 return 0;
1463 }
1464
1465 *ns = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, scalar_g_bytes);
1466 *ls = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, scalar_h_bytes);
1467 *cs = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, scalar_h_bytes);
1468 *gs = (secp256k1_ge*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, ge_bytes);
1469 if (*ns == NULL || *ls == NULL || *cs == NULL || *gs == NULL) {
1470 return 0;
1471 }
1472 memcpy(*ns, n_vec, scalar_g_bytes);
1473 memcpy(*ls, l_vec, scalar_h_bytes);
1474 memcpy(*cs, c_vec, scalar_h_bytes);
1475 memcpy(*gs, gens_vec, ge_bytes);
1476 return 1;
1477}
1478
1479static int purify_bppp_rangeproof_norm_product_prove_const(const secp256k1_context* ctx, secp256k1_scratch_space* scratch,
1480 unsigned char* proof, size_t* proof_len,
1481 secp256k1_sha256* transcript, const secp256k1_scalar* rho,
1482 const secp256k1_ge* g_vec, size_t g_vec_len,
1483 const secp256k1_scalar* n_vec, size_t n_vec_len,
1484 const secp256k1_scalar* l_vec, size_t l_vec_len,
1485 const secp256k1_scalar* c_vec, size_t c_vec_len) {
1486 secp256k1_scalar *ns = NULL, *ls = NULL, *cs = NULL;
1487 secp256k1_ge *gs = NULL;
1488 size_t checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
1489 int result = 0;
1490
1491 if (purify_copy_vectors_into_scratch(ctx, scratch, &ns, &ls, &cs, &gs, n_vec, l_vec, c_vec, g_vec, n_vec_len, l_vec_len)) {
1492 result = secp256k1_bppp_rangeproof_norm_product_prove(ctx, scratch, proof, proof_len, transcript, rho,
1493 gs, g_vec_len, ns, n_vec_len, ls, l_vec_len, cs, c_vec_len);
1494 }
1495 secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, checkpoint);
1496 return result;
1497}
1498
1499size_t purify_bppp_required_proof_size(size_t n_vec_len, size_t c_vec_len) {
1500 size_t log_g_len, log_h_len, max_log_len, proof_size = 0;
1501 if (n_vec_len == 0 || c_vec_len == 0) {
1502 return 0;
1503 }
1504 log_g_len = secp256k1_bppp_log2(n_vec_len);
1505 log_h_len = secp256k1_bppp_log2(c_vec_len);
1506 max_log_len = log_g_len > log_h_len ? log_g_len : log_h_len;
1507 if (!purify_bridge_checked_mul_size(65u, max_log_len, &proof_size) ||
1508 !purify_bridge_checked_add_size(proof_size, 64u, &proof_size)) {
1509 return 0;
1510 }
1511 return proof_size;
1512}
1513
1514int purify_bppp_base_generator(purify_secp_context* context, unsigned char out33[33]) {
1515 secp256k1_context* ctx = purify_context_handle(context);
1516 secp256k1_generator generator;
1517 secp256k1_ge ge = secp256k1_ge_const_g;
1518 int ok;
1519
1520 if (ctx == NULL || out33 == NULL) {
1521 return 0;
1522 }
1523 secp256k1_generator_save(&generator, &ge);
1524 ok = secp256k1_generator_serialize(ctx, out33, &generator);
1525 return ok;
1526}
1527
1528int purify_bppp_value_generator_h(purify_secp_context* context, unsigned char out33[33]) {
1529 secp256k1_context* ctx = purify_context_handle(context);
1530 int ok;
1531
1532 if (ctx == NULL || out33 == NULL) {
1533 return 0;
1534 }
1535 ok = secp256k1_generator_serialize(ctx, out33, secp256k1_generator_h);
1536 return ok;
1537}
1538
1539int purify_bppp_create_generators(purify_secp_context* context, size_t count, unsigned char* out, size_t* out_len) {
1540 secp256k1_context* ctx = purify_context_handle(context);
1541 secp256k1_bppp_generators* gens = NULL;
1542 size_t required = 0;
1543 int ok = 0;
1544
1545 if (ctx == NULL || out_len == NULL) {
1546 return 0;
1547 }
1548 if (!purify_bridge_checked_mul_size(count, 33u, &required)) {
1549 *out_len = 0;
1550 return 0;
1551 }
1552 if (*out_len < required || out == NULL) {
1553 *out_len = required;
1554 return 0;
1555 }
1556 gens = secp256k1_bppp_generators_create(ctx, count);
1557 if (gens == NULL) {
1558 return 0;
1559 }
1560 ok = secp256k1_bppp_generators_serialize(ctx, gens, out, out_len);
1561 secp256k1_bppp_generators_destroy(ctx, gens);
1562 return ok;
1563}
1564
1566 const unsigned char blind32[32], const unsigned char value32[32],
1567 const unsigned char value_gen33[33], const unsigned char blind_gen33[33],
1568 unsigned char commitment_out33[33]) {
1569 secp256k1_context* ctx = purify_context_handle(context);
1570 secp256k1_scalar blind_scalar, value_scalar;
1571 secp256k1_generator value_generator, blind_generator;
1572 secp256k1_ge value_ge, blind_ge, commit_ge;
1573 secp256k1_gej blind_part, value_part, total;
1574 int ok = 0;
1575
1576 if (ctx == NULL || blind32 == NULL || value32 == NULL || value_gen33 == NULL || blind_gen33 == NULL || commitment_out33 == NULL) {
1577 return 0;
1578 }
1579 if (!purify_parse_scalar(blind32, &blind_scalar, 0) || !purify_parse_scalar(value32, &value_scalar, 0)) {
1580 return 0;
1581 }
1582 if (!secp256k1_generator_parse(ctx, &value_generator, value_gen33) || !secp256k1_generator_parse(ctx, &blind_generator, blind_gen33)) {
1583 return 0;
1584 }
1585 secp256k1_generator_load(&value_ge, &value_generator);
1586 secp256k1_generator_load(&blind_ge, &blind_generator);
1587 secp256k1_ecmult_const(&blind_part, &blind_ge, &blind_scalar);
1588 secp256k1_ecmult_const(&value_part, &value_ge, &value_scalar);
1589 secp256k1_gej_add_var(&total, &blind_part, &value_part, NULL);
1590 if (!secp256k1_gej_is_infinity(&total)) {
1591 secp256k1_ge_set_gej(&commit_ge, &total);
1592 ok = purify_serialize_point(commitment_out33, &commit_ge);
1593 }
1594 return ok;
1595}
1596
1599 const unsigned char rho32[32], const unsigned char* generators33,
1600 size_t generators_count, const unsigned char* n_vec32, size_t n_vec_len,
1601 const unsigned char* l_vec32, size_t l_vec_len,
1602 const unsigned char* c_vec32, size_t c_vec_len,
1603 unsigned char commitment_out33[33]) {
1604 secp256k1_context* ctx = resources != NULL ? resources->ctx : purify_context_handle(context);
1605 secp256k1_scratch_space* scratch = resources != NULL ? resources->scratch : NULL;
1606 secp256k1_bppp_generators* gens = resources != NULL ? resources->gens : NULL;
1607 secp256k1_scalar rho, mu;
1608 secp256k1_scalar *n_vec = NULL, *l_vec = NULL, *c_vec = NULL;
1609 secp256k1_ge commit;
1610 size_t expected_generators = 0;
1611 size_t serialized_generators_len = 0;
1612 int ok = 0;
1613
1614 if (ctx == NULL || rho32 == NULL || (resources == NULL && generators33 == NULL) || n_vec32 == NULL || l_vec32 == NULL || c_vec32 == NULL ||
1615 commitment_out33 == NULL) {
1616 return 0;
1617 }
1618 if (n_vec_len == 0 || l_vec_len == 0 || c_vec_len == 0 || l_vec_len != c_vec_len) {
1619 return 0;
1620 }
1621 if (!secp256k1_is_power_of_two(n_vec_len) || !secp256k1_is_power_of_two(c_vec_len) ||
1622 !purify_bridge_checked_add_size(n_vec_len, l_vec_len, &expected_generators) ||
1623 generators_count != expected_generators ||
1624 !purify_bridge_checked_mul_size(generators_count, 33u, &serialized_generators_len)) {
1625 return 0;
1626 }
1627 if (resources != NULL && resources->generators_count != generators_count) {
1628 return 0;
1629 }
1630 if (!purify_parse_scalar(rho32, &rho, 1)) {
1631 return 0;
1632 }
1633 if (resources == NULL) {
1634 scratch = secp256k1_scratch_space_create(ctx, 1u << 24);
1635 gens = secp256k1_bppp_generators_parse(ctx, generators33, serialized_generators_len);
1636 }
1637 n_vec = (secp256k1_scalar*)purify_malloc_array(n_vec_len, sizeof(*n_vec));
1638 l_vec = (secp256k1_scalar*)purify_malloc_array(l_vec_len, sizeof(*l_vec));
1639 c_vec = (secp256k1_scalar*)purify_malloc_array(c_vec_len, sizeof(*c_vec));
1640 if (scratch == NULL || gens == NULL || n_vec == NULL || l_vec == NULL || c_vec == NULL) {
1641 goto cleanup;
1642 }
1643 if (!purify_parse_scalar_array(n_vec32, n_vec_len, n_vec) ||
1644 !purify_parse_scalar_array(l_vec32, l_vec_len, l_vec) ||
1645 !purify_parse_scalar_array(c_vec32, c_vec_len, c_vec)) {
1646 goto cleanup;
1647 }
1648 secp256k1_scalar_sqr(&mu, &rho);
1649 if (!secp256k1_bppp_commit(ctx, scratch, &commit, gens, n_vec, n_vec_len, l_vec, l_vec_len, c_vec, c_vec_len, &mu)) {
1650 goto cleanup;
1651 }
1652 ok = purify_serialize_point(commitment_out33, &commit);
1653
1654cleanup:
1655 if (n_vec != NULL) free(n_vec);
1656 if (l_vec != NULL) free(l_vec);
1657 if (c_vec != NULL) free(c_vec);
1658 if (resources == NULL) {
1659 if (gens != NULL) secp256k1_bppp_generators_destroy(ctx, gens);
1660 if (scratch != NULL) secp256k1_scratch_space_destroy(ctx, scratch);
1661 }
1662 return ok;
1663}
1664
1666 const unsigned char rho32[32], const unsigned char* generators33, size_t generators_count,
1667 const unsigned char* n_vec32, size_t n_vec_len, const unsigned char* l_vec32,
1668 size_t l_vec_len, const unsigned char* c_vec32, size_t c_vec_len,
1669 unsigned char commitment_out33[33]) {
1670 return purify_bppp_commit_norm_arg_impl(context, NULL, rho32, generators33, generators_count, n_vec32, n_vec_len,
1671 l_vec32, l_vec_len, c_vec32, c_vec_len, commitment_out33);
1672}
1673
1675 const unsigned char rho32[32],
1676 const unsigned char* n_vec32, size_t n_vec_len,
1677 const unsigned char* l_vec32, size_t l_vec_len,
1678 const unsigned char* c_vec32, size_t c_vec_len,
1679 unsigned char commitment_out33[33]) {
1680 return purify_bppp_commit_norm_arg_impl(NULL, resources, rho32, NULL,
1681 resources != NULL ? resources->generators_count : 0,
1682 n_vec32, n_vec_len, l_vec32, l_vec_len, c_vec32, c_vec_len,
1683 commitment_out33);
1684}
1685
1688 const unsigned char* generators33, size_t generators_count,
1689 const unsigned char* n_vec32, size_t n_vec_len,
1690 const unsigned char* l_vec32, size_t l_vec_len,
1691 unsigned char commitment_out33[33]) {
1692 secp256k1_context* ctx = resources != NULL ? resources->ctx : purify_context_handle(context);
1693 secp256k1_scratch_space* scratch = resources != NULL ? resources->scratch : NULL;
1694 secp256k1_bppp_generators* gens = resources != NULL ? resources->gens : NULL;
1695 secp256k1_scalar zero;
1696 secp256k1_scalar *n_vec = NULL, *l_vec = NULL;
1697 secp256k1_ge commit;
1698 secp256k1_gej commitj;
1699 ecmult_bp_commit_cb_data data;
1700 size_t expected_generators = 0;
1701 size_t serialized_generators_len = 0;
1702 int ok = 0;
1703
1704 if (ctx == NULL || (resources == NULL && generators33 == NULL) || n_vec32 == NULL || l_vec32 == NULL || commitment_out33 == NULL) {
1705 return 0;
1706 }
1707 if (n_vec_len == 0 || l_vec_len == 0 ||
1708 !purify_bridge_checked_add_size(n_vec_len, l_vec_len, &expected_generators) ||
1709 generators_count != expected_generators ||
1710 !purify_bridge_checked_mul_size(generators_count, 33u, &serialized_generators_len)) {
1711 return 0;
1712 }
1713 if (resources != NULL && resources->generators_count != generators_count) {
1714 return 0;
1715 }
1716
1717 if (resources == NULL) {
1718 scratch = secp256k1_scratch_space_create(ctx, 1u << 24);
1719 gens = secp256k1_bppp_generators_parse(ctx, generators33, serialized_generators_len);
1720 }
1721 n_vec = (secp256k1_scalar*)purify_malloc_array(n_vec_len, sizeof(*n_vec));
1722 l_vec = (secp256k1_scalar*)purify_malloc_array(l_vec_len, sizeof(*l_vec));
1723 if (scratch == NULL || gens == NULL || n_vec == NULL || l_vec == NULL) {
1724 goto cleanup;
1725 }
1726 if (!purify_parse_scalar_array(n_vec32, n_vec_len, n_vec) ||
1727 !purify_parse_scalar_array(l_vec32, l_vec_len, l_vec)) {
1728 goto cleanup;
1729 }
1730
1731 secp256k1_scalar_set_int(&zero, 0);
1732 data.g = gens->gens;
1733 data.n = n_vec;
1734 data.l = l_vec;
1735 data.g_len = n_vec_len;
1736 if (!secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &commitj, &zero, ecmult_bp_commit_cb,
1737 (void*)&data, expected_generators)) {
1738 goto cleanup;
1739 }
1740 if (secp256k1_gej_is_infinity(&commitj)) {
1741 goto cleanup;
1742 }
1743 secp256k1_ge_set_gej_var(&commit, &commitj);
1744 ok = purify_serialize_point(commitment_out33, &commit);
1745
1746cleanup:
1747 if (n_vec != NULL) free(n_vec);
1748 if (l_vec != NULL) free(l_vec);
1749 if (resources == NULL) {
1750 if (gens != NULL) secp256k1_bppp_generators_destroy(ctx, gens);
1751 if (scratch != NULL) secp256k1_scratch_space_destroy(ctx, scratch);
1752 }
1753 return ok;
1754}
1755
1757 const unsigned char* generators33, size_t generators_count,
1758 const unsigned char* n_vec32, size_t n_vec_len, const unsigned char* l_vec32,
1759 size_t l_vec_len, unsigned char commitment_out33[33]) {
1760 return purify_bppp_commit_witness_only_impl(context, NULL, generators33, generators_count,
1761 n_vec32, n_vec_len, l_vec32, l_vec_len, commitment_out33);
1762}
1763
1765 const unsigned char* n_vec32, size_t n_vec_len,
1766 const unsigned char* l_vec32, size_t l_vec_len,
1767 unsigned char commitment_out33[33]) {
1768 return purify_bppp_commit_witness_only_impl(NULL, resources, NULL,
1769 resources != NULL ? resources->generators_count : 0,
1770 n_vec32, n_vec_len, l_vec32, l_vec_len, commitment_out33);
1771}
1772
1774 const unsigned char commitment33[33], const unsigned char scalar32[32],
1775 unsigned char commitment_out33[33]) {
1776 secp256k1_context* ctx = purify_context_handle(context);
1777 secp256k1_scalar scalar;
1778 secp256k1_ge commitment_ge, result_ge;
1779 secp256k1_gej commitment_j, offset_j, result_j;
1780 int ok = 0;
1781
1782 if (ctx == NULL || commitment33 == NULL || scalar32 == NULL || commitment_out33 == NULL) {
1783 return 0;
1784 }
1785 if (!purify_parse_point_as_ge(commitment33, &commitment_ge) ||
1786 !purify_parse_scalar(scalar32, &scalar, 0)) {
1787 return 0;
1788 }
1789
1790 secp256k1_gej_set_ge(&commitment_j, &commitment_ge);
1791 secp256k1_ecmult_const(&offset_j, &secp256k1_ge_const_g, &scalar);
1792 secp256k1_gej_add_var(&result_j, &commitment_j, &offset_j, NULL);
1793 if (!secp256k1_gej_is_infinity(&result_j)) {
1794 secp256k1_ge_set_gej(&result_ge, &result_j);
1795 ok = purify_serialize_point(commitment_out33, &result_ge);
1796 }
1797 return ok;
1798}
1799
1801 const unsigned char point33[33], const unsigned char scalar32[32],
1802 unsigned char out33[33]) {
1803 secp256k1_context* ctx = purify_context_handle(context);
1804 secp256k1_scalar scalar;
1805 secp256k1_ge point_ge, result_ge;
1806 secp256k1_gej result_j;
1807 int ok = 0;
1808
1809 if (ctx == NULL || point33 == NULL || scalar32 == NULL || out33 == NULL) {
1810 return 0;
1811 }
1812 if (!purify_parse_point_as_ge(point33, &point_ge) ||
1813 !purify_parse_scalar(scalar32, &scalar, 0)) {
1814 return 0;
1815 }
1816
1817 secp256k1_ecmult_const(&result_j, &point_ge, &scalar);
1818 if (!secp256k1_gej_is_infinity(&result_j)) {
1819 secp256k1_ge_set_gej(&result_ge, &result_j);
1820 ok = purify_serialize_point(out33, &result_ge);
1821 }
1822 return ok;
1823}
1824
1826 const unsigned char lhs33[33], const unsigned char rhs33[33],
1827 unsigned char out33[33]) {
1828 secp256k1_context* ctx = purify_context_handle(context);
1829 secp256k1_ge lhs_ge, rhs_ge, result_ge;
1830 secp256k1_gej lhs_j, result_j;
1831 int ok = 0;
1832
1833 if (ctx == NULL || lhs33 == NULL || rhs33 == NULL || out33 == NULL) {
1834 return 0;
1835 }
1836 if (!purify_parse_point_as_ge(lhs33, &lhs_ge) ||
1837 !purify_parse_point_as_ge(rhs33, &rhs_ge)) {
1838 return 0;
1839 }
1840
1841 secp256k1_gej_set_ge(&lhs_j, &lhs_ge);
1842 secp256k1_gej_add_ge_var(&result_j, &lhs_j, &rhs_ge, NULL);
1843 if (!secp256k1_gej_is_infinity(&result_j)) {
1844 secp256k1_ge_set_gej(&result_ge, &result_j);
1845 ok = purify_serialize_point(out33, &result_ge);
1846 }
1847 return ok;
1848}
1849
1852 const unsigned char rho32[32], const unsigned char* generators33,
1853 size_t generators_count, const unsigned char* n_vec32, size_t n_vec_len,
1854 const unsigned char* l_vec32, size_t l_vec_len,
1855 const unsigned char* c_vec32, size_t c_vec_len,
1856 unsigned char commitment_out33[33], unsigned char* proof_out,
1857 size_t* proof_len) {
1858 secp256k1_context* ctx = resources != NULL ? resources->ctx : purify_context_handle(context);
1859 secp256k1_scratch_space* scratch = resources != NULL ? resources->scratch : NULL;
1860 secp256k1_bppp_generators* gens = NULL;
1861 secp256k1_scalar rho, mu;
1862 secp256k1_scalar *n_vec = NULL, *l_vec = NULL, *c_vec = NULL;
1863 secp256k1_ge commit;
1864 secp256k1_sha256 transcript;
1865 size_t required = purify_bppp_required_proof_size(n_vec_len, c_vec_len);
1866 size_t expected_generators = 0;
1867 size_t serialized_generators_len = 0;
1868 int ok = 0;
1869 purify_bppp_mutable_generators_guard gens_guard = {0};
1870
1871 if (ctx == NULL || rho32 == NULL || (resources == NULL && generators33 == NULL) || n_vec32 == NULL || l_vec32 == NULL || c_vec32 == NULL ||
1872 commitment_out33 == NULL || proof_out == NULL || proof_len == NULL) {
1873 return 0;
1874 }
1875 if (n_vec_len == 0 || l_vec_len == 0 || c_vec_len == 0 || l_vec_len != c_vec_len) {
1876 return 0;
1877 }
1878 if (!secp256k1_is_power_of_two(n_vec_len) || !secp256k1_is_power_of_two(c_vec_len) ||
1879 !purify_bridge_checked_add_size(n_vec_len, l_vec_len, &expected_generators) ||
1880 generators_count != expected_generators ||
1881 !purify_bridge_checked_mul_size(generators_count, 33u, &serialized_generators_len)) {
1882 return 0;
1883 }
1884 if (resources != NULL && resources->generators_count != generators_count) {
1885 return 0;
1886 }
1887 if (*proof_len < required) {
1888 *proof_len = required;
1889 return 0;
1890 }
1891 if (!purify_parse_scalar(rho32, &rho, 1)) {
1892 return 0;
1893 }
1894 if (resources != NULL) {
1895 gens = purify_bppp_backend_resources_acquire_scratch_gens(resources, &gens_guard);
1896 if (gens == NULL) {
1897 return 0;
1898 }
1899 } else {
1900 scratch = secp256k1_scratch_space_create(ctx, 1u << 24);
1901 gens = secp256k1_bppp_generators_parse(ctx, generators33, serialized_generators_len);
1902 }
1903 n_vec = (secp256k1_scalar*)purify_malloc_array(n_vec_len, sizeof(*n_vec));
1904 l_vec = (secp256k1_scalar*)purify_malloc_array(l_vec_len, sizeof(*l_vec));
1905 c_vec = (secp256k1_scalar*)purify_malloc_array(c_vec_len, sizeof(*c_vec));
1906 if (scratch == NULL || gens == NULL || n_vec == NULL || l_vec == NULL || c_vec == NULL) {
1907 goto cleanup;
1908 }
1909 if (!purify_parse_scalar_array(n_vec32, n_vec_len, n_vec) ||
1910 !purify_parse_scalar_array(l_vec32, l_vec_len, l_vec) ||
1911 !purify_parse_scalar_array(c_vec32, c_vec_len, c_vec)) {
1912 goto cleanup;
1913 }
1914 secp256k1_scalar_sqr(&mu, &rho);
1915 if (!secp256k1_bppp_commit(ctx, scratch, &commit, gens, n_vec, n_vec_len, l_vec, l_vec_len, c_vec, c_vec_len, &mu)) {
1916 goto cleanup;
1917 }
1918 if (!purify_serialize_point(commitment_out33, &commit)) {
1919 goto cleanup;
1920 }
1921 purify_norm_arg_commit_initial_data(&transcript, &rho, gens, n_vec_len, c_vec, c_vec_len, &commit);
1922 ok = purify_bppp_rangeproof_norm_product_prove_const(ctx, scratch, proof_out, proof_len, &transcript, &rho,
1923 gens->gens, gens->n, n_vec, n_vec_len, l_vec, l_vec_len, c_vec, c_vec_len);
1924
1925cleanup:
1926 if (n_vec != NULL) free(n_vec);
1927 if (l_vec != NULL) free(l_vec);
1928 if (c_vec != NULL) free(c_vec);
1930 if (resources == NULL) {
1931 if (gens != NULL) secp256k1_bppp_generators_destroy(ctx, gens);
1932 if (scratch != NULL) secp256k1_scratch_space_destroy(ctx, scratch);
1933 }
1934 return ok;
1935}
1936
1938 const unsigned char rho32[32], const unsigned char* generators33, size_t generators_count,
1939 const unsigned char* n_vec32, size_t n_vec_len, const unsigned char* l_vec32,
1940 size_t l_vec_len, const unsigned char* c_vec32, size_t c_vec_len,
1941 unsigned char commitment_out33[33], unsigned char* proof_out, size_t* proof_len) {
1942 return purify_bppp_prove_norm_arg_impl(context, NULL, rho32, generators33, generators_count, n_vec32, n_vec_len,
1943 l_vec32, l_vec_len, c_vec32, c_vec_len, commitment_out33,
1944 proof_out, proof_len);
1945}
1946
1948 const unsigned char rho32[32],
1949 const unsigned char* n_vec32, size_t n_vec_len,
1950 const unsigned char* l_vec32, size_t l_vec_len,
1951 const unsigned char* c_vec32, size_t c_vec_len,
1952 unsigned char commitment_out33[33], unsigned char* proof_out,
1953 size_t* proof_len) {
1954 return purify_bppp_prove_norm_arg_impl(NULL, resources, rho32, NULL,
1955 resources != NULL ? resources->generators_count : 0,
1956 n_vec32, n_vec_len, l_vec32, l_vec_len, c_vec32, c_vec_len,
1957 commitment_out33, proof_out, proof_len);
1958}
1959
1962 const unsigned char rho32[32], const unsigned char* generators33,
1963 size_t generators_count, const unsigned char* n_vec32,
1964 size_t n_vec_len, const unsigned char* l_vec32,
1965 size_t l_vec_len, const unsigned char* c_vec32,
1966 size_t c_vec_len, const unsigned char commitment33[33],
1967 unsigned char* proof_out, size_t* proof_len) {
1968 secp256k1_context* ctx = resources != NULL ? resources->ctx : purify_context_handle(context);
1969 secp256k1_scratch_space* scratch = resources != NULL ? resources->scratch : NULL;
1970 secp256k1_bppp_generators* gens = NULL;
1971 secp256k1_scalar rho, mu;
1972 secp256k1_scalar *n_vec = NULL, *l_vec = NULL, *c_vec = NULL;
1973 secp256k1_ge expected_commit, commitment_ge;
1974 secp256k1_sha256 transcript;
1975 unsigned char expected_commitment33[33];
1976 size_t required = purify_bppp_required_proof_size(n_vec_len, c_vec_len);
1977 size_t expected_generators = 0;
1978 size_t serialized_generators_len = 0;
1979 int ok = 0;
1980 purify_bppp_mutable_generators_guard gens_guard = {0};
1981
1982 memset(expected_commitment33, 0, sizeof(expected_commitment33));
1983 if (ctx == NULL || rho32 == NULL || (resources == NULL && generators33 == NULL) || n_vec32 == NULL || l_vec32 == NULL || c_vec32 == NULL ||
1984 commitment33 == NULL || proof_out == NULL || proof_len == NULL) {
1985 return 0;
1986 }
1987 if (n_vec_len == 0 || l_vec_len == 0 || c_vec_len == 0 || l_vec_len != c_vec_len) {
1988 return 0;
1989 }
1990 if (!secp256k1_is_power_of_two(n_vec_len) || !secp256k1_is_power_of_two(c_vec_len) ||
1991 !purify_bridge_checked_add_size(n_vec_len, l_vec_len, &expected_generators) ||
1992 generators_count != expected_generators ||
1993 !purify_bridge_checked_mul_size(generators_count, 33u, &serialized_generators_len)) {
1994 return 0;
1995 }
1996 if (resources != NULL && resources->generators_count != generators_count) {
1997 return 0;
1998 }
1999 if (*proof_len < required) {
2000 *proof_len = required;
2001 return 0;
2002 }
2003 if (!purify_parse_scalar(rho32, &rho, 1) || !purify_parse_point_as_ge(commitment33, &commitment_ge)) {
2004 return 0;
2005 }
2006 if (resources != NULL) {
2007 gens = purify_bppp_backend_resources_acquire_scratch_gens(resources, &gens_guard);
2008 if (gens == NULL) {
2009 return 0;
2010 }
2011 } else {
2012 scratch = secp256k1_scratch_space_create(ctx, 1u << 24);
2013 gens = secp256k1_bppp_generators_parse(ctx, generators33, serialized_generators_len);
2014 }
2015 n_vec = (secp256k1_scalar*)purify_malloc_array(n_vec_len, sizeof(*n_vec));
2016 l_vec = (secp256k1_scalar*)purify_malloc_array(l_vec_len, sizeof(*l_vec));
2017 c_vec = (secp256k1_scalar*)purify_malloc_array(c_vec_len, sizeof(*c_vec));
2018 if (scratch == NULL || gens == NULL || n_vec == NULL || l_vec == NULL || c_vec == NULL) {
2019 goto cleanup;
2020 }
2021 if (!purify_parse_scalar_array(n_vec32, n_vec_len, n_vec) ||
2022 !purify_parse_scalar_array(l_vec32, l_vec_len, l_vec) ||
2023 !purify_parse_scalar_array(c_vec32, c_vec_len, c_vec)) {
2024 goto cleanup;
2025 }
2026 secp256k1_scalar_sqr(&mu, &rho);
2027 if (!secp256k1_bppp_commit(ctx, scratch, &expected_commit, gens, n_vec, n_vec_len, l_vec, l_vec_len, c_vec, c_vec_len, &mu)) {
2028 goto cleanup;
2029 }
2030 if (!purify_serialize_point(expected_commitment33, &expected_commit)) {
2031 goto cleanup;
2032 }
2033 if (secp256k1_memcmp_var(expected_commitment33, commitment33, sizeof(expected_commitment33)) != 0) {
2034 goto cleanup;
2035 }
2036 purify_norm_arg_commit_initial_data(&transcript, &rho, gens, n_vec_len, c_vec, c_vec_len, &commitment_ge);
2037 ok = purify_bppp_rangeproof_norm_product_prove_const(ctx, scratch, proof_out, proof_len, &transcript, &rho,
2038 gens->gens, gens->n, n_vec, n_vec_len, l_vec, l_vec_len, c_vec, c_vec_len);
2039
2040cleanup:
2041 if (n_vec != NULL) free(n_vec);
2042 if (l_vec != NULL) free(l_vec);
2043 if (c_vec != NULL) free(c_vec);
2045 if (resources == NULL) {
2046 if (gens != NULL) secp256k1_bppp_generators_destroy(ctx, gens);
2047 if (scratch != NULL) secp256k1_scratch_space_destroy(ctx, scratch);
2048 }
2049 return ok;
2050}
2051
2053 const unsigned char rho32[32], const unsigned char* generators33, size_t generators_count,
2054 const unsigned char* n_vec32, size_t n_vec_len, const unsigned char* l_vec32,
2055 size_t l_vec_len, const unsigned char* c_vec32, size_t c_vec_len,
2056 const unsigned char commitment33[33], unsigned char* proof_out, size_t* proof_len) {
2057 return purify_bppp_prove_norm_arg_to_commitment_impl(context, NULL, rho32, generators33, generators_count,
2058 n_vec32, n_vec_len, l_vec32, l_vec_len, c_vec32, c_vec_len,
2059 commitment33, proof_out, proof_len);
2060}
2061
2063 const unsigned char rho32[32],
2064 const unsigned char* n_vec32, size_t n_vec_len,
2065 const unsigned char* l_vec32, size_t l_vec_len,
2066 const unsigned char* c_vec32, size_t c_vec_len,
2067 const unsigned char commitment33[33],
2068 unsigned char* proof_out, size_t* proof_len) {
2069 return purify_bppp_prove_norm_arg_to_commitment_impl(NULL, resources, rho32, NULL,
2070 resources != NULL ? resources->generators_count : 0,
2071 n_vec32, n_vec_len, l_vec32, l_vec_len, c_vec32, c_vec_len,
2072 commitment33, proof_out, proof_len);
2073}
2074
2077 const unsigned char rho32[32], const unsigned char* generators33,
2078 size_t generators_count, const unsigned char* c_vec32, size_t c_vec_len,
2079 size_t n_vec_len, const unsigned char commitment33[33],
2080 const unsigned char* proof, size_t proof_len) {
2081 secp256k1_context* ctx = resources != NULL ? resources->ctx : purify_context_handle(context);
2082 secp256k1_scratch_space* scratch = resources != NULL ? resources->scratch : NULL;
2083 secp256k1_bppp_generators* gens = resources != NULL ? resources->gens : NULL;
2084 secp256k1_scalar rho, *c_vec = NULL;
2085 secp256k1_ge commit;
2086 secp256k1_sha256 transcript;
2087 size_t expected_generators = 0;
2088 size_t serialized_generators_len = 0;
2089 int ok = 0;
2090
2091 if (ctx == NULL || rho32 == NULL || (resources == NULL && generators33 == NULL) || c_vec32 == NULL || commitment33 == NULL || proof == NULL) {
2092 return 0;
2093 }
2094 if (n_vec_len == 0 || c_vec_len == 0 ||
2095 !purify_bridge_checked_add_size(n_vec_len, c_vec_len, &expected_generators) ||
2096 generators_count != expected_generators ||
2097 !purify_bridge_checked_mul_size(generators_count, 33u, &serialized_generators_len)) {
2098 return 0;
2099 }
2100 if (!secp256k1_is_power_of_two(n_vec_len) || !secp256k1_is_power_of_two(c_vec_len)) {
2101 return 0;
2102 }
2103 if (resources != NULL && resources->generators_count != generators_count) {
2104 return 0;
2105 }
2106 if (!purify_parse_scalar(rho32, &rho, 1) || !secp256k1_ge_parse_ext(&commit, commitment33)) {
2107 return 0;
2108 }
2109 if (resources == NULL) {
2110 scratch = secp256k1_scratch_space_create(ctx, 1u << 24);
2111 gens = secp256k1_bppp_generators_parse(ctx, generators33, serialized_generators_len);
2112 }
2113 c_vec = (secp256k1_scalar*)purify_malloc_array(c_vec_len, sizeof(*c_vec));
2114 if (scratch == NULL || gens == NULL || c_vec == NULL) {
2115 goto cleanup;
2116 }
2117 if (!purify_parse_scalar_array(c_vec32, c_vec_len, c_vec)) {
2118 goto cleanup;
2119 }
2120 purify_norm_arg_commit_initial_data(&transcript, &rho, gens, n_vec_len, c_vec, c_vec_len, &commit);
2121 ok = secp256k1_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, proof_len, &transcript, &rho,
2122 gens, n_vec_len, c_vec, c_vec_len, &commit);
2123
2124cleanup:
2125 if (c_vec != NULL) free(c_vec);
2126 if (resources == NULL) {
2127 if (gens != NULL) secp256k1_bppp_generators_destroy(ctx, gens);
2128 if (scratch != NULL) secp256k1_scratch_space_destroy(ctx, scratch);
2129 }
2130 return ok;
2131}
2132
2134 const unsigned char rho32[32], const unsigned char* generators33, size_t generators_count,
2135 const unsigned char* c_vec32, size_t c_vec_len, size_t n_vec_len,
2136 const unsigned char commitment33[33], const unsigned char* proof, size_t proof_len) {
2137 return purify_bppp_verify_norm_arg_impl(context, NULL, rho32, generators33, generators_count,
2138 c_vec32, c_vec_len, n_vec_len, commitment33, proof, proof_len);
2139}
2140
2142 const unsigned char rho32[32],
2143 const unsigned char* c_vec32, size_t c_vec_len, size_t n_vec_len,
2144 const unsigned char commitment33[33], const unsigned char* proof,
2145 size_t proof_len) {
2146 return purify_bppp_verify_norm_arg_impl(NULL, resources, rho32, NULL,
2147 resources != NULL ? resources->generators_count : 0,
2148 c_vec32, c_vec_len, n_vec_len, commitment33, proof, proof_len);
2149}
static secp256k1_scalar * purify_scalar_cast(purify_scalar *scalar)
static void purify_bulletproof_circuit_evaluate_sum_row(secp256k1_scalar *acc, const secp256k1_bulletproof_wmatrix_row *row, const secp256k1_scalar *assn)
void purify_scalar_mul(purify_scalar *out, const purify_scalar *lhs, const purify_scalar *rhs)
Multiplies two scalars modulo the backend field.
int purify_bppp_prove_norm_arg_to_commitment_with_resources(purify_bppp_backend_resources *resources, const unsigned char rho32[32], const unsigned char *n_vec32, size_t n_vec_len, const unsigned char *l_vec32, size_t l_vec_len, const unsigned char *c_vec32, size_t c_vec_len, const unsigned char commitment33[33], unsigned char *proof_out, size_t *proof_len)
static int purify_parse_scalar_array(const unsigned char *input32, size_t count, secp256k1_scalar *out)
static int purify_bppp_backend_resources_reset_scratch_gens(purify_bppp_backend_resources *resources)
static int purify_bppp_rangeproof_norm_product_prove_const(const secp256k1_context *ctx, secp256k1_scratch_space *scratch, unsigned char *proof, size_t *proof_len, secp256k1_sha256 *transcript, const secp256k1_scalar *rho, const secp256k1_ge *g_vec, size_t g_vec_len, const secp256k1_scalar *n_vec, size_t n_vec_len, const secp256k1_scalar *l_vec, size_t l_vec_len, const secp256k1_scalar *c_vec, size_t c_vec_len)
static int purify_build_row_family(secp256k1_bulletproof_wmatrix_row *out_rows, size_t row_count, const purify_bulletproof_row_view *in_rows, size_t n_constraints, secp256k1_bulletproof_wmatrix_entry *entries, size_t *offset)
int purify_bulletproof_prove_circuit(purify_secp_context *context, const purify_bulletproof_circuit_view *circuit, const purify_bulletproof_assignment_view *assignment, const unsigned char *blind32, const unsigned char value_gen33[33], const unsigned char nonce32[32], const unsigned char *extra_commit, size_t extra_commit_len, unsigned char commitment_out33[33], unsigned char *proof_out, size_t *proof_len)
static secp256k1_bppp_generators * purify_bppp_backend_resources_acquire_scratch_gens(purify_bppp_backend_resources *resources, purify_bppp_mutable_generators_guard *guard)
static int purify_parse_scalar(const unsigned char input32[32], secp256k1_scalar *scalar, int reject_zero)
static int purify_build_bulletproof_assignment(const purify_bulletproof_assignment_view *view, secp256k1_bulletproof_circuit_assignment *out)
int purify_bppp_commit_witness_only_with_resources(purify_bppp_backend_resources *resources, const unsigned char *n_vec32, size_t n_vec_len, const unsigned char *l_vec32, size_t l_vec_len, unsigned char commitment_out33[33])
int purify_bulletproof_prove_circuit_with_resources(purify_bulletproof_backend_resources *resources, const purify_bulletproof_circuit_view *circuit, const purify_bulletproof_assignment_view *assignment, const unsigned char *blind32, const unsigned char value_gen33[33], const unsigned char nonce32[32], const unsigned char *extra_commit, size_t extra_commit_len, unsigned char commitment_out33[33], unsigned char *proof_out, size_t *proof_len)
int purify_scalar_is_zero(const purify_scalar *value)
Returns nonzero when the scalar is zero.
int purify_bip340_xonly_from_point(purify_secp_context *context, const unsigned char point33[33], unsigned char xonly32[32], int *parity_out)
Converts a compressed secp256k1 point into its x-only public key encoding.
int purify_bulletproof_verify_circuit(purify_secp_context *context, const purify_bulletproof_circuit_view *circuit, const unsigned char commitment33[33], const unsigned char value_gen33[33], const unsigned char *extra_commit, size_t extra_commit_len, const unsigned char *proof, size_t proof_len)
int purify_bulletproof_prove_circuit_assume_valid(purify_secp_context *context, const purify_bulletproof_circuit_view *circuit, const purify_bulletproof_assignment_view *assignment, const unsigned char *blind32, const unsigned char value_gen33[33], const unsigned char nonce32[32], const unsigned char *extra_commit, size_t extra_commit_len, unsigned char commitment_out33[33], unsigned char *proof_out, size_t *proof_len)
int purify_bip340_key_from_seckey(purify_secp_context *context, unsigned char seckey32[32], unsigned char xonly_pubkey32[32])
Canonicalizes a valid secp256k1 secret key for BIP340 and derives its x-only public key.
int purify_scalar_add(purify_scalar *out, const purify_scalar *lhs, const purify_scalar *rhs)
Adds two scalars modulo the backend field.
int purify_bip340_nonce_from_scalar(purify_secp_context *context, unsigned char scalar32[32], unsigned char xonly_nonce32[32])
Canonicalizes a valid secp256k1 nonce scalar for BIP340 and derives its x-only public nonce.
int purify_point_scale(purify_secp_context *context, const unsigned char point33[33], const unsigned char scalar32[32], unsigned char out33[33])
void purify_scalar_set_int(purify_scalar *out, unsigned int value)
Initializes a scalar from an unsigned integer.
void purify_scalar_cmov(purify_scalar *dst, const purify_scalar *src, int flag)
Conditionally assigns src into dst when flag is nonzero.
static void purify_norm_arg_commit_initial_data(secp256k1_sha256 *transcript, const secp256k1_scalar *rho, const secp256k1_bppp_generators *gens_vec, size_t g_len, const secp256k1_scalar *c_vec, size_t c_vec_len, const secp256k1_ge *commit)
static int purify_copy_vectors_into_scratch(const secp256k1_context *ctx, secp256k1_scratch_space *scratch, secp256k1_scalar **ns, secp256k1_scalar **ls, secp256k1_scalar **cs, secp256k1_ge **gs, const secp256k1_scalar *n_vec, const secp256k1_scalar *l_vec, const secp256k1_scalar *c_vec, const secp256k1_ge *gens_vec, size_t g_len, size_t h_len)
static int purify_bridge_checked_mul_size(size_t lhs, size_t rhs, size_t *out)
int purify_bulletproof_verify_circuit_with_resources(purify_bulletproof_backend_resources *resources, const purify_bulletproof_circuit_view *circuit, const unsigned char commitment33[33], const unsigned char value_gen33[33], const unsigned char *extra_commit, size_t extra_commit_len, const unsigned char *proof, size_t proof_len)
static int purify_parse_point_as_ge(const unsigned char point33[33], secp256k1_ge *out)
int purify_bip340_sign_with_fixed_nonce(purify_secp_context *context, unsigned char sig64[64], const unsigned char *msg, size_t msglen, const unsigned char seckey32[32], const unsigned char nonce32[32])
Signs a message with a caller-supplied BIP340 nonce scalar.
static int purify_bulletproof_verify_circuit_impl(purify_secp_context *context, purify_bulletproof_backend_resources *resources, const purify_bulletproof_circuit_view *circuit, const unsigned char commitment33[33], const unsigned char value_gen33[33], const unsigned char *extra_commit, size_t extra_commit_len, const unsigned char *proof, size_t proof_len)
int purify_scalar_is_even(const purify_scalar *value)
Returns nonzero when the scalar is even.
static void purify_free_bulletproof_circuit(secp256k1_bulletproof_circuit *circuit)
static int purify_bppp_commit_norm_arg_impl(purify_secp_context *context, purify_bppp_backend_resources *resources, const unsigned char rho32[32], const unsigned char *generators33, size_t generators_count, const unsigned char *n_vec32, size_t n_vec_len, const unsigned char *l_vec32, size_t l_vec_len, const unsigned char *c_vec32, size_t c_vec_len, unsigned char commitment_out33[33])
static int purify_fixed_nonce_function(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data)
int purify_sha256_many(unsigned char output32[32], const unsigned char *const *items, const size_t *item_lens, size_t items_count)
Computes SHA-256 over a set of byte strings.
int purify_bppp_prove_norm_arg(purify_secp_context *context, const unsigned char rho32[32], const unsigned char *generators33, size_t generators_count, const unsigned char *n_vec32, size_t n_vec_len, const unsigned char *l_vec32, size_t l_vec_len, const unsigned char *c_vec32, size_t c_vec_len, unsigned char commitment_out33[33], unsigned char *proof_out, size_t *proof_len)
Produces a standalone BPPP norm argument.
static int purify_bppp_prove_norm_arg_to_commitment_impl(purify_secp_context *context, purify_bppp_backend_resources *resources, const unsigned char rho32[32], const unsigned char *generators33, size_t generators_count, const unsigned char *n_vec32, size_t n_vec_len, const unsigned char *l_vec32, size_t l_vec_len, const unsigned char *c_vec32, size_t c_vec_len, const unsigned char commitment33[33], unsigned char *proof_out, size_t *proof_len)
int purify_bppp_commit_witness_only(purify_secp_context *context, const unsigned char *generators33, size_t generators_count, const unsigned char *n_vec32, size_t n_vec_len, const unsigned char *l_vec32, size_t l_vec_len, unsigned char commitment_out33[33])
int purify_bppp_commit_norm_arg(purify_secp_context *context, const unsigned char rho32[32], const unsigned char *generators33, size_t generators_count, const unsigned char *n_vec32, size_t n_vec_len, const unsigned char *l_vec32, size_t l_vec_len, const unsigned char *c_vec32, size_t c_vec_len, unsigned char commitment_out33[33])
static void purify_free_bulletproof_assignment(secp256k1_bulletproof_circuit_assignment *assignment)
void purify_sha256(unsigned char output32[32], const unsigned char *data, size_t data_len)
Computes SHA-256 over a byte string.
static int purify_bppp_verify_norm_arg_impl(purify_secp_context *context, purify_bppp_backend_resources *resources, const unsigned char rho32[32], const unsigned char *generators33, size_t generators_count, const unsigned char *c_vec32, size_t c_vec_len, size_t n_vec_len, const unsigned char commitment33[33], const unsigned char *proof, size_t proof_len)
int purify_scalar_is_one(const purify_scalar *value)
Returns nonzero when the scalar is one.
static size_t purify_total_row_entries(const purify_bulletproof_row_view *rows, size_t count, int *ok)
int purify_bip340_validate_signature(purify_secp_context *context, const unsigned char sig64[64])
Returns nonzero when the 64-byte BIP340 signature has a syntactically valid encoding.
void purify_secp_context_destroy(purify_secp_context *context)
Destroys a context returned by purify_secp_context_create.
Definition bppp_bridge.c:69
void purify_bppp_backend_resources_destroy(purify_bppp_backend_resources *resources)
void purify_scalar_inverse(purify_scalar *out, const purify_scalar *value)
Computes the multiplicative inverse of a scalar in constant time.
int purify_bppp_value_generator_h(purify_secp_context *context, unsigned char out33[33])
Serializes the alternate value generator used by Pedersen commitments.
int purify_bppp_create_generators(purify_secp_context *context, size_t count, unsigned char *out, size_t *out_len)
Expands the generator list required by the BPPP prover and verifier.
purify_bppp_backend_resources * purify_bppp_backend_resources_clone(const purify_bppp_backend_resources *resources)
static const secp256k1_scalar * purify_scalar_cast_const(const purify_scalar *scalar)
static int purify_bulletproof_circuit_evaluate(const secp256k1_bulletproof_circuit *circuit, const secp256k1_bulletproof_circuit_assignment *assignment)
int purify_point_add(purify_secp_context *context, const unsigned char lhs33[33], const unsigned char rhs33[33], unsigned char out33[33])
int purify_bppp_verify_norm_arg(purify_secp_context *context, const unsigned char rho32[32], const unsigned char *generators33, size_t generators_count, const unsigned char *c_vec32, size_t c_vec_len, size_t n_vec_len, const unsigned char commitment33[33], const unsigned char *proof, size_t proof_len)
Verifies a standalone BPPP norm argument.
int purify_pedersen_commit_char(purify_secp_context *context, const unsigned char blind32[32], const unsigned char value32[32], const unsigned char value_gen33[33], const unsigned char blind_gen33[33], unsigned char commitment_out33[33])
Computes a Pedersen commitment to an arbitrary 32-byte scalar value.
void purify_scalar_inverse_var(purify_scalar *out, const purify_scalar *value)
Computes the multiplicative inverse of a scalar.
int purify_bip340_validate_xonly_pubkey(purify_secp_context *context, const unsigned char xonly_pubkey32[32])
Returns nonzero when the x-only public key encoding parses successfully.
static secp256k1_context * purify_context_handle(const purify_secp_context *context)
Definition bppp_bridge.c:42
static void purify_bridge_secure_clear(void *data, size_t size)
Definition bppp_bridge.c:79
int purify_bppp_prove_norm_arg_with_resources(purify_bppp_backend_resources *resources, const unsigned char rho32[32], const unsigned char *n_vec32, size_t n_vec_len, const unsigned char *l_vec32, size_t l_vec_len, const unsigned char *c_vec32, size_t c_vec_len, unsigned char commitment_out33[33], unsigned char *proof_out, size_t *proof_len)
int purify_scalar_eq(const purify_scalar *lhs, const purify_scalar *rhs)
Returns nonzero when two scalars are equal.
int purify_bulletproof_prove_circuit_assume_valid_with_resources(purify_bulletproof_backend_resources *resources, const purify_bulletproof_circuit_view *circuit, const purify_bulletproof_assignment_view *assignment, const unsigned char *blind32, const unsigned char value_gen33[33], const unsigned char nonce32[32], const unsigned char *extra_commit, size_t extra_commit_len, unsigned char commitment_out33[33], unsigned char *proof_out, size_t *proof_len)
static int purify_parse_generator_as_ge(const secp256k1_context *ctx, const unsigned char generator33[33], secp256k1_ge *out)
int purify_bppp_offset_commitment(purify_secp_context *context, const unsigned char commitment33[33], const unsigned char scalar32[32], unsigned char commitment_out33[33])
static int purify_parse_fast_scalar(const unsigned char input32[32], secp256k1_fast_scalar *scalar)
void purify_scalar_negate(purify_scalar *out, const purify_scalar *value)
Computes the additive inverse of a scalar.
void purify_bulletproof_backend_resources_destroy(purify_bulletproof_backend_resources *resources)
purify_secp_context * purify_secp_context_create(void)
Creates one reusable secp256k1 context for the Purify bridge and public APIs.
Definition bppp_bridge.c:46
int purify_bppp_prove_norm_arg_to_commitment(purify_secp_context *context, const unsigned char rho32[32], const unsigned char *generators33, size_t generators_count, const unsigned char *n_vec32, size_t n_vec_len, const unsigned char *l_vec32, size_t l_vec_len, const unsigned char *c_vec32, size_t c_vec_len, const unsigned char commitment33[33], unsigned char *proof_out, size_t *proof_len)
purify_bulletproof_backend_resources * purify_bulletproof_backend_resources_create(purify_secp_context *context, size_t n_gates)
purify_bulletproof_backend_resources * purify_bulletproof_backend_resources_clone(const purify_bulletproof_backend_resources *resources)
int purify_bppp_base_generator(purify_secp_context *context, unsigned char out33[33])
Serializes the secp256k1 base generator into compressed form.
int purify_bppp_commit_norm_arg_with_resources(purify_bppp_backend_resources *resources, const unsigned char rho32[32], const unsigned char *n_vec32, size_t n_vec_len, const unsigned char *l_vec32, size_t l_vec_len, const unsigned char *c_vec32, size_t c_vec_len, unsigned char commitment_out33[33])
size_t purify_bppp_required_proof_size(size_t n_vec_len, size_t c_vec_len)
Computes the maximum serialized size of a BPPP norm proof.
static secp256k1_bppp_generators * purify_bppp_generators_clone(const secp256k1_bppp_generators *generators)
static int purify_bppp_prove_norm_arg_impl(purify_secp_context *context, purify_bppp_backend_resources *resources, const unsigned char rho32[32], const unsigned char *generators33, size_t generators_count, const unsigned char *n_vec32, size_t n_vec_len, const unsigned char *l_vec32, size_t l_vec_len, const unsigned char *c_vec32, size_t c_vec_len, unsigned char commitment_out33[33], unsigned char *proof_out, size_t *proof_len)
static void * purify_malloc_array(size_t count, size_t elem_size)
void purify_scalar_set_u64(purify_scalar *out, uint64_t value)
Initializes a scalar from a 64-bit unsigned integer.
void purify_hmac_sha256(unsigned char output32[32], const unsigned char *key, size_t key_len, const unsigned char *data, size_t data_len)
Computes HMAC-SHA256 over a byte string.
static void purify_bppp_backend_resources_release_scratch_gens(purify_bppp_mutable_generators_guard *guard)
void purify_scalar_get_b32(unsigned char output32[32], const purify_scalar *value)
Serializes a scalar as 32 big-endian bytes.
size_t purify_bulletproof_required_proof_size(size_t n_gates)
purify_bppp_backend_resources * purify_bppp_backend_resources_create(purify_secp_context *context, const unsigned char *generators33, size_t generators_count)
static int purify_bulletproof_prove_circuit_impl(const purify_bulletproof_circuit_view *circuit, const purify_bulletproof_assignment_view *assignment, const unsigned char *blind32, const unsigned char value_gen33[33], const unsigned char nonce32[32], const unsigned char *extra_commit, size_t extra_commit_len, unsigned char commitment_out33[33], unsigned char *proof_out, size_t *proof_len, int require_valid_assignment, purify_secp_context *context, purify_bulletproof_backend_resources *resources)
static int purify_bridge_checked_add_size(size_t lhs, size_t rhs, size_t *out)
int purify_bip340_verify(purify_secp_context *context, const unsigned char sig64[64], const unsigned char *msg, size_t msglen, const unsigned char xonly_pubkey32[32])
Verifies a BIP340 signature against a serialized x-only public key.
static void * purify_calloc_array(size_t count, size_t elem_size)
static int purify_serialize_point(unsigned char out33[33], secp256k1_ge *point)
int purify_bppp_verify_norm_arg_with_resources(purify_bppp_backend_resources *resources, const unsigned char rho32[32], const unsigned char *c_vec32, size_t c_vec_len, size_t n_vec_len, const unsigned char commitment33[33], const unsigned char *proof, size_t proof_len)
void purify_scalar_set_b32(purify_scalar *out, const unsigned char input32[32], int *overflow)
Parses a big-endian 32-byte scalar.
static int purify_build_bulletproof_circuit(const purify_bulletproof_circuit_view *view, secp256k1_bulletproof_circuit *out)
static int purify_bppp_commit_witness_only_impl(purify_secp_context *context, purify_bppp_backend_resources *resources, const unsigned char *generators33, size_t generators_count, const unsigned char *n_vec32, size_t n_vec_len, const unsigned char *l_vec32, size_t l_vec_len, unsigned char commitment_out33[33])
C ABI bridging Purify C++ code to secp256k1-zkp BPPP functionality.
static void secp256k1_fast_scalar_mul(secp256k1_scalar *r, const secp256k1_fast_scalar *a, const secp256k1_scalar *b)
static int secp256k1_bulletproof_relation66_verify_impl(const secp256k1_ecmult_context *ecmult_ctx, secp256k1_scratch *scratch, const unsigned char *const *proof, size_t n_proofs, size_t plen, const secp256k1_ge *const *commitp, size_t *nc, const secp256k1_ge *value_gen, const secp256k1_bulletproof_circuit *const *circ, const secp256k1_bulletproof_generators *gens, const unsigned char **extra_commit, size_t *extra_commit_len)
static int secp256k1_bulletproof_relation66_prove_impl(const secp256k1_ecmult_context *ecmult_ctx, secp256k1_scratch *scratch, unsigned char *proof, size_t *plen, const secp256k1_bulletproof_circuit_assignment *assn, const secp256k1_ge *commitp, const secp256k1_scalar *blinds, size_t nc, const secp256k1_ge *value_gen, const secp256k1_bulletproof_circuit *circ, const secp256k1_bulletproof_generators *gens, const unsigned char *nonce, const unsigned char *extra_commit, size_t extra_commit_len)
size_t secp256k1_bulletproof_innerproduct_proof_length(size_t n)
static secp256k1_bulletproof_generators * secp256k1_bulletproof_generators_create(const secp256k1_context *ctx, const secp256k1_generator *blinding_gen, size_t n, size_t precomp_n)
Definition core.h:97
static void secp256k1_bulletproof_generators_destroy(const secp256k1_context *ctx, secp256k1_bulletproof_generators *gen)
Definition core.h:169
#define secp256k1_scratch_alloc(scratch, size)
Definition core.h:26
static SECP256K1_INLINE void secp256k1_pedersen_ecmult_scalar(secp256k1_gej *rj, const secp256k1_scalar *sec, const secp256k1_scalar *value, const secp256k1_ge *value_gen, const secp256k1_ge *blind_gen)
Definition core.h:220
std::size_t generator_count
Definition bppp.cpp:344
std::vector< FieldElement > c_vec
Definition bppp.cpp:472
FieldElement rho
Definition bppp.cpp:468
std::vector< FieldElement > l_vec
Definition bppp.cpp:487
std::vector< PointBytes > generators
Definition bppp.cpp:471
std::vector< FieldElement > n_vec
Definition bppp.cpp:486
Scalar32 scalar
Definition bppp.cpp:119
Public C core for Purify key validation, key derivation, key generation, and evaluation.
purify_error_code purify_fill_secure_random(unsigned char *bytes, size_t bytes_len)
Fills a caller-owned buffer with secure operating-system randomness.
Definition core.c:260
@ PURIFY_ERROR_OK
Definition purify.h:29
Narrow C ABI exposing secp256k1 scalar and HMAC helpers to the C++ headers.
secp256k1_scratch_space * scratch
Definition bppp_bridge.c:95
secp256k1_context * ctx
Definition bppp_bridge.c:94
secp256k1_bppp_generators * gens
Definition bppp_bridge.c:96
secp256k1_bppp_generators gens_scratch
Definition bppp_bridge.c:97
purify_bppp_backend_resources * resources
secp256k1_scratch_space * scratch
Definition bppp_bridge.c:88
secp256k1_bulletproof_generators * gens
Definition bppp_bridge.c:89
const purify_bulletproof_row_view * wr
const purify_bulletproof_row_view * wo
const purify_bulletproof_row_view * wl
const purify_bulletproof_row_view * wv
const unsigned char * c32
Opaque scalar storage compatible with secp256k1-zkp internal scalar storage.
Definition secp_bridge.h:22
secp256k1_context * ctx
Definition bppp_bridge.c:37
secp256k1_bulletproof_wmatrix_row * wl
Definition core.h:52
secp256k1_bulletproof_wmatrix_row * wv
Definition core.h:55
secp256k1_bulletproof_wmatrix_entry * entries
Definition core.h:57
secp256k1_bulletproof_wmatrix_row * wo
Definition core.h:54
secp256k1_bulletproof_wmatrix_row * wr
Definition core.h:53
secp256k1_fast_scalar * c
Definition core.h:56
secp256k1_ge * blinding_gen
Definition core.h:72
Definition core.h:37
secp256k1_fast_scalar scal
Definition core.h:39
size_t idx
Definition core.h:38
secp256k1_bulletproof_wmatrix_entry * entry
Definition core.h:44