Bitcoin Core 31.99.0
P2P Digital Currency
bench_impl.h
Go to the documentation of this file.
1/***********************************************************************
2 * Copyright (c) 2024 josibake *
3 * Distributed under the MIT software license, see the accompanying *
4 * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
5 ***********************************************************************/
6
7#ifndef SECP256K1_MODULE_SILENTPAYMENTS_BENCH_H
8#define SECP256K1_MODULE_SILENTPAYMENTS_BENCH_H
9
10#include "../../../include/secp256k1_silentpayments.h"
11
12#include "../../util.h"
13
14/* maximum non-coinbase taproot outputs per block: largest N for 1-in-N-out P2TR transaction
15 * that has a vsize <= (1_000_000 - 81 - 64) [https://bitcoin.stackexchange.com/a/122952]
16 * (needed for constructing the "worst-case scanning attack", where a single
17 * tx fills up a full bock of taproot outputs that all go to the same scankey group) */
18#define MAX_P2TR_OUTPUTS_PER_BLOCK 23250
19
20#define SP_BENCH_MAX_INPUTS 1
21#define SP_BENCH_MAX_OUTPUTS MAX_P2TR_OUTPUTS_PER_BLOCK
22
23typedef struct {
26 unsigned char scan_key[32];
33 unsigned char smallest_outpoint[36];
34 unsigned char label[33];
35 unsigned char label_tweak[32];
39
40const unsigned char* label_lookup(const unsigned char* key, const void* cache_ptr) {
42 if (secp256k1_memcmp_var(key, data->label, 33) == 0) {
43 return data->label_tweak;
44 }
45 return NULL;
46}
47
48static void bench_silentpayments_scan_setup(void* arg) {
49 int i;
51 const unsigned char smallest_outpoint[36] = {
52 0x16, 0x9e, 0x1e, 0x83, 0xe9, 0x30, 0x85, 0x33, 0x91,
53 0xbc, 0x6f, 0x35, 0xf6, 0x05, 0xc6, 0x75, 0x4c, 0xfe,
54 0xad, 0x57, 0xcf, 0x83, 0x87, 0x63, 0x9d, 0x3b, 0x40,
55 0x96, 0xc5, 0x4f, 0x18, 0xf4, 0x00, 0x00, 0x00, 0x00,
56 };
57 const unsigned char spend_pubkey[33] = {
58 0x02,0xee,0x97,0xdf,0x83,0xb2,0x54,0x6a,
59 0xf5,0xa7,0xd0,0x62,0x15,0xd9,0x8b,0xcb,
60 0x63,0x7f,0xe0,0x5d,0xd0,0xfa,0x37,0x3b,
61 0xd8,0x20,0xe6,0x64,0xd3,0x72,0xde,0x9a,0x01
62 };
63 const unsigned char scan_key[32] = {
64 0xa8,0x90,0x54,0xc9,0x5b,0xe3,0xc3,0x01,
65 0x56,0x65,0x74,0xf2,0xaa,0x93,0xad,0xe0,
66 0x51,0x85,0x09,0x03,0xa6,0x9c,0xbd,0xd1,
67 0xd4,0x7e,0xae,0x26,0x3d,0x7b,0xc0,0x31
68 };
69 unsigned char scalar[32];
70 secp256k1_keypair input_keypair;
71 size_t pubkeylen = 33;
72
73 for (i = 0; i < 32; i++) {
74 scalar[i] = i + 1;
75 }
76 /* Create the first input public key for the full scan from the scalar. */
77 CHECK(secp256k1_keypair_create(data->ctx, &input_keypair, scalar));
78 CHECK(secp256k1_keypair_xonly_pub(data->ctx, &data->tx_inputs[0], NULL, &input_keypair));
79 data->tx_inputs_ptrs[0] = &data->tx_inputs[0];
80 CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->spend_pubkey, spend_pubkey, pubkeylen));
81 memcpy(data->scan_key, scan_key, 32);
82 memcpy(data->smallest_outpoint, smallest_outpoint, 36);
83
84 /* prepare transaction outputs for the "worst-case scanning attack",
85 * can be used for typical scanning scenarios as well */
86 {
87 secp256k1_silentpayments_recipient *recipients = malloc(sizeof(secp256k1_silentpayments_recipient) * data->num_outputs);
88 const secp256k1_silentpayments_recipient **recipients_ptrs = malloc(sizeof(secp256k1_silentpayments_recipient*) * data->num_outputs);
89 const secp256k1_keypair *keypairs_ptrs[SP_BENCH_MAX_INPUTS];
90 secp256k1_pubkey scan_pubkey, other_scan_pubkey;
91 unsigned char other_scan_seckey[32] = {99};
93 secp256k1_pubkey labeled_spend_pubkey;
94 int index_first_k;
95
96 CHECK(data->num_outputs <= SP_BENCH_MAX_OUTPUTS);
97 CHECK(data->num_matches <= data->num_outputs);
98 index_first_k = data->num_outputs - data->num_matches;
99
100 CHECK(secp256k1_ec_pubkey_create(data->ctx, &scan_pubkey, data->scan_key));
101 CHECK(secp256k1_ec_pubkey_create(data->ctx, &other_scan_pubkey, other_scan_seckey));
102
103 CHECK(secp256k1_silentpayments_recipient_label_create(data->ctx, &label, data->label_tweak, data->scan_key, 0));
106 &labeled_spend_pubkey, &data->spend_pubkey, &label));
107
108 data->tx_outputs = malloc(sizeof(secp256k1_xonly_pubkey) * data->num_outputs);
109 data->tx_outputs_ptrs = malloc(sizeof(secp256k1_xonly_pubkey*) * data->num_outputs);
110 data->found_outputs = malloc(sizeof(secp256k1_silentpayments_found_output) * data->num_outputs);
111 data->found_outputs_ptrs = malloc(sizeof(secp256k1_silentpayments_found_output*) * data->num_outputs);
112
113 keypairs_ptrs[0] = &input_keypair;
114 for (i = 0; i < data->num_outputs; i++) {
115 data->tx_outputs_ptrs[i] = &data->tx_outputs[i];
116 recipients_ptrs[i] = &recipients[i];
117 recipients[i].spend_pubkey = labeled_spend_pubkey;
118 if (i >= index_first_k) {
119 recipients[i].scan_pubkey = scan_pubkey;
120 } else {
121 unsigned char tweak[32] = {0};
122 tweak[31] = 1;
123 /* tweak non-match scan pubkey in order to create single-recipient groups
124 * (we want to avoid running into the recipient group protocol limit) */
125 CHECK(secp256k1_ec_pubkey_tweak_add(data->ctx, &other_scan_pubkey, tweak));
126 recipients[i].scan_pubkey = other_scan_pubkey;
127 }
128 recipients[i].index = i;
129 }
130 CHECK(secp256k1_silentpayments_sender_create_outputs(data->ctx, data->tx_outputs_ptrs, recipients_ptrs,
131 data->num_outputs, data->smallest_outpoint, keypairs_ptrs, SP_BENCH_MAX_INPUTS, NULL, 0));
132
133 for (i = 0; i < data->num_outputs; i++) {
134 data->found_outputs_ptrs[i] = &data->found_outputs[i];
135 }
136 /* reverse outputs within k group to simulate worst-case */
137 for (i = 0; i < data->num_matches / 2; i++) {
138 int pos = index_first_k + i;
139 secp256k1_xonly_pubkey *tmp = data->tx_outputs_ptrs[pos];
140 data->tx_outputs_ptrs[pos] = data->tx_outputs_ptrs[data->num_outputs - i - 1];
141 data->tx_outputs_ptrs[data->num_outputs - i - 1] = tmp;
142 }
143
144 free(recipients_ptrs);
145 free(recipients);
146 }
147}
148
149static void bench_silentpayments_scan_teardown(void* arg, int iters) {
151 (void)iters;
152
153 free(data->tx_outputs);
154 free(data->tx_outputs_ptrs);
155 free(data->found_outputs);
156 free(data->found_outputs_ptrs);
157}
158
159static void bench_silentpayments_scan(void* arg, int iters) {
162 uint32_t n_found = 0;
163 int i;
165 const void *label_context = data;
166
167 CHECK(data->num_outputs <= SP_BENCH_MAX_OUTPUTS);
168
169 for (i = 0; i < iters; i++) {
171 data->smallest_outpoint, data->tx_inputs_ptrs, SP_BENCH_MAX_INPUTS, NULL, 0));
173 data->found_outputs_ptrs, &n_found,
174 (const secp256k1_xonly_pubkey**)data->tx_outputs_ptrs, data->num_outputs,
175 data->scan_key, &prevouts_summary, &data->spend_pubkey,
176 label_lookup_fn, label_context)
177 );
178 CHECK(n_found == (uint32_t)data->num_matches);
179 }
180}
181
182static void run_silentpayments_bench(int iters, int argc, char** argv) {
184 int d = argc == 1;
185
187
188 if (d || have_flag(argc, argv, "silentpayments") || have_flag(argc, argv, "silentpayments_scan_nomatch")) {
189 const int num_outputs_bench[] = {2, 5, 10, 100, 1000, 2323, MAX_P2TR_OUTPUTS_PER_BLOCK};
190 size_t o;
191 for (o = 0; o < ARRAY_SIZE(num_outputs_bench); o++) {
192 const int num_outputs = num_outputs_bench[o];
193 char str[64];
194 data.num_outputs = num_outputs;
195 data.num_matches = 0;
196 sprintf(str, "silentpayments_scan_nomatch_N=%i", num_outputs);
197 /* Don't run these slow benchmarks with low iterations (as used e.g. in CI) to prevent slow down */
198 if (iters <= 2 && num_outputs > 10) {
199 printf("Skipping benchmark \"%s\" due to SECP256K1_BENCH_ITERS <= 2\n", str);
200 } else {
202 }
203 }
204 }
205
206 if (d || have_flag(argc, argv, "silentpayments") || have_flag(argc, argv, "silentpayments_scan_worstcase")) {
207 size_t k;
208 const int num_matches_bench[] = {10, 100, 1000, 2323};
209 for (k = 0; k < ARRAY_SIZE(num_matches_bench); k++) {
210 const int num_matches = num_matches_bench[k];
211 char str[64];
212 data.num_outputs = MAX_P2TR_OUTPUTS_PER_BLOCK;
213 data.num_matches = num_matches;
214 sprintf(str, "silentpayments_scan_worstcase_K=%i", num_matches);
215 /* Don't run these slow benchmarks with low iterations (as used e.g. in CI) to prevent slow down */
216 if (iters <= 2) {
217 printf("Skipping benchmark \"%s\" due to SECP256K1_BENCH_ITERS <= 2\n", str);
218 } else {
220 }
221 }
222 }
223
225}
226
227#endif /* SECP256K1_MODULE_SILENTPAYMENTS_BENCH_H */
static const PrecomputedData data
Precomputed COutPoint and CCoins values.
static void run_benchmark(char *name, void(*benchmark)(void *), void(*setup)(void *), void(*teardown)(void *), void *data, int count, int iter)
Definition: bench.c:26
#define CHECK(cond)
Unconditional failure on condition failure.
Definition: util.h:35
static int tweak(const secp256k1_context *ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache)
Definition: musig.c:64
void printf(FormatStringCheck< sizeof...(Args)> fmt, const Args &... args)
Format list of arguments to std::cout, according to the given format string.
Definition: tinyformat.h:1096
static int have_flag(int argc, char **argv, char *flag)
Definition: bench.h:112
static SECP256K1_INLINE int secp256k1_memcmp_var(const void *s1, const void *s2, size_t n)
Semantics like memcmp.
Definition: util.h:282
#define ARRAY_SIZE(arr)
Definition: util.h:195
SECP256K1_API void secp256k1_context_destroy(secp256k1_context *ctx) SECP256K1_ARG_NONNULL(1)
Destroy a secp256k1 context object (created in dynamically allocated memory).
Definition: secp256k1.c:190
SECP256K1_API secp256k1_context * secp256k1_context_create(unsigned int flags) SECP256K1_WARN_UNUSED_RESULT
Create a secp256k1 context object (in dynamically allocated memory).
Definition: secp256k1.c:144
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *input, size_t inputlen) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Parse a variable-length public key into the pubkey object.
Definition: secp256k1.c:269
#define SECP256K1_CONTEXT_NONE
Context flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size,...
Definition: secp256k1.h:215
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Compute the public key for a secret key.
Definition: secp256k1.c:637
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak32) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Tweak a public key by adding tweak times the generator to it.
Definition: secp256k1.c:720
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(const secp256k1_context *ctx, secp256k1_keypair *keypair, const unsigned char *seckey) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Compute the keypair for a valid secret key.
Definition: main_impl.h:203
SECP256K1_API int secp256k1_keypair_xonly_pub(const secp256k1_context *ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, const secp256k1_keypair *keypair) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4)
Get the x-only public key from a keypair.
Definition: main_impl.h:241
SECP256K1_API int secp256k1_silentpayments_recipient_label_serialize(const secp256k1_context *ctx, unsigned char *out33, const secp256k1_silentpayments_label *label) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Serialize a Silent Payments label.
Definition: main_impl.h:378
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_prevouts_summary_create(const secp256k1_context *ctx, secp256k1_silentpayments_prevouts_summary *prevouts_summary, const unsigned char *outpoint_smallest36, const secp256k1_xonly_pubkey *const *xonly_pubkeys, size_t n_xonly_pubkeys, const secp256k1_pubkey *const *pubkeys, size_t n_pubkeys) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Compute Silent Payments prevouts summary from prevout public keys and transaction inputs.
Definition: main_impl.h:488
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_sender_create_outputs(const secp256k1_context *ctx, secp256k1_xonly_pubkey **generated_outputs, const secp256k1_silentpayments_recipient **recipients, size_t n_recipients, const unsigned char *outpoint_smallest36, const secp256k1_keypair *const *keypairs, size_t n_keypairs, const unsigned char *const *seckeys, size_t n_seckeys) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5)
Create Silent Payments outputs for recipient(s).
Definition: main_impl.h:187
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_create_labeled_spend_pubkey(const secp256k1_context *ctx, secp256k1_pubkey *labeled_spend_pubkey, const secp256k1_pubkey *unlabeled_spend_pubkey, const secp256k1_silentpayments_label *label) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
Create Silent Payments labeled spend public key.
Definition: main_impl.h:430
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_scan_outputs(const secp256k1_context *ctx, secp256k1_silentpayments_found_output **found_outputs, uint32_t *n_found_outputs, const secp256k1_xonly_pubkey *const *tx_outputs, size_t n_tx_outputs, const unsigned char *scan_key32, const secp256k1_silentpayments_prevouts_summary *prevouts_summary, const secp256k1_pubkey *unlabeled_spend_pubkey, secp256k1_silentpayments_label_lookup label_lookup, const void *label_context) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8)
Scan for Silent Payments transaction outputs.
Definition: main_impl.h:603
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_label_create(const secp256k1_context *ctx, secp256k1_silentpayments_label *label, unsigned char *label_tweak32, const unsigned char *scan_key32, uint32_t m) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
Create Silent Payments label tweak and label.
Definition: main_impl.h:393
const unsigned char *(* secp256k1_silentpayments_label_lookup)(const unsigned char *label33, const void *label_context)
Type of callback function for label lookups.
static void bench_silentpayments_scan_setup(void *arg)
Definition: bench_impl.h:48
#define SP_BENCH_MAX_INPUTS
Definition: bench_impl.h:20
#define MAX_P2TR_OUTPUTS_PER_BLOCK
Definition: bench_impl.h:18
static void bench_silentpayments_scan(void *arg, int iters)
Definition: bench_impl.h:159
const unsigned char * label_lookup(const unsigned char *key, const void *cache_ptr)
Definition: bench_impl.h:40
static void bench_silentpayments_scan_teardown(void *arg, int iters)
Definition: bench_impl.h:149
#define SP_BENCH_MAX_OUTPUTS
Definition: bench_impl.h:21
static void run_silentpayments_bench(int iters, int argc, char **argv)
Definition: bench_impl.h:182
static unsigned char smallest_outpoint[36]
secp256k1_silentpayments_found_output ** found_outputs_ptrs
Definition: bench_impl.h:32
secp256k1_pubkey spend_pubkey
Definition: bench_impl.h:25
secp256k1_silentpayments_found_output * found_outputs
Definition: bench_impl.h:31
secp256k1_xonly_pubkey ** tx_outputs_ptrs
Definition: bench_impl.h:28
secp256k1_context * ctx
Definition: bench_impl.h:24
secp256k1_xonly_pubkey * tx_outputs
Definition: bench_impl.h:27
Opaque data structure that holds a keypair consisting of a secret and a public key.
Opaque data structure that holds a parsed and valid public key.
Definition: secp256k1.h:62
Opaque data structure that holds a Silent Payments label.
Opaque data structure that holds Silent Payments prevouts summary data.
The data from a single recipient address.
Opaque data structure that holds a parsed and valid "x-only" public key.