Skip to content

Commit 1419637

Browse files
committed
Merge #580: Add trivial ecmult_multi algorithm which does not require a scratch space
a697d82 Add trivial ecmult_multi to the benchmark tool (Jonas Nick) bade617 Add trivial ecmult_multi algorithm. It is selected when no scratch space is given and just multiplies and adds the points. (Jonas Nick) Pull request description: This commit adds a new ecmult_multi algorithm that is automatically selected when `ecmult_multi_var` is called with scratch space set to `NULL`. This is a trivial algorithm that simply multiplies the points with the corresponding scalars and adds them up. The use case is to allow creating exposed function that uses `ecmult_multi` but without requiring a scratch space argument. For example, in MuSig when computing the combined public key we need to compute a weighted sum of points but we most likely don't care about the performance. And if we do we can still provide a scratch space. Having the option of not providing a scratch space is useful because creating a scratch space is not entirely trivial. One needs to decide on a size and it needs to be destroyed. Tree-SHA512: 2de20feeff00902ca0936ec1f8d81cf7a95d0917f80e76e9eacbd739c8c2e248fbdaeb468a0aeaf715ec251c2c79b5e271ff4d77456218d02332e26e003d796e
2 parents 5545e13 + a697d82 commit 1419637

File tree

4 files changed

+46
-6
lines changed

4 files changed

+46
-6
lines changed

src/bench_ecmult.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,25 +139,31 @@ int main(int argc, char **argv) {
139139
secp256k1_gej* pubkeys_gej;
140140
size_t scratch_size;
141141

142+
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
143+
scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
144+
data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);
142145
data.ecmult_multi = secp256k1_ecmult_multi_var;
146+
143147
if (argc > 1) {
144148
if(have_flag(argc, argv, "pippenger_wnaf")) {
145149
printf("Using pippenger_wnaf:\n");
146150
data.ecmult_multi = secp256k1_ecmult_pippenger_batch_single;
147151
} else if(have_flag(argc, argv, "strauss_wnaf")) {
148152
printf("Using strauss_wnaf:\n");
149153
data.ecmult_multi = secp256k1_ecmult_strauss_batch_single;
154+
} else if(have_flag(argc, argv, "simple")) {
155+
printf("Using simple algorithm:\n");
156+
data.ecmult_multi = secp256k1_ecmult_multi_var;
157+
secp256k1_scratch_space_destroy(data.scratch);
158+
data.scratch = NULL;
150159
} else {
151160
fprintf(stderr, "%s: unrecognized argument '%s'.\n", argv[0], argv[1]);
152-
fprintf(stderr, "Use 'pippenger_wnaf', 'strauss_wnaf' or no argument to benchmark a combined algorithm.\n");
161+
fprintf(stderr, "Use 'pippenger_wnaf', 'strauss_wnaf', 'simple' or no argument to benchmark a combined algorithm.\n");
153162
return 1;
154163
}
155164
}
156165

157166
/* Allocate stuff */
158-
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
159-
scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
160-
data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);
161167
data.scalars = malloc(sizeof(secp256k1_scalar) * POINTS);
162168
data.seckeys = malloc(sizeof(secp256k1_scalar) * POINTS);
163169
data.pubkeys = malloc(sizeof(secp256k1_ge) * POINTS);
@@ -188,7 +194,9 @@ int main(int argc, char **argv) {
188194
}
189195
}
190196
secp256k1_context_destroy(data.ctx);
191-
secp256k1_scratch_space_destroy(data.scratch);
197+
if (data.scratch != NULL) {
198+
secp256k1_scratch_space_destroy(data.scratch);
199+
}
192200
free(data.scalars);
193201
free(data.pubkeys);
194202
free(data.seckeys);

src/ecmult.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge
3737
* Chooses the right algorithm for a given number of points and scratch space
3838
* size. Resets and overwrites the given scratch space. If the points do not
3939
* fit in the scratch space the algorithm is repeatedly run with batches of
40-
* points.
40+
* points. If no scratch space is given then a simple algorithm is used that
41+
* simply multiplies the points with the corresponding scalars and adds them up.
4142
* Returns: 1 on success (including when inp_g_sc is NULL and n is 0)
4243
* 0 if there is not enough scratch space for a single point or
4344
* callback returns 0

src/ecmult_impl.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,33 @@ static size_t secp256k1_pippenger_max_points(secp256k1_scratch *scratch) {
10841084
return res;
10851085
}
10861086

1087+
/* Computes ecmult_multi by simply multiplying and adding each point. Does not
1088+
* require a scratch space */
1089+
static int secp256k1_ecmult_multi_simple_var(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) {
1090+
size_t point_idx;
1091+
secp256k1_scalar szero;
1092+
secp256k1_gej tmpj;
1093+
1094+
secp256k1_scalar_set_int(&szero, 0);
1095+
secp256k1_gej_set_infinity(r);
1096+
secp256k1_gej_set_infinity(&tmpj);
1097+
/* r = inp_g_sc*G */
1098+
secp256k1_ecmult(ctx, r, &tmpj, &szero, inp_g_sc);
1099+
for (point_idx = 0; point_idx < n_points; point_idx++) {
1100+
secp256k1_ge point;
1101+
secp256k1_gej pointj;
1102+
secp256k1_scalar scalar;
1103+
if (!cb(&scalar, &point, point_idx, cbdata)) {
1104+
return 0;
1105+
}
1106+
/* r += scalar*point */
1107+
secp256k1_gej_set_ge(&pointj, &point);
1108+
secp256k1_ecmult(ctx, &tmpj, &pointj, &scalar, NULL);
1109+
secp256k1_gej_add_var(r, r, &tmpj, NULL);
1110+
}
1111+
return 1;
1112+
}
1113+
10871114
typedef int (*secp256k1_ecmult_multi_func)(const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t);
10881115
static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
10891116
size_t i;
@@ -1102,6 +1129,9 @@ static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp2
11021129
secp256k1_ecmult(ctx, r, r, &szero, inp_g_sc);
11031130
return 1;
11041131
}
1132+
if (scratch == NULL) {
1133+
return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n);
1134+
}
11051135

11061136
max_points = secp256k1_pippenger_max_points(scratch);
11071137
if (max_points == 0) {

src/tests.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2926,6 +2926,7 @@ void run_ecmult_multi_tests(void) {
29262926
test_ecmult_multi_pippenger_max_points();
29272927
scratch = secp256k1_scratch_create(&ctx->error_callback, 819200);
29282928
test_ecmult_multi(scratch, secp256k1_ecmult_multi_var);
2929+
test_ecmult_multi(NULL, secp256k1_ecmult_multi_var);
29292930
test_ecmult_multi(scratch, secp256k1_ecmult_pippenger_batch_single);
29302931
test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single);
29312932
secp256k1_scratch_destroy(scratch);

0 commit comments

Comments
 (0)