2013-03-16 15:51:55 +01:00
|
|
|
#include <sstream>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#include "num.h"
|
|
|
|
#include "group.h"
|
|
|
|
#include "ecmult.h"
|
|
|
|
|
|
|
|
// optimal for 128-bit and 256-bit exponents
|
|
|
|
#define WINDOW_A 5
|
|
|
|
|
|
|
|
// larger numbers may result in slightly better performance, at the cost of
|
|
|
|
// exponentially larger precomputed tables. WINDOW_G == 13 results in 640 KiB.
|
|
|
|
#define WINDOW_G 14
|
|
|
|
|
|
|
|
namespace secp256k1 {
|
|
|
|
|
2013-03-31 17:02:52 +02:00
|
|
|
template<int W> class WNAFPrecompJac {
|
2013-03-16 15:51:55 +01:00
|
|
|
private:
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_t pre[1 << (W-2)];
|
2013-03-16 15:51:55 +01:00
|
|
|
|
|
|
|
public:
|
2013-03-31 17:02:52 +02:00
|
|
|
WNAFPrecompJac() {}
|
2013-03-16 15:51:55 +01:00
|
|
|
|
2013-03-31 17:02:52 +02:00
|
|
|
void Build(const secp256k1_gej_t &base) {
|
2013-03-16 15:51:55 +01:00
|
|
|
pre[0] = base;
|
2013-03-31 17:02:52 +02:00
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
|
|
|
WNAFPrecompJac(const secp256k1_gej_t &base) {
|
|
|
|
Build(base);
|
|
|
|
}
|
|
|
|
|
|
|
|
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]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<int W> class WNAFPrecompAff {
|
|
|
|
private:
|
|
|
|
secp256k1_ge_t pre[1 << (W-2)];
|
|
|
|
|
|
|
|
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);
|
2013-03-16 15:51:55 +01:00
|
|
|
for (int i=1; i<(1 << (W-2)); i++) {
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_add_ge(&x, &d, &pre[i-1]);
|
|
|
|
secp256k1_ge_set_gej(&pre[i], &x);
|
2013-03-16 15:51:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-31 17:02:52 +02:00
|
|
|
WNAFPrecompAff(const secp256k1_ge_t &base) {
|
2013-03-16 15:51:55 +01:00
|
|
|
Build(base);
|
|
|
|
}
|
|
|
|
|
2013-03-31 17:02:52 +02:00
|
|
|
void Get(secp256k1_ge_t &out, int exp) const {
|
2013-03-16 15:51:55 +01:00
|
|
|
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 {
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_ge_neg(&out, &pre[(-exp-1)/2]);
|
2013-03-16 15:51:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
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:
|
2013-03-24 10:38:35 +01:00
|
|
|
WNAF(const secp256k1_num_t &exp, int w) : used(0) {
|
2013-03-16 15:51:55 +01:00
|
|
|
int zeroes = 0;
|
2013-03-24 10:38:35 +01:00
|
|
|
secp256k1_num_t x;
|
|
|
|
secp256k1_num_init(&x);
|
|
|
|
secp256k1_num_copy(&x, &exp);
|
2013-03-16 15:51:55 +01:00
|
|
|
int sign = 1;
|
2013-03-24 10:38:35 +01:00
|
|
|
if (secp256k1_num_is_neg(&x)) {
|
2013-03-16 15:51:55 +01:00
|
|
|
sign = -1;
|
2013-03-24 10:38:35 +01:00
|
|
|
secp256k1_num_negate(&x);
|
2013-03-16 15:51:55 +01:00
|
|
|
}
|
2013-03-24 10:38:35 +01:00
|
|
|
while (!secp256k1_num_is_zero(&x)) {
|
|
|
|
while (!secp256k1_num_is_odd(&x)) {
|
2013-03-16 15:51:55 +01:00
|
|
|
zeroes++;
|
2013-03-24 10:38:35 +01:00
|
|
|
secp256k1_num_shift(&x, 1);
|
2013-03-16 15:51:55 +01:00
|
|
|
}
|
2013-03-24 10:38:35 +01:00
|
|
|
int word = secp256k1_num_shift(&x, w);
|
2013-03-16 15:51:55 +01:00
|
|
|
if (word & (1 << (w-1))) {
|
2013-03-24 10:38:35 +01:00
|
|
|
secp256k1_num_inc(&x);
|
2013-03-16 15:51:55 +01:00
|
|
|
PushNAF(sign * (word - (1 << w)), zeroes);
|
|
|
|
} else {
|
|
|
|
PushNAF(sign * word, zeroes);
|
|
|
|
}
|
|
|
|
zeroes = w-1;
|
|
|
|
}
|
2013-03-24 10:38:35 +01:00
|
|
|
secp256k1_num_free(&x);
|
2013-03-16 15:51:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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:
|
2013-03-31 17:02:52 +02:00
|
|
|
WNAFPrecompAff<WINDOW_G> wpg;
|
|
|
|
WNAFPrecompAff<WINDOW_G> wpg128;
|
|
|
|
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))
|
2013-03-16 15:51:55 +01:00
|
|
|
|
|
|
|
ECMultConsts() {
|
2013-03-31 17:02:52 +02:00
|
|
|
const secp256k1_ge_t &g = secp256k1_ge_consts->g;
|
|
|
|
secp256k1_gej_t g128j; secp256k1_gej_set_ge(&g128j, &g);
|
2013-03-16 15:51:55 +01:00
|
|
|
for (int i=0; i<128; i++)
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_double(&g128j, &g128j);
|
|
|
|
secp256k1_ge_t g128; secp256k1_ge_set_gej(&g128, &g128j);
|
2013-03-16 15:51:55 +01:00
|
|
|
wpg.Build(g);
|
|
|
|
wpg128.Build(g128);
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_t gg; secp256k1_gej_set_ge(&gg, &g);
|
|
|
|
secp256k1_ge_t ad = g;
|
|
|
|
secp256k1_gej_t fn; secp256k1_gej_set_infinity(&fn);
|
2013-03-18 02:41:01 +01:00
|
|
|
for (int j=0; j<64; j++) {
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_ge_set_gej(&prec[j][0], &gg);
|
|
|
|
secp256k1_gej_add(&fn, &fn, &gg);
|
2013-03-18 02:41:01 +01:00
|
|
|
for (int i=1; i<16; i++) {
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_add_ge(&gg, &gg, &ad);
|
|
|
|
secp256k1_ge_set_gej(&prec[j][i], &gg);
|
2013-03-18 02:41:01 +01:00
|
|
|
}
|
|
|
|
ad = prec[j][15];
|
|
|
|
}
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_ge_set_gej(&fin, &fn);
|
|
|
|
secp256k1_ge_neg(&fin, &fin);
|
2013-03-16 15:51:55 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const ECMultConsts &GetECMultConsts() {
|
|
|
|
static const ECMultConsts ecmult_consts;
|
|
|
|
return ecmult_consts;
|
|
|
|
}
|
|
|
|
|
2013-03-31 17:02:52 +02:00
|
|
|
void ECMultBase(secp256k1_gej_t &out, const secp256k1_num_t &gn) {
|
2013-03-24 10:38:35 +01:00
|
|
|
secp256k1_num_t n;
|
|
|
|
secp256k1_num_init(&n);
|
|
|
|
secp256k1_num_copy(&n, &gn);
|
2013-03-18 02:41:01 +01:00
|
|
|
const ECMultConsts &c = GetECMultConsts();
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_set_ge(&out, &c.prec[0][secp256k1_num_shift(&n, 4)]);
|
2013-03-18 02:41:01 +01:00
|
|
|
for (int j=1; j<64; j++) {
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_add_ge(&out, &out, &c.prec[j][secp256k1_num_shift(&n, 4)]);
|
2013-03-18 02:41:01 +01:00
|
|
|
}
|
2013-03-24 10:38:35 +01:00
|
|
|
secp256k1_num_free(&n);
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_add_ge(&out, &out, &c.fin);
|
2013-03-18 02:41:01 +01:00
|
|
|
}
|
|
|
|
|
2013-03-31 17:02:52 +02:00
|
|
|
void ECMult(secp256k1_gej_t &out, const secp256k1_gej_t &a, const secp256k1_num_t &an, const secp256k1_num_t &gn) {
|
2013-03-24 10:38:35 +01:00
|
|
|
secp256k1_num_t an1, an2;
|
|
|
|
secp256k1_num_t gn1, gn2;
|
|
|
|
|
|
|
|
secp256k1_num_init(&an1);
|
|
|
|
secp256k1_num_init(&an2);
|
|
|
|
secp256k1_num_init(&gn1);
|
|
|
|
secp256k1_num_init(&gn2);
|
2013-03-16 15:51:55 +01:00
|
|
|
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_split_exp(&an1, &an2, &an);
|
2013-03-16 15:51:55 +01:00
|
|
|
// 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());
|
2013-03-24 10:38:35 +01:00
|
|
|
secp256k1_num_split(&gn1, &gn2, &gn, 128);
|
2013-03-16 15:51:55 +01:00
|
|
|
|
|
|
|
WNAF<128> wa1(an1, WINDOW_A);
|
|
|
|
WNAF<128> wa2(an2, WINDOW_A);
|
|
|
|
WNAF<128> wg1(gn1, WINDOW_G);
|
|
|
|
WNAF<128> wg2(gn2, WINDOW_G);
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_t a2; secp256k1_gej_mul_lambda(&a2, &a);
|
|
|
|
WNAFPrecompJac<WINDOW_A> wpa1(a);
|
|
|
|
WNAFPrecompJac<WINDOW_A> wpa2(a2);
|
2013-03-16 15:51:55 +01:00
|
|
|
const ECMultConsts &c = GetECMultConsts();
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
2013-03-31 17:02:52 +02:00
|
|
|
out; secp256k1_gej_set_infinity(&out);
|
|
|
|
secp256k1_gej_t tmpj;
|
|
|
|
secp256k1_ge_t tmpa;
|
2013-03-16 15:51:55 +01:00
|
|
|
|
|
|
|
for (int i=size-1; i>=0; i--) {
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_double(&out, &out);
|
2013-03-16 15:51:55 +01:00
|
|
|
int nw;
|
|
|
|
if (i < size_a1 && (nw = wa1.Get(i))) {
|
|
|
|
wpa1.Get(tmpj, nw);
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_add(&out, &out, &tmpj);
|
2013-03-16 15:51:55 +01:00
|
|
|
}
|
|
|
|
if (i < size_a2 && (nw = wa2.Get(i))) {
|
|
|
|
wpa2.Get(tmpj, nw);
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_add(&out, &out, &tmpj);
|
2013-03-16 15:51:55 +01:00
|
|
|
}
|
|
|
|
if (i < size_g1 && (nw = wg1.Get(i))) {
|
|
|
|
c.wpg.Get(tmpa, nw);
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_add_ge(&out, &out, &tmpa);
|
2013-03-16 15:51:55 +01:00
|
|
|
}
|
|
|
|
if (i < size_g2 && (nw = wg2.Get(i))) {
|
|
|
|
c.wpg128.Get(tmpa, nw);
|
2013-03-31 17:02:52 +02:00
|
|
|
secp256k1_gej_add_ge(&out, &out, &tmpa);
|
2013-03-16 15:51:55 +01:00
|
|
|
}
|
|
|
|
}
|
2013-03-24 10:38:35 +01:00
|
|
|
|
|
|
|
secp256k1_num_free(&an1);
|
|
|
|
secp256k1_num_free(&an2);
|
|
|
|
secp256k1_num_free(&gn1);
|
|
|
|
secp256k1_num_free(&gn2);
|
2013-03-16 15:51:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|