Skip to content

Commit b3d370f

Browse files
committed
batch: Add API usage example
This commit adds an example C program using the batch API. GNU Autotools will compile this example only if both batch and schnorrsig modules are enabled.
1 parent 9c120ef commit b3d370f

File tree

3 files changed

+193
-0
lines changed

3 files changed

+193
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ valgrind_ctime_test
99
ecdh_example
1010
ecdsa_example
1111
schnorr_example
12+
batch_example
1213
*.exe
1314
*.so
1415
*.a

Makefile.am

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,17 @@ if BUILD_WINDOWS
170170
schnorr_example_LDFLAGS += -lbcrypt
171171
endif
172172
TESTS += schnorr_example
173+
if ENABLE_MODULE_BATCH
174+
noinst_PROGRAMS += batch_example
175+
batch_example_SOURCES = examples/batch.c
176+
batch_example_CPPFLAGS = -I$(top_srcdir)/include
177+
batch_example_LDADD = libsecp256k1.la
178+
batch_example_LDFLAGS = -static
179+
if BUILD_WINDOWS
180+
batch_example_LDFLAGS += -lbcrypt
181+
endif
182+
TESTS += batch_example
183+
endif
173184
endif
174185
endif
175186

examples/batch.c

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
#include <stdio.h>
2+
#include <assert.h>
3+
#include <string.h>
4+
5+
#include <secp256k1.h>
6+
#include <secp256k1_batch.h>
7+
#include <secp256k1_schnorrsig_batch.h>
8+
#include <secp256k1_tweak_check_batch.h>
9+
10+
#include "random.h"
11+
12+
/* key pair data */
13+
unsigned char sk[32];
14+
secp256k1_keypair keypair;
15+
secp256k1_xonly_pubkey pk;
16+
17+
/* schnorrsig verification data */
18+
#define N_SIGS 10
19+
unsigned char msg[N_SIGS][32];
20+
unsigned char sig[N_SIGS][64];
21+
22+
/* xonly pubkey tweak checks data */
23+
#define N_CHECKS 10
24+
unsigned char tweaked_pubkey[N_CHECKS][32];
25+
int tweaked_pk_parity[N_CHECKS];
26+
unsigned char tweak[N_CHECKS][32];
27+
28+
/* 2*N_SIGS since one schnorrsig creates two scalar-point pairs in batch
29+
* whereas one tweak check creates one scalar-point pair in batch */
30+
#define N_TERMS (N_CHECKS + 2*N_SIGS)
31+
32+
/* generate key pair required for sign and verify */
33+
int create_keypair(secp256k1_context *ctx) {
34+
while(1) {
35+
if (!fill_random(sk, sizeof(sk))) {
36+
printf("Failed to generate randomness\n");
37+
return 1;
38+
}
39+
if (secp256k1_keypair_create(ctx, &keypair, sk)) {
40+
break;
41+
}
42+
}
43+
if (!secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair)) {
44+
return 0;
45+
}
46+
47+
return 1;
48+
}
49+
50+
/* create valid schnorrsigs for N_SIGS random messages */
51+
int generate_schnorrsigs(secp256k1_context *ctx) {
52+
size_t i;
53+
54+
for (i = 0; i < N_SIGS; i++) {
55+
if(!fill_random(msg[i], sizeof(msg[i]))) {
56+
printf("Failed to generate randomness\n");
57+
return 1;
58+
}
59+
assert(secp256k1_schnorrsig_sign32(ctx, sig[i], msg[i], &keypair, NULL));
60+
assert(secp256k1_schnorrsig_verify(ctx, sig[i], msg[i], sizeof(msg[i]), &pk));
61+
}
62+
63+
return 1;
64+
}
65+
66+
/* create valid N_CHECKS number of xonly pukey tweak checks */
67+
int generate_xonlypub_tweak_checks(secp256k1_context *ctx) {
68+
secp256k1_pubkey output_pk;
69+
secp256k1_xonly_pubkey output_xonly_pk;
70+
size_t i;
71+
72+
for (i = 0; i < N_CHECKS; i++) {
73+
if (!fill_random(tweak[i], sizeof(tweak[i]))) {
74+
printf("Failed to generate randomness\n");
75+
return 1;
76+
}
77+
assert(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &pk, tweak[i]));
78+
assert(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_xonly_pk, &tweaked_pk_parity[i], &output_pk));
79+
assert(secp256k1_xonly_pubkey_serialize(ctx, tweaked_pubkey[i], &output_xonly_pk));
80+
assert(secp256k1_xonly_pubkey_tweak_add_check(ctx, tweaked_pubkey[i], tweaked_pk_parity[i], &pk, tweak[i]));
81+
}
82+
83+
return 1;
84+
}
85+
86+
int main(void) {
87+
int ret;
88+
size_t i;
89+
/* batch object uses secp256k1_context only for the error callback function
90+
* here, we create secp256k1_context that can sign and verify, only to generate
91+
* input data (schnorrsigs, tweak checks) required for the batch */
92+
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
93+
secp256k1_batch *batch;
94+
unsigned char auxiliary_rand[16];
95+
96+
/* Generate 16 bytes of randomness to use during batch creation. */
97+
if (!fill_random(auxiliary_rand, sizeof(auxiliary_rand))) {
98+
printf("Failed to generate randomness\n");
99+
return 1;
100+
}
101+
102+
batch = secp256k1_batch_create(ctx, N_TERMS, auxiliary_rand);
103+
104+
assert(ctx != NULL);
105+
assert(batch != NULL);
106+
107+
/* key pair generation */
108+
printf("Creating a key pair.........................");
109+
if(!create_keypair(ctx)) {
110+
printf("FAILED\n");
111+
return 1;
112+
}
113+
printf("ok\n");
114+
115+
/* create schnorrsigs for N_SIGS random messages */
116+
printf("Signing messages............................");
117+
if(!generate_schnorrsigs(ctx)) {
118+
printf("FAILED\n");
119+
return 1;
120+
}
121+
printf("ok\n");
122+
123+
printf("Adding signatures to the batch object.......");
124+
for (i = 0; i < N_SIGS; i++) {
125+
/* It is recommended to check the validity of the batch before adding a
126+
* new input (schnorrsig/tweak check) to it. The `secp256k1_batch_add_` APIs
127+
* won't add any new input to invalid batch since the final `secp256k1_batch_verify`
128+
* API call will fail even if the new input is valid. */
129+
if(secp256k1_batch_usable(ctx, batch)) {
130+
ret = secp256k1_batch_add_schnorrsig(ctx, batch, sig[i], msg[i], sizeof(msg[i]), &pk);
131+
} else {
132+
printf("INVALID BATCH\n");
133+
return 1;
134+
}
135+
136+
if(!ret) {
137+
printf("FAILED\n");
138+
return 1;
139+
}
140+
}
141+
printf("ok\n");
142+
143+
printf("Generating xonlypub tweak checks............");
144+
if(!generate_xonlypub_tweak_checks(ctx)) {
145+
printf("FAILED\n");
146+
return 1;
147+
}
148+
printf("ok\n");
149+
150+
printf("Adding tweak checks to the batch object.....");
151+
for (i = 0; i < N_CHECKS; i++) {
152+
/* It is recommended to check the validity of the batch before adding a
153+
* new input (schnorrsig/tweak check) to it. The `secp256k1_batch_add_` APIs
154+
* won't add any new input to invalid batch since the final `secp256k1_batch_verify`
155+
* API call will fail even if the new input is valid. */
156+
if(secp256k1_batch_usable(ctx, batch)) {
157+
ret = secp256k1_batch_add_xonlypub_tweak_check(ctx, batch, tweaked_pubkey[i], tweaked_pk_parity[i], &pk, tweak[i]);
158+
} else {
159+
printf("INVALID BATCH\n");
160+
return 1;
161+
}
162+
163+
if(!ret) {
164+
printf("FAILED\n");
165+
return 1;
166+
}
167+
}
168+
printf("ok\n");
169+
170+
printf("Verifying the batch object..................");
171+
if(!secp256k1_batch_verify(ctx, batch)) {
172+
printf("FAILED\n");
173+
return 1;
174+
}
175+
printf("ok\n");
176+
177+
secp256k1_batch_destroy(ctx, batch);
178+
secp256k1_context_destroy(ctx);
179+
180+
return 0;
181+
}

0 commit comments

Comments
 (0)