Skip to content

Commit d517cec

Browse files
siv2rEunovo
authored andcommitted
batch: Add create and destroy APIs
This commit adds the _batch_create and _batch_destroy APIs. Relevant Links: 1. _batch_scratch_size allocation formula is taken from bench ecmult: https://github.com/bitcoin-core/secp256k1/blob/694ce8fb2d1fd8a3d641d7c33705691d41a2a860/src/bench_ecmult.c#L312. 2. aux_rand16 param in _batch_create enables synthetic randomness for randomizer generation: sipa/bips#204.
1 parent f7fad2d commit d517cec

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed

include/secp256k1_batch.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,51 @@ extern "C" {
1818
* (https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki).
1919
*/
2020

21+
/** Opaque data structure that holds information required for the batch verification.
22+
*
23+
* The purpose of this structure is to store elliptic curve points, their scalar
24+
* coefficients, and scalar coefficient of generator point participating in Multi-Scalar
25+
* Point Multiplication computation, which is done by `secp256k1_ecmult_strauss_batch_internal`
26+
*/
27+
typedef struct secp256k1_batch_struct secp256k1_batch;
28+
29+
/** Create a secp256k1 batch object object (in dynamically allocated memory).
30+
*
31+
* This function uses malloc to allocate memory. It is guaranteed that malloc is
32+
* called at most twice for every call of this function.
33+
*
34+
* Returns: a newly created batch object.
35+
* Args: ctx: an existing `secp256k1_context` object. Not to be confused
36+
* with the batch object object that this function creates.
37+
* In: max_terms: Max number of (scalar, curve point) pairs that the batch
38+
* object can store.
39+
* 1. `batch_add_schnorrsig` - adds two scalar-point pairs to the batch
40+
* 2. `batch_add_xonpub_tweak_check` - adds one scalar-point pair to the batch
41+
* Hence, for adding n schnorrsigs and m tweak checks, `max_terms`
42+
* should be set to 2*n + m.
43+
* aux_rand16: 16 bytes of fresh randomness. While recommended to provide
44+
* this, it is only supplemental to security and can be NULL. A
45+
* NULL argument is treated the same as an all-zero one.
46+
*/
47+
SECP256K1_API secp256k1_batch* secp256k1_batch_create(
48+
const secp256k1_context* ctx,
49+
size_t max_terms,
50+
const unsigned char *aux_rand16
51+
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
52+
53+
/** Destroy a secp256k1 batch object (created in dynamically allocated memory).
54+
*
55+
* The batch object's pointer may not be used afterwards.
56+
*
57+
* Args: ctx: a secp256k1 context object.
58+
* batch: an existing batch object to destroy, constructed
59+
* using `secp256k1_batch_create`
60+
*/
61+
SECP256K1_API void secp256k1_batch_destroy(
62+
const secp256k1_context* ctx,
63+
secp256k1_batch* batch
64+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
65+
2166
#ifdef __cplusplus
2267
}
2368
#endif

src/modules/batch/main_impl.h

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,139 @@
33

44
#include "include/secp256k1_batch.h"
55

6+
/** Opaque data structure that holds information required for the batch verification.
7+
*
8+
* Members:
9+
* data: scratch space object that contains points (_gej) and their
10+
* respective scalars. To be used in Multi-Scalar Multiplication
11+
* algorithms such as Strauss and Pippenger.
12+
* scalars: pointer to scalars allocated on the scratch space.
13+
* points: pointer to points allocated on the scratch space.
14+
* sc_g: scalar corresponding to the generator point (G) in Multi-Scalar
15+
* Multiplication equation.
16+
* sha256: contains hash of all the inputs (schnorrsig/tweaks) present in
17+
* the batch object, expect the first input. Used for generating a random secp256k1_scalar
18+
* for each term added by secp256k1_batch_add_*.
19+
* sha256: contains hash of all inputs (except the first one) present in the batch.
20+
* `secp256k1_batch_add_` APIs use these for randomizing the scalar (i.e., multiplying
21+
* it with a newly generated scalar) before adding it to the batch.
22+
* len: number of scalar-point pairs present in the batch.
23+
* capacity: max number of scalar-point pairs that the batch can hold.
24+
* result: tells whether the given set of inputs (schnorrsigs or tweak checks) is valid
25+
* or invalid. 1 = valid and 0 = invalid. By default, this is set to 1
26+
* during batch object creation (i.e., `secp256k1_batch_create`).
27+
*
28+
* The following struct name is typdef as secp256k1_batch (in include/secp256k1_batch.h).
29+
*/
30+
struct secp256k1_batch_struct{
31+
secp256k1_scratch *data;
32+
secp256k1_scalar *scalars;
33+
secp256k1_gej *points;
34+
secp256k1_scalar sc_g;
35+
secp256k1_sha256 sha256;
36+
size_t len;
37+
size_t capacity;
38+
int result;
39+
};
40+
41+
static size_t secp256k1_batch_scratch_size(int max_terms) {
42+
size_t ret = secp256k1_strauss_scratch_size(max_terms) + STRAUSS_SCRATCH_OBJECTS*16;
43+
VERIFY_CHECK(ret != 0);
44+
45+
return ret;
46+
}
47+
48+
/** Allocates space for `batch->capacity` number of scalars and points on batch
49+
* object's scratch space */
50+
static int secp256k1_batch_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_batch* batch) {
51+
size_t checkpoint = secp256k1_scratch_checkpoint(error_callback, batch->data);
52+
size_t count = batch->capacity;
53+
54+
VERIFY_CHECK(count > 0);
55+
56+
batch->scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, batch->data, count*sizeof(secp256k1_scalar));
57+
batch->points = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, batch->data, count*sizeof(secp256k1_gej));
58+
59+
/* If scalar or point allocation fails, restore scratch space to previous state */
60+
if (batch->scalars == NULL || batch->points == NULL) {
61+
secp256k1_scratch_apply_checkpoint(error_callback, batch->data, checkpoint);
62+
return 0;
63+
}
64+
65+
return 1;
66+
}
67+
68+
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
69+
* SHA256 to SHA256("BIP0340/batch")||SHA256("BIP0340/batch"). */
70+
static void secp256k1_batch_sha256_tagged(secp256k1_sha256 *sha) {
71+
secp256k1_sha256_initialize(sha);
72+
sha->s[0] = 0x79e3e0d2ul;
73+
sha->s[1] = 0x12284f32ul;
74+
sha->s[2] = 0xd7d89e1cul;
75+
sha->s[3] = 0x6491ea9aul;
76+
sha->s[4] = 0xad823b2ful;
77+
sha->s[5] = 0xfacfe0b6ul;
78+
sha->s[6] = 0x342b78baul;
79+
sha->s[7] = 0x12ece87cul;
80+
81+
sha->bytes = 64;
82+
}
83+
84+
secp256k1_batch* secp256k1_batch_create(const secp256k1_context* ctx, size_t max_terms, const unsigned char *aux_rand16) {
85+
size_t batch_size;
86+
secp256k1_batch* batch;
87+
size_t batch_scratch_size;
88+
unsigned char zeros[16] = {0};
89+
90+
VERIFY_CHECK(ctx != NULL);
91+
ARG_CHECK(max_terms != 0);
92+
93+
batch_size = sizeof(secp256k1_batch);
94+
batch = (secp256k1_batch *)checked_malloc(&ctx->error_callback, batch_size);
95+
batch_scratch_size = secp256k1_batch_scratch_size(max_terms);
96+
if (batch != NULL) {
97+
/* create scratch space inside batch object, if that fails return NULL*/
98+
batch->data = secp256k1_scratch_create(&ctx->error_callback, batch_scratch_size);
99+
if (batch->data == NULL) {
100+
return NULL;
101+
}
102+
/* allocate memeory for `max_terms` number of scalars and points on scratch space */
103+
batch->capacity = max_terms;
104+
if (!secp256k1_batch_scratch_alloc(&ctx->error_callback, batch)) {
105+
/* if scratch memory allocation fails, free all the previous the allocated memory
106+
and return NULL */
107+
secp256k1_scratch_destroy(&ctx->error_callback, batch->data);
108+
free(batch);
109+
return NULL;
110+
}
111+
112+
/* set remaining data members */
113+
secp256k1_scalar_clear(&batch->sc_g);
114+
secp256k1_batch_sha256_tagged(&batch->sha256);
115+
if (aux_rand16 != NULL) {
116+
secp256k1_sha256_write(&batch->sha256, aux_rand16, 16);
117+
} else {
118+
/* use 16 bytes of 0x0000...000, if no fresh randomness provided */
119+
secp256k1_sha256_write(&batch->sha256, zeros, 16);
120+
}
121+
batch->len = 0;
122+
batch->result = 1;
123+
}
124+
125+
return batch;
126+
}
127+
128+
void secp256k1_batch_destroy(const secp256k1_context *ctx, secp256k1_batch *batch) {
129+
VERIFY_CHECK(ctx != NULL);
130+
131+
if (batch != NULL) {
132+
if(batch->data != NULL) {
133+
/* can't destroy a scratch space with non-zero size */
134+
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, batch->data, 0);
135+
secp256k1_scratch_destroy(&ctx->error_callback, batch->data);
136+
}
137+
free(batch);
138+
}
139+
}
140+
6141
#endif /* SECP256K1_MODULE_BATCH_MAIN_H */

0 commit comments

Comments
 (0)