mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-03 09:56:38 -05:00
Fourth step in converting to C: ecmult
This commit is contained in:
parent
f11ff5be70
commit
b1483f874c
7 changed files with 206 additions and 402 deletions
|
@ -12,6 +12,7 @@ int main() {
|
|||
secp256k1_num_start();
|
||||
secp256k1_fe_start();
|
||||
secp256k1_ge_start();
|
||||
secp256k1_ecmult_start();
|
||||
|
||||
secp256k1_fe_t x;
|
||||
const secp256k1_num_t *order = &secp256k1_ge_consts->order;
|
||||
|
@ -39,6 +40,7 @@ int main() {
|
|||
secp256k1_num_free(&s);
|
||||
secp256k1_num_free(&m);
|
||||
|
||||
secp256k1_ecmult_stop();
|
||||
secp256k1_ge_stop();
|
||||
secp256k1_fe_stop();
|
||||
secp256k1_num_stop();
|
||||
|
|
|
@ -79,7 +79,7 @@ bool Signature::RecomputeR(secp256k1_num_t &r2, const secp256k1_gej_t &pubkey, c
|
|||
secp256k1_num_mod_inverse(&sn, &s, &c.order);
|
||||
secp256k1_num_mod_mul(&u1, &sn, &message, &c.order);
|
||||
secp256k1_num_mod_mul(&u2, &sn, &r, &c.order);
|
||||
secp256k1_gej_t pr; ECMult(pr, pubkey, u2, u1);
|
||||
secp256k1_gej_t pr; secp256k1_ecmult(&pr, &pubkey, &u2, &u1);
|
||||
if (!secp256k1_gej_is_infinity(&pr)) {
|
||||
secp256k1_fe_t xr; secp256k1_gej_get_x(&xr, &pr);
|
||||
secp256k1_fe_normalize(&xr);
|
||||
|
@ -107,7 +107,7 @@ bool Signature::Sign(const secp256k1_num_t &seckey, const secp256k1_num_t &messa
|
|||
const secp256k1_ge_consts_t &c = *secp256k1_ge_consts;
|
||||
|
||||
secp256k1_gej_t rp;
|
||||
ECMultBase(rp, nonce);
|
||||
secp256k1_ecmult_gen(&rp, &nonce);
|
||||
secp256k1_fe_t rx;
|
||||
secp256k1_gej_get_x(&rx, &rp);
|
||||
unsigned char b[32];
|
||||
|
|
388
src/ecmult.cpp
388
src/ecmult.cpp
|
@ -12,245 +12,221 @@
|
|||
// exponentially larger precomputed tables. WINDOW_G == 13 results in 640 KiB.
|
||||
#define WINDOW_G 14
|
||||
|
||||
namespace secp256k1 {
|
||||
extern "C" {
|
||||
|
||||
template<int W> class WNAFPrecompJac {
|
||||
private:
|
||||
secp256k1_gej_t pre[1 << (W-2)];
|
||||
/** Fill a table 'pre' with precomputed odd multiples of a. W determines the size of the table.
|
||||
* pre will contains the values [1*a,3*a,5*a,...,(2^(w-1)-1)*a], so it needs place for
|
||||
* 2^(w-2) entries.
|
||||
*
|
||||
* There are two versions of this function:
|
||||
* - secp256k1_ecmult_precomp_wnaf_gej, which operates on group elements in jacobian notation,
|
||||
* fast to precompute, but slower to use in later additions.
|
||||
* - secp256k1_ecmult_precomp_wnaf_ge, which operates on group elements in affine notations,
|
||||
* (much) slower to precompute, but a bit faster to use in later additions.
|
||||
* To compute a*P + b*G, we use the jacobian version for P, and the affine version for G, as
|
||||
* G is constant, so it only needs to be done once in advance.
|
||||
*/
|
||||
void static secp256k1_ecmult_table_precomp_gej(secp256k1_gej_t *pre, const secp256k1_gej_t *a, int w) {
|
||||
pre[0] = *a;
|
||||
secp256k1_gej_t d; secp256k1_gej_double(&d, &pre[0]);
|
||||
for (int i=1; i<(1 << (w-2)); i++)
|
||||
secp256k1_gej_add(&pre[i], &d, &pre[i-1]);
|
||||
}
|
||||
|
||||
public:
|
||||
WNAFPrecompJac() {}
|
||||
|
||||
void Build(const secp256k1_gej_t &base) {
|
||||
pre[0] = base;
|
||||
secp256k1_gej_t d; secp256k1_gej_double(&d, &pre[0]);
|
||||
for (int i=1; i<(1 << (W-2)); i++)
|
||||
secp256k1_gej_add(&pre[i], &d, &pre[i-1]);
|
||||
void static secp256k1_ecmult_table_precomp_ge(secp256k1_ge_t *pre, const secp256k1_ge_t *a, int w) {
|
||||
pre[0] = *a;
|
||||
secp256k1_gej_t x; secp256k1_gej_set_ge(&x, a);
|
||||
secp256k1_gej_t d; secp256k1_gej_double(&d, &x);
|
||||
for (int i=1; i<(1 << (w-2)); i++) {
|
||||
secp256k1_gej_add_ge(&x, &d, &pre[i-1]);
|
||||
secp256k1_ge_set_gej(&pre[i], &x);
|
||||
}
|
||||
}
|
||||
|
||||
WNAFPrecompJac(const secp256k1_gej_t &base) {
|
||||
Build(base);
|
||||
}
|
||||
/** The number of entries a table with precomputed multiples needs to have. */
|
||||
#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))
|
||||
|
||||
void Get(secp256k1_gej_t &out, int exp) const {
|
||||
assert((exp & 1) == 1);
|
||||
assert(exp >= -((1 << (W-1)) - 1));
|
||||
assert(exp <= ((1 << (W-1)) - 1));
|
||||
if (exp > 0) {
|
||||
out = pre[(exp-1)/2];
|
||||
} else {
|
||||
secp256k1_gej_neg(&out, &pre[(-exp-1)/2]);
|
||||
}
|
||||
}
|
||||
};
|
||||
/** The following two macro retrieves a particular odd multiple from a table
|
||||
* of precomputed multiples. */
|
||||
#define ECMULT_TABLE_GET(r,pre,n,w,neg) do { \
|
||||
assert(((n) & 1) == 1); \
|
||||
assert((n) >= -((1 << ((w)-1)) - 1)); \
|
||||
assert((n) <= ((1 << ((w)-1)) - 1)); \
|
||||
if ((n) > 0) \
|
||||
*(r) = (pre)[((n)-1)/2]; \
|
||||
else \
|
||||
(neg)((r), &(pre)[(-(n)-1)/2]); \
|
||||
} while(0)
|
||||
|
||||
template<int W> class WNAFPrecompAff {
|
||||
private:
|
||||
secp256k1_ge_t pre[1 << (W-2)];
|
||||
#define ECMULT_TABLE_GET_GEJ(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_gej_neg)
|
||||
#define ECMULT_TABLE_GET_GE(r,pre,n,w) ECMULT_TABLE_GET((r),(pre),(n),(w),secp256k1_ge_neg)
|
||||
|
||||
public:
|
||||
WNAFPrecompAff() {}
|
||||
|
||||
void Build(const secp256k1_ge_t &base) {
|
||||
pre[0] = base;
|
||||
secp256k1_gej_t x; secp256k1_gej_set_ge(&x, &base);
|
||||
secp256k1_gej_t d; secp256k1_gej_double(&d, &x);
|
||||
for (int i=1; i<(1 << (W-2)); i++) {
|
||||
secp256k1_gej_add_ge(&x, &d, &pre[i-1]);
|
||||
secp256k1_ge_set_gej(&pre[i], &x);
|
||||
}
|
||||
}
|
||||
|
||||
WNAFPrecompAff(const secp256k1_ge_t &base) {
|
||||
Build(base);
|
||||
}
|
||||
|
||||
void Get(secp256k1_ge_t &out, int exp) const {
|
||||
assert((exp & 1) == 1);
|
||||
assert(exp >= -((1 << (W-1)) - 1));
|
||||
assert(exp <= ((1 << (W-1)) - 1));
|
||||
if (exp > 0) {
|
||||
out = pre[(exp-1)/2];
|
||||
} else {
|
||||
secp256k1_ge_neg(&out, &pre[(-exp-1)/2]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<int B> class WNAF {
|
||||
private:
|
||||
int naf[B+1];
|
||||
int used;
|
||||
|
||||
void PushNAF(int num, int zeroes) {
|
||||
assert(used < B+1);
|
||||
for (int i=0; i<zeroes; i++) {
|
||||
naf[used++]=0;
|
||||
}
|
||||
naf[used++]=num;
|
||||
}
|
||||
|
||||
public:
|
||||
WNAF(const secp256k1_num_t &exp, int w) : used(0) {
|
||||
int zeroes = 0;
|
||||
secp256k1_num_t x;
|
||||
secp256k1_num_init(&x);
|
||||
secp256k1_num_copy(&x, &exp);
|
||||
int sign = 1;
|
||||
if (secp256k1_num_is_neg(&x)) {
|
||||
sign = -1;
|
||||
secp256k1_num_negate(&x);
|
||||
}
|
||||
while (!secp256k1_num_is_zero(&x)) {
|
||||
while (!secp256k1_num_is_odd(&x)) {
|
||||
zeroes++;
|
||||
secp256k1_num_shift(&x, 1);
|
||||
}
|
||||
int word = secp256k1_num_shift(&x, w);
|
||||
if (word & (1 << (w-1))) {
|
||||
secp256k1_num_inc(&x);
|
||||
PushNAF(sign * (word - (1 << w)), zeroes);
|
||||
} else {
|
||||
PushNAF(sign * word, zeroes);
|
||||
}
|
||||
zeroes = w-1;
|
||||
}
|
||||
secp256k1_num_free(&x);
|
||||
}
|
||||
|
||||
int GetSize() const {
|
||||
return used;
|
||||
}
|
||||
|
||||
int Get(int pos) const {
|
||||
assert(pos >= 0 && pos < used);
|
||||
return naf[pos];
|
||||
}
|
||||
|
||||
std::string ToString() {
|
||||
std::stringstream ss;
|
||||
ss << "(";
|
||||
for (int i=0; i<GetSize(); i++) {
|
||||
ss << Get(used-1-i);
|
||||
if (i != used-1)
|
||||
ss << ',';
|
||||
}
|
||||
ss << ")";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class ECMultConsts {
|
||||
public:
|
||||
WNAFPrecompAff<WINDOW_G> wpg;
|
||||
WNAFPrecompAff<WINDOW_G> wpg128;
|
||||
typedef struct {
|
||||
secp256k1_ge_t pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; // odd multiples of the generator
|
||||
secp256k1_ge_t pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; // odd multiples of 2^128*generator
|
||||
secp256k1_ge_t prec[64][16]; // prec[j][i] = 16^j * (i+1) * G
|
||||
secp256k1_ge_t fin; // -(sum(prec[j][0], j=0..63))
|
||||
} secp256k1_ecmult_consts_t;
|
||||
|
||||
ECMultConsts() {
|
||||
const secp256k1_ge_t &g = secp256k1_ge_consts->g;
|
||||
secp256k1_gej_t g128j; secp256k1_gej_set_ge(&g128j, &g);
|
||||
for (int i=0; i<128; i++)
|
||||
secp256k1_gej_double(&g128j, &g128j);
|
||||
secp256k1_ge_t g128; secp256k1_ge_set_gej(&g128, &g128j);
|
||||
wpg.Build(g);
|
||||
wpg128.Build(g128);
|
||||
secp256k1_gej_t gg; secp256k1_gej_set_ge(&gg, &g);
|
||||
secp256k1_ge_t ad = g;
|
||||
secp256k1_gej_t fn; secp256k1_gej_set_infinity(&fn);
|
||||
for (int j=0; j<64; j++) {
|
||||
secp256k1_ge_set_gej(&prec[j][0], &gg);
|
||||
secp256k1_gej_add(&fn, &fn, &gg);
|
||||
for (int i=1; i<16; i++) {
|
||||
secp256k1_gej_add_ge(&gg, &gg, &ad);
|
||||
secp256k1_ge_set_gej(&prec[j][i], &gg);
|
||||
}
|
||||
ad = prec[j][15];
|
||||
static secp256k1_ecmult_consts_t *secp256k1_ecmult_consts = NULL;
|
||||
|
||||
static void secp256k1_ecmult_start(void) {
|
||||
if (secp256k1_ecmult_consts != NULL)
|
||||
return;
|
||||
|
||||
secp256k1_ecmult_consts_t *ret = (secp256k1_ecmult_consts_t*)malloc(sizeof(secp256k1_ecmult_consts_t));
|
||||
secp256k1_ecmult_consts = ret;
|
||||
|
||||
// get the generator
|
||||
const secp256k1_ge_t *g = &secp256k1_ge_consts->g;
|
||||
|
||||
// calculate 2^128*generator
|
||||
secp256k1_gej_t g_128j; secp256k1_gej_set_ge(&g_128j, g);
|
||||
for (int i=0; i<128; i++)
|
||||
secp256k1_gej_double(&g_128j, &g_128j);
|
||||
secp256k1_ge_t g_128; secp256k1_ge_set_gej(&g_128, &g_128j);
|
||||
|
||||
// precompute the tables with odd multiples
|
||||
secp256k1_ecmult_table_precomp_ge(ret->pre_g, g, WINDOW_G);
|
||||
secp256k1_ecmult_table_precomp_ge(ret->pre_g_128, &g_128, WINDOW_G);
|
||||
|
||||
// compute prec and fin
|
||||
secp256k1_gej_t gg; secp256k1_gej_set_ge(&gg, g);
|
||||
secp256k1_ge_t ad = *g;
|
||||
secp256k1_gej_t fn; secp256k1_gej_set_infinity(&fn);
|
||||
for (int j=0; j<64; j++) {
|
||||
secp256k1_ge_set_gej(&ret->prec[j][0], &gg);
|
||||
secp256k1_gej_add(&fn, &fn, &gg);
|
||||
for (int i=1; i<16; i++) {
|
||||
secp256k1_gej_add_ge(&gg, &gg, &ad);
|
||||
secp256k1_ge_set_gej(&ret->prec[j][i], &gg);
|
||||
}
|
||||
secp256k1_ge_set_gej(&fin, &fn);
|
||||
secp256k1_ge_neg(&fin, &fin);
|
||||
ad = ret->prec[j][15];
|
||||
}
|
||||
};
|
||||
|
||||
const ECMultConsts &GetECMultConsts() {
|
||||
static const ECMultConsts ecmult_consts;
|
||||
return ecmult_consts;
|
||||
secp256k1_ge_set_gej(&ret->fin, &fn);
|
||||
secp256k1_ge_neg(&ret->fin, &ret->fin);
|
||||
}
|
||||
|
||||
void ECMultBase(secp256k1_gej_t &out, const secp256k1_num_t &gn) {
|
||||
static void secp256k1_ecmult_stop(void) {
|
||||
if (secp256k1_ecmult_consts == NULL)
|
||||
return;
|
||||
|
||||
free(secp256k1_ecmult_consts);
|
||||
secp256k1_ecmult_consts = NULL;
|
||||
}
|
||||
|
||||
/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits),
|
||||
* with the following guarantees:
|
||||
* - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1)
|
||||
* - two non-zero entries in wnaf are separated by at least w-1 zeroes.
|
||||
* - the index of the highest non-zero entry in wnaf (=return value-1) is at most bits, where
|
||||
* bits is the number of bits necessary to represent the absolute value of the input.
|
||||
*/
|
||||
static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_num_t *a, int w) {
|
||||
int ret = 0;
|
||||
int zeroes = 0;
|
||||
secp256k1_num_t x;
|
||||
secp256k1_num_init(&x);
|
||||
secp256k1_num_copy(&x, a);
|
||||
int sign = 1;
|
||||
if (secp256k1_num_is_neg(&x)) {
|
||||
sign = -1;
|
||||
secp256k1_num_negate(&x);
|
||||
}
|
||||
while (!secp256k1_num_is_zero(&x)) {
|
||||
while (!secp256k1_num_is_odd(&x)) {
|
||||
zeroes++;
|
||||
secp256k1_num_shift(&x, 1);
|
||||
}
|
||||
int word = secp256k1_num_shift(&x, w);
|
||||
while (zeroes) {
|
||||
wnaf[ret++] = 0;
|
||||
zeroes--;
|
||||
}
|
||||
if (word & (1 << (w-1))) {
|
||||
secp256k1_num_inc(&x);
|
||||
wnaf[ret++] = sign * (word - (1 << w));
|
||||
} else {
|
||||
wnaf[ret++] = sign * word;
|
||||
}
|
||||
zeroes = w-1;
|
||||
}
|
||||
secp256k1_num_free(&x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void static secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_num_t *gn) {
|
||||
secp256k1_num_t n;
|
||||
secp256k1_num_init(&n);
|
||||
secp256k1_num_copy(&n, &gn);
|
||||
const ECMultConsts &c = GetECMultConsts();
|
||||
secp256k1_gej_set_ge(&out, &c.prec[0][secp256k1_num_shift(&n, 4)]);
|
||||
for (int j=1; j<64; j++) {
|
||||
secp256k1_gej_add_ge(&out, &out, &c.prec[j][secp256k1_num_shift(&n, 4)]);
|
||||
}
|
||||
secp256k1_num_copy(&n, gn);
|
||||
const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts;
|
||||
secp256k1_gej_set_ge(r, &c->prec[0][secp256k1_num_shift(&n, 4)]);
|
||||
for (int j=1; j<64; j++)
|
||||
secp256k1_gej_add_ge(r, r, &c->prec[j][secp256k1_num_shift(&n, 4)]);
|
||||
secp256k1_num_free(&n);
|
||||
secp256k1_gej_add_ge(&out, &out, &c.fin);
|
||||
secp256k1_gej_add_ge(r, r, &c->fin);
|
||||
}
|
||||
|
||||
void ECMult(secp256k1_gej_t &out, const secp256k1_gej_t &a, const secp256k1_num_t &an, const secp256k1_num_t &gn) {
|
||||
secp256k1_num_t an1, an2;
|
||||
secp256k1_num_t gn1, gn2;
|
||||
void static secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_num_t *na, const secp256k1_num_t *ng) {
|
||||
const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts;
|
||||
|
||||
secp256k1_num_init(&an1);
|
||||
secp256k1_num_init(&an2);
|
||||
secp256k1_num_init(&gn1);
|
||||
secp256k1_num_init(&gn2);
|
||||
secp256k1_num_t na_1, na_lam;
|
||||
secp256k1_num_t ng_1, ng_128;
|
||||
secp256k1_num_init(&na_1);
|
||||
secp256k1_num_init(&na_lam);
|
||||
secp256k1_num_init(&ng_1);
|
||||
secp256k1_num_init(&ng_128);
|
||||
|
||||
secp256k1_gej_split_exp(&an1, &an2, &an);
|
||||
// printf("an=%s\n", an.ToString().c_str());
|
||||
// printf("an1=%s\n", an1.ToString().c_str());
|
||||
// printf("an2=%s\n", an2.ToString().c_str());
|
||||
// printf("an1.len=%i\n", an1.GetBits());
|
||||
// printf("an2.len=%i\n", an2.GetBits());
|
||||
secp256k1_num_split(&gn1, &gn2, &gn, 128);
|
||||
// split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit)
|
||||
secp256k1_gej_split_exp(&na_1, &na_lam, na);
|
||||
// split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit)
|
||||
secp256k1_num_split(&ng_1, &ng_128, ng, 128);
|
||||
|
||||
WNAF<128> wa1(an1, WINDOW_A);
|
||||
WNAF<128> wa2(an2, WINDOW_A);
|
||||
WNAF<128> wg1(gn1, WINDOW_G);
|
||||
WNAF<128> wg2(gn2, WINDOW_G);
|
||||
secp256k1_gej_t a2; secp256k1_gej_mul_lambda(&a2, &a);
|
||||
WNAFPrecompJac<WINDOW_A> wpa1(a);
|
||||
WNAFPrecompJac<WINDOW_A> wpa2(a2);
|
||||
const ECMultConsts &c = GetECMultConsts();
|
||||
// build wnaf representation for na_1, na_lam, ng_1, ng_128
|
||||
int wnaf_na_1[129]; int bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A);
|
||||
int wnaf_na_lam[129]; int bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A);
|
||||
int wnaf_ng_1[129]; int bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G);
|
||||
int wnaf_ng_128[129]; int bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G);
|
||||
|
||||
int size_a1 = wa1.GetSize();
|
||||
int size_a2 = wa2.GetSize();
|
||||
int size_g1 = wg1.GetSize();
|
||||
int size_g2 = wg2.GetSize();
|
||||
int size = std::max(std::max(size_a1, size_a2), std::max(size_g1, size_g2));
|
||||
// calculate a_lam = a*lambda
|
||||
secp256k1_gej_t a_lam; secp256k1_gej_mul_lambda(&a_lam, a);
|
||||
|
||||
out; secp256k1_gej_set_infinity(&out);
|
||||
// calculate odd multiples of a and a_lam
|
||||
secp256k1_gej_t pre_a_1[ECMULT_TABLE_SIZE(WINDOW_A)], pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
secp256k1_ecmult_table_precomp_gej(pre_a_1, a, WINDOW_A);
|
||||
secp256k1_ecmult_table_precomp_gej(pre_a_lam, &a_lam, WINDOW_A);
|
||||
|
||||
int bits = std::max(std::max(bits_na_1, bits_na_lam), std::max(bits_ng_1, bits_ng_128));
|
||||
|
||||
secp256k1_gej_set_infinity(r);
|
||||
secp256k1_gej_t tmpj;
|
||||
secp256k1_ge_t tmpa;
|
||||
|
||||
for (int i=size-1; i>=0; i--) {
|
||||
secp256k1_gej_double(&out, &out);
|
||||
int nw;
|
||||
if (i < size_a1 && (nw = wa1.Get(i))) {
|
||||
wpa1.Get(tmpj, nw);
|
||||
secp256k1_gej_add(&out, &out, &tmpj);
|
||||
for (int i=bits-1; i>=0; i--) {
|
||||
secp256k1_gej_double(r, r);
|
||||
int n;
|
||||
if (i < bits_na_1 && (n = wnaf_na_1[i])) {
|
||||
ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_1, n, WINDOW_A);
|
||||
secp256k1_gej_add(r, r, &tmpj);
|
||||
}
|
||||
if (i < size_a2 && (nw = wa2.Get(i))) {
|
||||
wpa2.Get(tmpj, nw);
|
||||
secp256k1_gej_add(&out, &out, &tmpj);
|
||||
if (i < bits_na_lam && (n = wnaf_na_lam[i])) {
|
||||
ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_lam, n, WINDOW_A);
|
||||
secp256k1_gej_add(r, r, &tmpj);
|
||||
}
|
||||
if (i < size_g1 && (nw = wg1.Get(i))) {
|
||||
c.wpg.Get(tmpa, nw);
|
||||
secp256k1_gej_add_ge(&out, &out, &tmpa);
|
||||
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
|
||||
ECMULT_TABLE_GET_GE(&tmpa, c->pre_g, n, WINDOW_G);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
}
|
||||
if (i < size_g2 && (nw = wg2.Get(i))) {
|
||||
c.wpg128.Get(tmpa, nw);
|
||||
secp256k1_gej_add_ge(&out, &out, &tmpa);
|
||||
if (i < bits_ng_128 && (n = wnaf_ng_128[i])) {
|
||||
ECMULT_TABLE_GET_GE(&tmpa, c->pre_g_128, n, WINDOW_G);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
}
|
||||
}
|
||||
|
||||
secp256k1_num_free(&an1);
|
||||
secp256k1_num_free(&an2);
|
||||
secp256k1_num_free(&gn1);
|
||||
secp256k1_num_free(&gn2);
|
||||
secp256k1_num_free(&na_1);
|
||||
secp256k1_num_free(&na_lam);
|
||||
secp256k1_num_free(&ng_1);
|
||||
secp256k1_num_free(&ng_128);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
11
src/ecmult.h
11
src/ecmult.h
|
@ -4,10 +4,15 @@
|
|||
#include "num.h"
|
||||
#include "group.h"
|
||||
|
||||
namespace secp256k1 {
|
||||
extern "C" {
|
||||
|
||||
void ECMultBase(secp256k1_gej_t &out, const secp256k1_num_t &gn);
|
||||
void ECMult(secp256k1_gej_t &out, const secp256k1_gej_t &a, const secp256k1_num_t &an, const secp256k1_num_t &gn);
|
||||
static void secp256k1_ecmult_start(void);
|
||||
static void secp256k1_ecmult_stop(void);
|
||||
|
||||
/** Multiply with the generator: R = a*G */
|
||||
static void secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_num_t *a);
|
||||
/** Double multiply: R = na*A + ng*G */
|
||||
static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_num_t *na, const secp256k1_num_t *ng);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,183 +0,0 @@
|
|||
#include <assert.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#include "num_openssl.h"
|
||||
|
||||
namespace secp256k1 {
|
||||
|
||||
class Context {
|
||||
private:
|
||||
BN_CTX *ctx;
|
||||
|
||||
operator BN_CTX*() {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
friend class Number;
|
||||
public:
|
||||
Context() {
|
||||
ctx = BN_CTX_new();
|
||||
}
|
||||
|
||||
~Context() {
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
};
|
||||
|
||||
Number::operator const BIGNUM*() const {
|
||||
return &b;
|
||||
}
|
||||
|
||||
Number::operator BIGNUM*() {
|
||||
return &b;
|
||||
}
|
||||
|
||||
Number::Number() {
|
||||
BN_init(*this);
|
||||
}
|
||||
|
||||
Number::~Number() {
|
||||
BN_free(*this);
|
||||
}
|
||||
|
||||
Number::Number(const unsigned char *bin, int len) {
|
||||
BN_init(*this);
|
||||
SetBytes(bin,len);
|
||||
}
|
||||
|
||||
void Number::SetNumber(const Number &x) {
|
||||
BN_copy(*this, x);
|
||||
}
|
||||
|
||||
Number::Number(const Number &x) {
|
||||
BN_init(*this);
|
||||
BN_copy(*this, x);
|
||||
}
|
||||
|
||||
Number &Number::operator=(const Number &x) {
|
||||
BN_copy(*this, x);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Number::SetBytes(const unsigned char *bin, int len) {
|
||||
BN_bin2bn(bin, len, *this);
|
||||
}
|
||||
|
||||
void Number::GetBytes(unsigned char *bin, int len) {
|
||||
int size = BN_num_bytes(*this);
|
||||
assert(size <= len);
|
||||
memset(bin,0,len);
|
||||
BN_bn2bin(*this, bin + len - size);
|
||||
}
|
||||
|
||||
void Number::SetInt(int x) {
|
||||
if (x >= 0) {
|
||||
BN_set_word(*this, x);
|
||||
} else {
|
||||
BN_set_word(*this, -x);
|
||||
BN_set_negative(*this, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Number::SetModInverse(const Number &x, const Number &m) {
|
||||
Context ctx;
|
||||
BN_mod_inverse(*this, x, m, ctx);
|
||||
}
|
||||
|
||||
void Number::SetModMul(const Number &a, const Number &b, const Number &m) {
|
||||
Context ctx;
|
||||
BN_mod_mul(*this, a, b, m, ctx);
|
||||
}
|
||||
|
||||
void Number::SetAdd(const Number &a1, const Number &a2) {
|
||||
BN_add(*this, a1, a2);
|
||||
}
|
||||
|
||||
void Number::SetSub(const Number &a1, const Number &a2) {
|
||||
BN_sub(*this, a1, a2);
|
||||
}
|
||||
|
||||
void Number::SetMult(const Number &a1, const Number &a2) {
|
||||
Context ctx;
|
||||
BN_mul(*this, a1, a2, ctx);
|
||||
}
|
||||
|
||||
void Number::SetDiv(const Number &a1, const Number &a2) {
|
||||
Context ctx;
|
||||
BN_div(*this, NULL, a1, a2, ctx);
|
||||
}
|
||||
|
||||
void Number::SetMod(const Number &a, const Number &m) {
|
||||
Context ctx;
|
||||
BN_nnmod(*this, a, m, ctx);
|
||||
}
|
||||
|
||||
int Number::Compare(const Number &a) const {
|
||||
return BN_cmp(*this, a);
|
||||
}
|
||||
|
||||
int Number::GetBits() const {
|
||||
return BN_num_bits(*this);
|
||||
}
|
||||
|
||||
int Number::ShiftLowBits(int bits) {
|
||||
BIGNUM *bn = *this;
|
||||
int ret = BN_is_zero(bn) ? 0 : bn->d[0] & ((1 << bits) - 1);
|
||||
BN_rshift(*this, *this, bits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Number::IsZero() const {
|
||||
return BN_is_zero((const BIGNUM*)*this);
|
||||
}
|
||||
|
||||
bool Number::IsOdd() const {
|
||||
return BN_is_odd((const BIGNUM*)*this);
|
||||
}
|
||||
|
||||
bool Number::CheckBit(int pos) const {
|
||||
return BN_is_bit_set((const BIGNUM*)*this, pos);
|
||||
}
|
||||
|
||||
bool Number::IsNeg() const {
|
||||
return BN_is_negative((const BIGNUM*)*this);
|
||||
}
|
||||
|
||||
void Number::Negate() {
|
||||
BN_set_negative(*this, !IsNeg());
|
||||
}
|
||||
|
||||
void Number::Shift1() {
|
||||
BN_rshift1(*this,*this);
|
||||
}
|
||||
|
||||
void Number::Inc() {
|
||||
BN_add_word(*this,1);
|
||||
}
|
||||
|
||||
void Number::SetHex(const std::string &str) {
|
||||
BIGNUM *bn = *this;
|
||||
BN_hex2bn(&bn, str.c_str());
|
||||
}
|
||||
|
||||
void Number::SetPseudoRand(const Number &max) {
|
||||
BN_pseudo_rand_range(*this, max);
|
||||
}
|
||||
|
||||
void Number::SplitInto(int bits, Number &low, Number &high) const {
|
||||
BN_copy(low, *this);
|
||||
BN_mask_bits(low, bits);
|
||||
BN_rshift(high, *this, bits);
|
||||
}
|
||||
|
||||
std::string Number::ToString() const {
|
||||
char *str = BN_bn2hex(*this);
|
||||
std::string ret(str);
|
||||
OPENSSL_free(str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
|
@ -11,10 +11,11 @@ extern "C" void secp256k1_start(void) {
|
|||
secp256k1_num_start();
|
||||
secp256k1_fe_start();
|
||||
secp256k1_ge_start();
|
||||
GetECMultConsts();
|
||||
secp256k1_ecmult_start();
|
||||
}
|
||||
|
||||
extern "C" void secp256k1_stop(void) {
|
||||
secp256k1_ecmult_stop();
|
||||
secp256k1_ge_stop();
|
||||
secp256k1_fe_stop();
|
||||
secp256k1_num_stop();
|
||||
|
|
|
@ -42,7 +42,7 @@ void test_run_ecmult_chain() {
|
|||
const secp256k1_num_t *order = &secp256k1_ge_consts->order;
|
||||
for (int i=0; i<200*COUNT; i++) {
|
||||
// in each iteration, compute X = xn*X + gn*G;
|
||||
ECMult(x, x, xn, gn);
|
||||
secp256k1_ecmult(&x, &x, &xn, &gn);
|
||||
// also compute ae and ge: the actual accumulated factors for A and G
|
||||
// if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G)
|
||||
secp256k1_num_mod_mul(&ae, &ae, &xn, order);
|
||||
|
@ -59,7 +59,7 @@ void test_run_ecmult_chain() {
|
|||
assert(strcmp(res, "(D6E96687F9B10D092A6F35439D86CEBEA4535D0D409F53586440BD74B933E830,B95CBCA2C77DA786539BE8FD53354D2D3B4F566AE658045407ED6015EE1B2A88)") == 0);
|
||||
}
|
||||
// redo the computation, but directly with the resulting ae and ge coefficients:
|
||||
secp256k1_gej_t x2; ECMult(x2, a, ae, ge);
|
||||
secp256k1_gej_t x2; secp256k1_ecmult(&x2, &a, &ae, &ge);
|
||||
char res2[132]; int resl2 = 132;
|
||||
secp256k1_gej_get_hex(res2, &resl2, &x2);
|
||||
assert(strcmp(res, res2) == 0);
|
||||
|
@ -82,7 +82,7 @@ void test_point_times_order(const secp256k1_gej_t &point) {
|
|||
secp256k1_num_init(&zero);
|
||||
secp256k1_num_set_int(&zero, 0);
|
||||
secp256k1_gej_t res;
|
||||
ECMult(res, point, *order, zero); // calc res = order * point + 0 * G;
|
||||
secp256k1_ecmult(&res, &point, order, order); // calc res = order * point + order * G;
|
||||
assert(secp256k1_gej_is_infinity(&res));
|
||||
secp256k1_num_free(&zero);
|
||||
}
|
||||
|
@ -106,11 +106,12 @@ void test_wnaf(const secp256k1_num_t &number, int w) {
|
|||
secp256k1_num_init(&t);
|
||||
secp256k1_num_set_int(&x, 0);
|
||||
secp256k1_num_set_int(&two, 2);
|
||||
WNAF<1023> wnaf(number, w);
|
||||
int wnaf[1024];
|
||||
int bits = secp256k1_ecmult_wnaf(wnaf, &number, w);
|
||||
int zeroes = -1;
|
||||
for (int i=wnaf.GetSize()-1; i>=0; i--) {
|
||||
for (int i=bits-1; i>=0; i--) {
|
||||
secp256k1_num_mul(&x, &x, &two);
|
||||
int v = wnaf.Get(i);
|
||||
int v = wnaf[i];
|
||||
if (v) {
|
||||
assert(zeroes == -1 || zeroes >= w-1); // check that distance between non-zero elements is at least w-1
|
||||
zeroes=0;
|
||||
|
@ -157,7 +158,7 @@ void test_ecdsa_sign_verify() {
|
|||
secp256k1_num_init(&key);
|
||||
secp256k1_num_set_rand(&key, &c.order);
|
||||
secp256k1_num_init(&nonce);
|
||||
secp256k1_gej_t pub; ECMultBase(pub, key);
|
||||
secp256k1_gej_t pub; secp256k1_ecmult_gen(&pub, &key);
|
||||
Signature sig;
|
||||
do {
|
||||
secp256k1_num_set_rand(&nonce, &c.order);
|
||||
|
@ -180,12 +181,14 @@ int main(void) {
|
|||
secp256k1_num_start();
|
||||
secp256k1_fe_start();
|
||||
secp256k1_ge_start();
|
||||
secp256k1_ecmult_start();
|
||||
|
||||
test_run_wnaf();
|
||||
test_run_point_times_order();
|
||||
test_run_ecmult_chain();
|
||||
test_run_ecdsa_sign_verify();
|
||||
|
||||
secp256k1_ecmult_stop();
|
||||
secp256k1_ge_stop();
|
||||
secp256k1_fe_stop();
|
||||
secp256k1_num_stop();
|
||||
|
|
Loading…
Add table
Reference in a new issue