|
1 | 1 | /***********************************************************************
|
2 |
| - * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * |
| 2 | + * Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman * |
3 | 3 | * Distributed under the MIT software license, see the accompanying *
|
4 | 4 | * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
5 | 5 | ***********************************************************************/
|
|
10 | 10 | #include "ecmult_gen_compute_table.h"
|
11 | 11 | #include "group_impl.h"
|
12 | 12 | #include "field_impl.h"
|
| 13 | +#include "scalar_impl.h" |
13 | 14 | #include "ecmult_gen.h"
|
14 | 15 | #include "util.h"
|
15 | 16 |
|
16 |
| -static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int bits) { |
17 |
| - int g = ECMULT_GEN_PREC_G(bits); |
18 |
| - int n = ECMULT_GEN_PREC_N(bits); |
| 17 | +static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth) { |
| 18 | + size_t points = ((size_t)1) << (teeth - 1); |
| 19 | + size_t points_total = points * blocks; |
| 20 | + int spacing = (256 + blocks * teeth - 1) / (blocks * teeth); |
| 21 | + secp256k1_ge* prec = checked_malloc(&default_error_callback, points_total * sizeof(*prec)); |
| 22 | + secp256k1_gej* ds = checked_malloc(&default_error_callback, teeth * sizeof(*ds)); |
| 23 | + secp256k1_gej* vs = checked_malloc(&default_error_callback, points_total * sizeof(*vs)); |
| 24 | + secp256k1_gej u; |
| 25 | + size_t vs_pos = 0; |
| 26 | + secp256k1_scalar half; |
| 27 | + int block, i; |
19 | 28 |
|
20 |
| - secp256k1_ge* prec = checked_malloc(&default_error_callback, n * g * sizeof(*prec)); |
21 |
| - secp256k1_gej gj; |
22 |
| - secp256k1_gej nums_gej; |
23 |
| - int i, j; |
| 29 | + VERIFY_CHECK(points_total > 0); |
24 | 30 |
|
25 |
| - VERIFY_CHECK(g > 0); |
26 |
| - VERIFY_CHECK(n > 0); |
27 |
| - |
28 |
| - /* get the generator */ |
29 |
| - secp256k1_gej_set_ge(&gj, gen); |
30 |
| - |
31 |
| - /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ |
| 31 | + /* u is the running power of two times gen we're working with, initially gen/2. */ |
| 32 | + secp256k1_scalar_half(&half, &secp256k1_scalar_one); |
| 33 | + secp256k1_gej_set_infinity(&u); |
| 34 | + for (i = 255; i >= 0; --i) { |
| 35 | + /* Use a very simple multiplication ladder to avoid dependency on ecmult. */ |
| 36 | + secp256k1_gej_double_var(&u, &u, NULL); |
| 37 | + if (secp256k1_scalar_get_bits(&half, i, 1)) { |
| 38 | + secp256k1_gej_add_ge_var(&u, &u, gen, NULL); |
| 39 | + } |
| 40 | + } |
| 41 | +#ifdef VERIFY |
32 | 42 | {
|
33 |
| - static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; |
34 |
| - secp256k1_fe nums_x; |
35 |
| - secp256k1_ge nums_ge; |
36 |
| - int r; |
37 |
| - r = secp256k1_fe_set_b32_limit(&nums_x, nums_b32); |
38 |
| - (void)r; |
39 |
| - VERIFY_CHECK(r); |
40 |
| - r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0); |
41 |
| - (void)r; |
42 |
| - VERIFY_CHECK(r); |
43 |
| - secp256k1_gej_set_ge(&nums_gej, &nums_ge); |
44 |
| - /* Add G to make the bits in x uniformly distributed. */ |
45 |
| - secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, gen, NULL); |
| 43 | + /* Verify that u*2 = gen. */ |
| 44 | + secp256k1_gej double_u; |
| 45 | + secp256k1_gej_double_var(&double_u, &u, NULL); |
| 46 | + VERIFY_CHECK(secp256k1_gej_eq_ge_var(&double_u, gen)); |
46 | 47 | }
|
| 48 | +#endif |
47 | 49 |
|
48 |
| - /* compute prec. */ |
49 |
| - { |
50 |
| - secp256k1_gej gbase; |
51 |
| - secp256k1_gej numsbase; |
52 |
| - secp256k1_gej* precj = checked_malloc(&default_error_callback, n * g * sizeof(*precj)); /* Jacobian versions of prec. */ |
53 |
| - gbase = gj; /* PREC_G^j * G */ |
54 |
| - numsbase = nums_gej; /* 2^j * nums. */ |
55 |
| - for (j = 0; j < n; j++) { |
56 |
| - /* Set precj[j*PREC_G .. j*PREC_G+(PREC_G-1)] to (numsbase, numsbase + gbase, ..., numsbase + (PREC_G-1)*gbase). */ |
57 |
| - precj[j*g] = numsbase; |
58 |
| - for (i = 1; i < g; i++) { |
59 |
| - secp256k1_gej_add_var(&precj[j*g + i], &precj[j*g + i - 1], &gbase, NULL); |
| 50 | + for (block = 0; block < blocks; ++block) { |
| 51 | + int tooth; |
| 52 | + /* Here u = 2^(block*teeth*spacing) * gen/2. */ |
| 53 | + secp256k1_gej sum; |
| 54 | + secp256k1_gej_set_infinity(&sum); |
| 55 | + for (tooth = 0; tooth < teeth; ++tooth) { |
| 56 | + /* Here u = 2^((block*teeth + tooth)*spacing) * gen/2. */ |
| 57 | + int bit_off; |
| 58 | + /* Make sum = sum(2^((block*teeth + t)*spacing), t=0..tooth) * gen/2. */ |
| 59 | + secp256k1_gej_add_var(&sum, &sum, &u, NULL); |
| 60 | + /* Make u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */ |
| 61 | + secp256k1_gej_double_var(&u, &u, NULL); |
| 62 | + /* Make ds[tooth] = u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */ |
| 63 | + ds[tooth] = u; |
| 64 | + /* Make u = 2^((block*teeth + tooth + 1)*spacing) * gen/2. */ |
| 65 | + for (bit_off = 1; bit_off < spacing; ++bit_off) { |
| 66 | + secp256k1_gej_double_var(&u, &u, NULL); |
60 | 67 | }
|
61 |
| - /* Multiply gbase by PREC_G. */ |
62 |
| - for (i = 0; i < bits; i++) { |
63 |
| - secp256k1_gej_double_var(&gbase, &gbase, NULL); |
64 |
| - } |
65 |
| - /* Multiply numbase by 2. */ |
66 |
| - secp256k1_gej_double_var(&numsbase, &numsbase, NULL); |
67 |
| - if (j == n - 2) { |
68 |
| - /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ |
69 |
| - secp256k1_gej_neg(&numsbase, &numsbase); |
70 |
| - secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); |
| 68 | + } |
| 69 | + /* Now u = 2^((block*teeth + teeth)*spacing) * gen/2 |
| 70 | + * = 2^((block+1)*teeth*spacing) * gen/2 */ |
| 71 | + |
| 72 | + /* Next, compute the table entries for block number block in Jacobian coordinates. |
| 73 | + * The entries will occupy vs[block*points + i] for i=0..points-1. |
| 74 | + * We start by computing the first (i=0) value corresponding to all summed |
| 75 | + * powers of two times G being negative. */ |
| 76 | + secp256k1_gej_neg(&vs[vs_pos++], &sum); |
| 77 | + /* And then teeth-1 times "double" the range of i values for which the table |
| 78 | + * is computed: in each iteration, double the table by taking an existing |
| 79 | + * table entry and adding ds[tooth]. */ |
| 80 | + for (tooth = 0; tooth < teeth - 1; ++tooth) { |
| 81 | + size_t stride = ((size_t)1) << tooth; |
| 82 | + size_t index; |
| 83 | + for (index = 0; index < stride; ++index, ++vs_pos) { |
| 84 | + secp256k1_gej_add_var(&vs[vs_pos], &vs[vs_pos - stride], &ds[tooth], NULL); |
71 | 85 | }
|
72 | 86 | }
|
73 |
| - secp256k1_ge_set_all_gej_var(prec, precj, n * g); |
74 |
| - free(precj); |
75 | 87 | }
|
76 |
| - for (j = 0; j < n; j++) { |
77 |
| - for (i = 0; i < g; i++) { |
78 |
| - secp256k1_ge_to_storage(&table[j*g + i], &prec[j*g + i]); |
| 88 | + VERIFY_CHECK(vs_pos == points_total); |
| 89 | + |
| 90 | + /* Convert all points simultaneously from secp256k1_gej to secp256k1_ge. */ |
| 91 | + secp256k1_ge_set_all_gej_var(prec, vs, points_total); |
| 92 | + /* Convert all points from secp256k1_ge to secp256k1_ge_storage output. */ |
| 93 | + for (block = 0; block < blocks; ++block) { |
| 94 | + size_t index; |
| 95 | + for (index = 0; index < points; ++index) { |
| 96 | + secp256k1_ge_to_storage(&table[block * points + index], &prec[block * points + index]); |
79 | 97 | }
|
80 | 98 | }
|
| 99 | + |
| 100 | + /* Free memory. */ |
| 101 | + free(vs); |
| 102 | + free(ds); |
81 | 103 | free(prec);
|
82 | 104 | }
|
83 | 105 |
|
|
0 commit comments