bitcoin/ecmult.h

188 lines
4.4 KiB
C
Raw Normal View History

2013-03-08 02:52:50 +01:00
#ifndef _SECP256K1_ECMULT_
#define _SECP256K1_ECMULT_
2013-03-09 22:47:40 +01:00
#include <sstream>
#include <algorithm>
2013-03-08 02:52:50 +01:00
#include "group.h"
2013-03-10 04:24:00 +01:00
#include "num.h"
2013-03-08 02:52:50 +01:00
2013-03-10 01:49:42 +01:00
#define WINDOW_A 5
2013-03-11 01:19:24 +01:00
#define WINDOW_G 13
2013-03-10 01:49:42 +01:00
2013-03-08 02:52:50 +01:00
namespace secp256k1 {
template<typename G, int W> class WNAFPrecomp {
private:
G pre[1 << (W-2)];
public:
2013-03-10 04:24:00 +01:00
WNAFPrecomp() {}
void Build(const G &base) {
2013-03-08 02:52:50 +01:00
pre[0] = base;
2013-03-10 01:49:42 +01:00
GroupElemJac x(base);
2013-03-08 02:52:50 +01:00
GroupElemJac d; d.SetDouble(x);
for (int i=1; i<(1 << (W-2)); i++) {
x.SetAdd(d,pre[i-1]);
2013-03-09 22:47:40 +01:00
pre[i].SetJac(x);
2013-03-08 02:52:50 +01:00
}
}
2013-03-10 04:24:00 +01:00
WNAFPrecomp(const G &base) {
Build(base);
}
2013-03-09 22:47:40 +01:00
void Get(G &out, int exp) const {
2013-03-08 02:52:50 +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-10 01:49:42 +01:00
out.SetNeg(pre[(-exp-1)/2]);
2013-03-08 02:52:50 +01:00
}
}
};
2013-03-09 22:47:40 +01:00
template<int B> class WNAF {
2013-03-08 02:52:50 +01:00
private:
2013-03-09 22:47:40 +01:00
int naf[B+1];
int used;
void PushNAF(int num, int zeroes) {
2013-03-11 01:19:24 +01:00
assert(used < B+1);
2013-03-09 22:47:40 +01:00
for (int i=0; i<zeroes; i++) {
naf[used++]=0;
}
naf[used++]=num;
}
public:
2013-03-10 04:24:00 +01:00
WNAF(Context &ctx, const Number &exp, int w) : used(0) {
2013-03-09 22:47:40 +01:00
int zeroes = 0;
2013-03-10 01:49:42 +01:00
Context ct(ctx);
2013-03-10 04:24:00 +01:00
Number x(ct);
2013-03-10 01:49:42 +01:00
x.SetNumber(exp);
2013-03-10 04:24:00 +01:00
int sign = 1;
if (x.IsNeg()) {
sign = -1;
x.Negate();
}
2013-03-10 01:49:42 +01:00
while (!x.IsZero()) {
while (!x.IsOdd()) {
2013-03-09 22:47:40 +01:00
zeroes++;
2013-03-10 01:49:42 +01:00
x.Shift1();
2013-03-09 22:47:40 +01:00
}
2013-03-11 01:19:24 +01:00
int word = x.ShiftLowBits(ct,w);
2013-03-09 22:47:40 +01:00
if (word & (1 << (w-1))) {
2013-03-10 01:49:42 +01:00
x.Inc();
2013-03-10 04:24:00 +01:00
PushNAF(sign * (word - (1 << w)), zeroes);
2013-03-09 22:47:40 +01:00
} else {
2013-03-10 04:24:00 +01:00
PushNAF(sign * word, zeroes);
2013-03-09 22:47:40 +01:00
}
zeroes = w-1;
}
}
int GetSize() const {
return used;
}
int Get(int pos) const {
2013-03-10 01:49:42 +01:00
assert(pos >= 0 && pos < used);
return naf[pos];
2013-03-09 22:47:40 +01:00
}
std::string ToString() {
std::stringstream ss;
ss << "(";
for (int i=0; i<GetSize(); i++) {
2013-03-10 01:49:42 +01:00
ss << Get(used-1-i);
2013-03-09 22:47:40 +01:00
if (i != used-1)
ss << ',';
}
ss << ")";
return ss.str();
}
};
class ECMultConsts {
public:
2013-03-10 04:24:00 +01:00
WNAFPrecomp<GroupElem,WINDOW_G> wpg;
WNAFPrecomp<GroupElem,WINDOW_G> wpg128;
ECMultConsts() {
const GroupElem &g = GetGroupConst().g;
GroupElemJac g128j(g);
for (int i=0; i<128; i++)
g128j.SetDouble(g128j);
GroupElem g128; g128.SetJac(g128j);
wpg.Build(g);
wpg128.Build(g128);
}
2013-03-08 02:52:50 +01:00
};
2013-03-09 22:47:40 +01:00
const ECMultConsts &GetECMultConsts() {
static const ECMultConsts ecmult_consts;
return ecmult_consts;
}
2013-03-11 01:19:24 +01:00
void ECMult(Context &ctx, GroupElemJac &out, const GroupElemJac &a, const Number &an, const Number &gn) {
2013-03-10 04:24:00 +01:00
Context ct(ctx);
Number an1(ct), an2(ct);
Number gn1(ct), gn2(ct);
SplitExp(ct, an, an1, an2);
// 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());
gn.SplitInto(ct, 128, gn1, gn2);
WNAF<129> wa1(ct, an1, WINDOW_A);
WNAF<129> wa2(ct, an2, WINDOW_A);
WNAF<128> wg1(ct, gn1, WINDOW_G);
WNAF<128> wg2(ct, gn2, WINDOW_G);
GroupElemJac a2; a2.SetMulLambda(a);
WNAFPrecomp<GroupElemJac,WINDOW_A> wpa1(a);
WNAFPrecomp<GroupElemJac,WINDOW_A> wpa2(a2);
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-09 22:47:40 +01:00
out = GroupElemJac();
GroupElemJac tmpj;
GroupElem tmpa;
2013-03-10 01:49:42 +01:00
for (int i=size-1; i>=0; i--) {
2013-03-09 22:47:40 +01:00
out.SetDouble(out);
2013-03-10 01:49:42 +01:00
int nw;
2013-03-10 04:24:00 +01:00
if (i < size_a1 && (nw = wa1.Get(i))) {
wpa1.Get(tmpj, nw);
out.SetAdd(out, tmpj);
}
if (i < size_a2 && (nw = wa2.Get(i))) {
wpa2.Get(tmpj, nw);
2013-03-09 22:47:40 +01:00
out.SetAdd(out, tmpj);
}
2013-03-10 04:24:00 +01:00
if (i < size_g1 && (nw = wg1.Get(i))) {
c.wpg.Get(tmpa, nw);
out.SetAdd(out, tmpa);
}
if (i < size_g2 && (nw = wg2.Get(i))) {
c.wpg128.Get(tmpa, nw);
2013-03-09 22:47:40 +01:00
out.SetAdd(out, tmpa);
}
}
}
2013-03-08 02:52:50 +01:00
}
#endif