Source tree reorganization

This commit is contained in:
Pieter Wuille
2013-03-31 05:03:27 +02:00
parent 938d3c27aa
commit 2d93809255
26 changed files with 29 additions and 21 deletions

43
src/bench.cpp Normal file
View File

@@ -0,0 +1,43 @@
#include <stdio.h>
#include "num.cpp"
#include "field.cpp"
#include "group.cpp"
#include "ecmult.cpp"
#include "ecdsa.cpp"
using namespace secp256k1;
int main() {
secp256k1_num_start();
secp256k1_fe_start();
secp256k1_fe_t x;
const secp256k1_num_t &order = GetGroupConst().order;
secp256k1_num_t r, s, m;
secp256k1_num_init(&r);
secp256k1_num_init(&s);
secp256k1_num_init(&m);
Signature sig;
secp256k1_fe_set_hex(&x, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64);
int cnt = 0;
int good = 0;
for (int i=0; i<1000000; i++) {
secp256k1_num_set_rand(&r, &order);
secp256k1_num_set_rand(&s, &order);
secp256k1_num_set_rand(&m, &order);
sig.SetRS(r,s);
GroupElemJac pubkey; pubkey.SetCompressed(x, true);
if (pubkey.IsValid()) {
cnt++;
good += sig.Verify(pubkey, m);
}
}
printf("%i/%i\n", good, cnt);
secp256k1_num_free(&r);
secp256k1_num_free(&s);
secp256k1_num_free(&m);
secp256k1_fe_stop();
return 0;
}

145
src/ecdsa.cpp Normal file
View File

@@ -0,0 +1,145 @@
#include "num.h"
#include "field.h"
#include "group.h"
#include "ecmult.h"
#include "ecdsa.h"
namespace secp256k1 {
bool ParsePubKey(GroupElemJac &elem, const unsigned char *pub, int size) {
if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
secp256k1_fe_t x;
secp256k1_fe_set_b32(&x, pub+1);
elem.SetCompressed(x, pub[0] == 0x03);
} else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
secp256k1_fe_t x,y;
secp256k1_fe_set_b32(&x, pub+1);
secp256k1_fe_set_b32(&y, pub+33);
elem = GroupElem(x,y);
if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07))
return false;
} else {
return false;
}
return elem.IsValid();
}
bool Signature::Parse(const unsigned char *sig, int size) {
if (sig[0] != 0x30) return false;
int lenr = sig[3];
if (5+lenr >= size) return false;
int lens = sig[lenr+5];
if (sig[1] != lenr+lens+4) return false;
if (lenr+lens+6 > size) return false;
if (sig[2] != 0x02) return false;
if (lenr == 0) return false;
if (sig[lenr+4] != 0x02) return false;
if (lens == 0) return false;
secp256k1_num_set_bin(&r, sig+4, lenr);
secp256k1_num_set_bin(&s, sig+6+lenr, lens);
return true;
}
bool Signature::Serialize(unsigned char *sig, int *size) {
int lenR = (secp256k1_num_bits(&r) + 7)/8;
if (lenR == 0 || secp256k1_num_get_bit(&r, lenR*8-1))
lenR++;
int lenS = (secp256k1_num_bits(&s) + 7)/8;
if (lenS == 0 || secp256k1_num_get_bit(&s, lenS*8-1))
lenS++;
if (*size < 6+lenS+lenR)
return false;
*size = 6 + lenS + lenR;
sig[0] = 0x30;
sig[1] = 4 + lenS + lenR;
sig[2] = 0x02;
sig[3] = lenR;
secp256k1_num_get_bin(sig+4, lenR, &r);
sig[4+lenR] = 0x02;
sig[5+lenR] = lenS;
secp256k1_num_get_bin(sig+lenR+6, lenS, &s);
return true;
}
bool Signature::RecomputeR(secp256k1_num_t &r2, const GroupElemJac &pubkey, const secp256k1_num_t &message) const {
const GroupConstants &c = GetGroupConst();
if (secp256k1_num_is_neg(&r) || secp256k1_num_is_neg(&s))
return false;
if (secp256k1_num_is_zero(&r) || secp256k1_num_is_zero(&s))
return false;
if (secp256k1_num_cmp(&r, &c.order) >= 0 || secp256k1_num_cmp(&s, &c.order) >= 0)
return false;
bool ret = false;
secp256k1_num_t sn, u1, u2;
secp256k1_num_init(&sn);
secp256k1_num_init(&u1);
secp256k1_num_init(&u2);
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);
GroupElemJac pr; ECMult(pr, pubkey, u2, u1);
if (!pr.IsInfinity()) {
secp256k1_fe_t xr; pr.GetX(xr);
secp256k1_fe_normalize(&xr);
unsigned char xrb[32]; secp256k1_fe_get_b32(xrb, &xr);
secp256k1_num_set_bin(&r2, xrb, 32);
secp256k1_num_mod(&r2, &r2, &c.order);
ret = true;
}
secp256k1_num_free(&sn);
secp256k1_num_free(&u1);
secp256k1_num_free(&u2);
return ret;
}
bool Signature::Verify(const GroupElemJac &pubkey, const secp256k1_num_t &message) const {
secp256k1_num_t r2;
secp256k1_num_init(&r2);
bool ret = false;
ret = RecomputeR(r2, pubkey, message) && secp256k1_num_cmp(&r, &r2) == 0;
secp256k1_num_free(&r2);
return ret;
}
bool Signature::Sign(const secp256k1_num_t &seckey, const secp256k1_num_t &message, const secp256k1_num_t &nonce) {
const GroupConstants &c = GetGroupConst();
GroupElemJac rp;
ECMultBase(rp, nonce);
secp256k1_fe_t rx;
rp.GetX(rx);
unsigned char b[32];
secp256k1_fe_normalize(&rx);
secp256k1_fe_get_b32(b, &rx);
secp256k1_num_set_bin(&r, b, 32);
secp256k1_num_mod(&r, &r, &c.order);
secp256k1_num_t n;
secp256k1_num_init(&n);
secp256k1_num_mod_mul(&n, &r, &seckey, &c.order);
secp256k1_num_add(&n, &n, &message);
secp256k1_num_mod_inverse(&s, &nonce, &c.order);
secp256k1_num_mod_mul(&s, &s, &n, &c.order);
secp256k1_num_free(&n);
if (secp256k1_num_is_zero(&s))
return false;
if (secp256k1_num_is_odd(&s))
secp256k1_num_sub(&s, &c.order, &s);
return true;
}
void Signature::SetRS(const secp256k1_num_t &rin, const secp256k1_num_t &sin) {
secp256k1_num_copy(&r, &rin);
secp256k1_num_copy(&s, &sin);
}
std::string Signature::ToString() const {
char rs[65], ss[65];
int rl = 65, sl = 65;
secp256k1_num_get_hex(rs, &rl, &r);
secp256k1_num_get_hex(ss, &sl, &s);
return "(" + std::string(rs) + "," + std::string(ss) + ")";
}
}

31
src/ecdsa.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef _SECP256K1_ECDSA_
#define _SECP256K1_ECDSA_
namespace secp256k1 {
class Signature {
private:
secp256k1_num_t r,s;
public:
Signature() {
secp256k1_num_init(&r);
secp256k1_num_init(&s);
}
~Signature() {
secp256k1_num_free(&r);
secp256k1_num_free(&s);
}
bool Parse(const unsigned char *sig, int size);
bool Serialize(unsigned char *sig, int *size);
bool RecomputeR(secp256k1_num_t &r2, const GroupElemJac &pubkey, const secp256k1_num_t &message) const;
bool Verify(const GroupElemJac &pubkey, const secp256k1_num_t &message) const;
bool Sign(const secp256k1_num_t &seckey, const secp256k1_num_t &message, const secp256k1_num_t &nonce);
void SetRS(const secp256k1_num_t &rin, const secp256k1_num_t &sin);
std::string ToString() const;
};
}
#endif

226
src/ecmult.cpp Normal file
View File

@@ -0,0 +1,226 @@
#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 {
template<typename G, int W> class WNAFPrecomp {
private:
G pre[1 << (W-2)];
public:
WNAFPrecomp() {}
void Build(const G &base) {
pre[0] = base;
GroupElemJac x(base);
GroupElemJac d; d.SetDouble(x);
for (int i=1; i<(1 << (W-2)); i++) {
x.SetAdd(d,pre[i-1]);
pre[i].SetJac(x);
}
}
WNAFPrecomp(const G &base) {
Build(base);
}
void Get(G &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 {
out.SetNeg(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:
WNAFPrecomp<GroupElem,WINDOW_G> wpg;
WNAFPrecomp<GroupElem,WINDOW_G> wpg128;
GroupElem prec[64][16]; // prec[j][i] = 16^j * (i+1) * G
GroupElem fin; // -(sum(prec[j][0], j=0..63))
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);
GroupElemJac gg(g);
GroupElem ad(g);
GroupElemJac fn;
for (int j=0; j<64; j++) {
prec[j][0].SetJac(gg);
fn.SetAdd(fn, gg);
for (int i=1; i<16; i++) {
gg.SetAdd(gg, ad);
prec[j][i].SetJac(gg);
}
ad = prec[j][15];
}
fn.SetNeg(fn);
fin.SetJac(fn);
}
};
const ECMultConsts &GetECMultConsts() {
static const ECMultConsts ecmult_consts;
return ecmult_consts;
}
void ECMultBase(GroupElemJac &out, const secp256k1_num_t &gn) {
secp256k1_num_t n;
secp256k1_num_init(&n);
secp256k1_num_copy(&n, &gn);
const ECMultConsts &c = GetECMultConsts();
out.SetAffine(c.prec[0][secp256k1_num_shift(&n, 4)]);
for (int j=1; j<64; j++) {
out.SetAdd(out, c.prec[j][secp256k1_num_shift(&n, 4)]);
}
secp256k1_num_free(&n);
out.SetAdd(out, c.fin);
}
void ECMult(GroupElemJac &out, const GroupElemJac &a, const secp256k1_num_t &an, const secp256k1_num_t &gn) {
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);
SplitExp(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());
secp256k1_num_split(&gn1, &gn2, &gn, 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);
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));
out = GroupElemJac();
GroupElemJac tmpj;
GroupElem tmpa;
for (int i=size-1; i>=0; i--) {
out.SetDouble(out);
int nw;
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);
out.SetAdd(out, tmpj);
}
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);
out.SetAdd(out, tmpa);
}
}
secp256k1_num_free(&an1);
secp256k1_num_free(&an2);
secp256k1_num_free(&gn1);
secp256k1_num_free(&gn2);
}
}

14
src/ecmult.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef _SECP256K1_ECMULT_
#define _SECP256K1_ECMULT_
#include "group.h"
#include "num.h"
namespace secp256k1 {
void ECMultBase(GroupElemJac &out, const secp256k1_num_t &gn);
void ECMult(GroupElemJac &out, const GroupElemJac &a, const secp256k1_num_t &an, const secp256k1_num_t &gn);
}
#endif

155
src/field.cpp Normal file
View File

@@ -0,0 +1,155 @@
// just one implementation for now
#include "field_5x52.cpp"
extern "C" {
static const unsigned char secp256k1_fe_consts_p[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
};
void static secp256k1_fe_start(void) {
if (secp256k1_fe_consts == NULL) {
secp256k1_fe_consts_t *ret = (secp256k1_fe_consts_t*)malloc(sizeof(secp256k1_fe_t));
secp256k1_num_set_bin(&ret->p, secp256k1_fe_consts_p, sizeof(secp256k1_fe_consts_p));
secp256k1_fe_consts = ret;
}
}
void static secp256k1_fe_stop(void) {
if (secp256k1_fe_consts != NULL) {
free((void*)secp256k1_fe_consts);
secp256k1_fe_consts = NULL;
}
}
void static secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a) {
if (*rlen < 65) {
*rlen = 65;
return;
}
*rlen = 65;
unsigned char tmp[32];
secp256k1_fe_t b = *a;
secp256k1_fe_normalize(&b);
secp256k1_fe_get_b32(tmp, &b);
for (int i=0; i<32; i++) {
static const char *c = "0123456789ABCDEF";
r[2*i] = c[(tmp[i] >> 4) & 0xF];
r[2*i+1] = c[(tmp[i]) & 0xF];
}
r[64] = 0x00;
}
void static secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) {
unsigned char tmp[32] = {};
static const int cvt[256] = {0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0};
for (int i=0; i<32; i++) {
if (alen > i*2)
tmp[32 - alen/2 + i] = (cvt[(unsigned char)a[2*i]] << 4) + cvt[(unsigned char)a[2*i+1]];
}
secp256k1_fe_set_b32(r, tmp);
}
void static secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
// calculate a^p, with p={15,780,1022,1023}
secp256k1_fe_t a2; secp256k1_fe_sqr(&a2, a);
secp256k1_fe_t a3; secp256k1_fe_mul(&a3, &a2, a);
secp256k1_fe_t a6; secp256k1_fe_sqr(&a6, &a3);
secp256k1_fe_t a12; secp256k1_fe_sqr(&a12, &a6);
secp256k1_fe_t a15; secp256k1_fe_mul(&a15, &a12, &a3);
secp256k1_fe_t a30; secp256k1_fe_sqr(&a30, &a15);
secp256k1_fe_t a60; secp256k1_fe_sqr(&a60, &a30);
secp256k1_fe_t a120; secp256k1_fe_sqr(&a120, &a60);
secp256k1_fe_t a240; secp256k1_fe_sqr(&a240, &a120);
secp256k1_fe_t a255; secp256k1_fe_mul(&a255, &a240, &a15);
secp256k1_fe_t a510; secp256k1_fe_sqr(&a510, &a255);
secp256k1_fe_t a750; secp256k1_fe_mul(&a750, &a510, &a240);
secp256k1_fe_t a780; secp256k1_fe_mul(&a780, &a750, &a30);
secp256k1_fe_t a1020; secp256k1_fe_sqr(&a1020, &a510);
secp256k1_fe_t a1022; secp256k1_fe_mul(&a1022, &a1020, &a2);
secp256k1_fe_t a1023; secp256k1_fe_mul(&a1023, &a1022, a);
secp256k1_fe_t x = a15;
for (int i=0; i<21; i++) {
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(&x, &x, &a1023);
}
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(&x, &x, &a1022);
for (int i=0; i<2; i++) {
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(&x, &x, &a1023);
}
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(r, &x, &a780);
}
void static secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
// calculate a^p, with p={45,63,1019,1023}
secp256k1_fe_t a2; secp256k1_fe_sqr(&a2, a);
secp256k1_fe_t a3; secp256k1_fe_mul(&a3, &a2, a);
secp256k1_fe_t a4; secp256k1_fe_sqr(&a4, &a2);
secp256k1_fe_t a5; secp256k1_fe_mul(&a5, &a4, a);
secp256k1_fe_t a10; secp256k1_fe_sqr(&a10, &a5);
secp256k1_fe_t a11; secp256k1_fe_mul(&a11, &a10, a);
secp256k1_fe_t a21; secp256k1_fe_mul(&a21, &a11, &a10);
secp256k1_fe_t a42; secp256k1_fe_sqr(&a42, &a21);
secp256k1_fe_t a45; secp256k1_fe_mul(&a45, &a42, &a3);
secp256k1_fe_t a63; secp256k1_fe_mul(&a63, &a42, &a21);
secp256k1_fe_t a126; secp256k1_fe_sqr(&a126, &a63);
secp256k1_fe_t a252; secp256k1_fe_sqr(&a252, &a126);
secp256k1_fe_t a504; secp256k1_fe_sqr(&a504, &a252);
secp256k1_fe_t a1008; secp256k1_fe_sqr(&a1008, &a504);
secp256k1_fe_t a1019; secp256k1_fe_mul(&a1019, &a1008, &a11);
secp256k1_fe_t a1023; secp256k1_fe_mul(&a1023, &a1019, &a4);
secp256k1_fe_t x = a63;
for (int i=0; i<21; i++) {
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(&x, &x, &a1023);
}
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(&x, &x, &a1019);
for (int i=0; i<2; i++) {
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(&x, &x, &a1023);
}
for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x);
secp256k1_fe_mul(r, &x, &a45);
}
void static secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#if defined(USE_FIELD_INV_BUILTIN)
secp256k1_fe_inv(r, a);
#else
unsigned char b[32];
secp256k1_fe_t c = *a;
secp256k1_fe_normalize(&c);
secp256k1_fe_get_b32(b, &c);
secp256k1_num_t n;
secp256k1_num_init(&n);
secp256k1_num_set_bin(&n, b, 32);
secp256k1_num_mod_inverse(&n, &n, &secp256k1_fe_consts->p);
secp256k1_num_get_bin(b, 32, &n);
secp256k1_num_free(&n);
secp256k1_fe_set_b32(&c, b);
#endif
}
}

92
src/field.h Normal file
View File

@@ -0,0 +1,92 @@
#ifndef _SECP256K1_FIELD_
#define _SECP256K1_FIELD_
/** Field element module.
*
* Field elements can be represented in several ways, but code accessing
* it (and implementations) need to take certain properaties into account:
* - Each field element can be normalized or not.
* - Each field element has a magnitude, which represents how far away
* its representation is away from normalization. Normalized elements
* always have a magnitude of 1, but a magnitude of 1 doesn't imply
* normality.
*/
// just one implementation for now
#include "field_5x52.h"
extern "C" {
typedef struct {
secp256k1_num_t p;
} secp256k1_fe_consts_t;
static const secp256k1_fe_consts_t *secp256k1_fe_consts = NULL;
/** Initialize field element precomputation data. */
void static secp256k1_fe_start(void);
/** Unload field element precomputation data. */
void static secp256k1_fe_stop(void);
/** Normalize a field element. */
void static secp256k1_fe_normalize(secp256k1_fe_t *r);
/** Set a field element equal to a small integer. Resulting field element is normalized. */
void static secp256k1_fe_set_int(secp256k1_fe_t *r, int a);
/** Verify whether a field element is zero. Requires the input to be normalized. */
int static secp256k1_fe_is_zero(const secp256k1_fe_t *a);
/** Check the "oddness" of a field element. Requires the input to be normalized. */
int static secp256k1_fe_is_odd(const secp256k1_fe_t *a);
/** Compare two field elements. Requires both inputs to be normalized */
int static secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b);
/** Set a field element equal to 32-byte big endian value. Resulting field element is normalized. */
void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a);
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a);
/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input
* as an argument. The magnitude of the output is one higher. */
void static secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m);
/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that
* small integer. */
void static secp256k1_fe_mul_int(secp256k1_fe_t *r, int a);
/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */
void static secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8.
* The output magnitude is 1 (but not guaranteed to be normalized). */
void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b);
/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8.
* The output magnitude is 1 (but not guaranteed to be normalized). */
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Sets a field element to be the (modular) square root of another. Requires the inputs' magnitude to
* be at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
void static secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
* at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
void static secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */
void static secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Convert a field element to a hexadecimal string. */
void static secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a);
/** Convert a hexadecimal string to a field element. */
void static secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen);
}
#endif

185
src/field_5x52.cpp Normal file
View File

@@ -0,0 +1,185 @@
#include <assert.h>
#include <string.h>
#include "num.h"
#include "field.h"
#ifdef USE_FIELD_5X52_ASM
#include "field_5x52_asm.cpp"
#else
#include "field_5x52_int128.cpp"
#endif
extern "C" {
/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
* represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular,
* each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element
* is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations
* accept any input with magnitude at most M, and have different rules for propagating magnitude to their
* output.
*/
void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
uint64_t c;
c = r->n[0];
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + r->n[1];
uint64_t t1 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + r->n[2];
uint64_t t2 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + r->n[3];
uint64_t t3 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + r->n[4];
uint64_t t4 = c & 0x0FFFFFFFFFFFFULL;
c >>= 48;
// The following code will not modify the t's if c is initially 0.
c = c * 0x1000003D1ULL + t0;
t0 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + t1;
t1 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + t2;
t2 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + t3;
t3 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + t4;
t4 = c & 0x0FFFFFFFFFFFFULL;
// Subtract p if result >= p
uint64_t mask = -(int64_t)((t4 < 0xFFFFFFFFFFFFULL) | (t3 < 0xFFFFFFFFFFFFFULL) | (t2 < 0xFFFFFFFFFFFFFULL) | (t1 < 0xFFFFFFFFFFFFFULL) | (t0 < 0xFFFFEFFFFFC2FULL));
t4 &= mask;
t3 &= mask;
t2 &= mask;
t1 &= mask;
t0 -= (~mask & 0xFFFFEFFFFFC2FULL);
// push internal variables back
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
#endif
}
void static inline secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
r->n[0] = a;
r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
#endif
}
// TODO: not constant time!
int static inline secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->normalized);
#endif
return (a->n[0] == 0 && a->n[1] == 0 && a->n[2] == 0 && a->n[3] == 0 && a->n[4] == 0);
}
int static inline secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->normalized);
#endif
return a->n[0] & 1;
}
// TODO: not constant time!
int static inline secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
#ifdef VERIFY
assert(a->normalized);
assert(b->normalized);
#endif
return (a->n[0] == b->n[0] && a->n[1] == b->n[1] && a->n[2] == b->n[2] && a->n[3] == b->n[3] && a->n[4] == b->n[4]);
}
void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
for (int i=0; i<32; i++) {
for (int j=0; j<2; j++) {
int limb = (8*i+4*j)/52;
int shift = (8*i+4*j)%52;
r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift;
}
}
#ifdef VERIFY
r->magnitude = 1;
r->normalized = true;
#endif
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->normalized);
#endif
for (int i=0; i<32; i++) {
int c = 0;
for (int j=0; j<2; j++) {
int limb = (8*i+4*j)/52;
int shift = (8*i+4*j)%52;
c |= ((a->n[limb] >> shift) & 0xF) << (4 * j);
}
r[31-i] = c;
}
}
void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) {
#ifdef VERIFY
assert(a->magnitude <= m);
r->magnitude = m + 1;
r->normalized = 0;
#endif
r->n[0] = 0xFFFFEFFFFFC2FULL * (m + 1) - a->n[0];
r->n[1] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[1];
r->n[2] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[2];
r->n[3] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[3];
r->n[4] = 0x0FFFFFFFFFFFFULL * (m + 1) - a->n[4];
}
void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
#ifdef VERIFY
r->magnitude *= a;
r->normalized = false;
#endif
r->n[0] *= a;
r->n[1] *= a;
r->n[2] *= a;
r->n[3] *= a;
r->n[4] *= a;
}
void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
r->magnitude += a->magnitude;
r->normalized = 0;
#endif
r->n[0] += a->n[0];
r->n[1] += a->n[1];
r->n[2] += a->n[2];
r->n[3] += a->n[3];
r->n[4] += a->n[4];
}
void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
#ifdef VERIFY
assert(a->magnitude <= 8);
assert(b->magnitude <= 8);
r->magnitude = 1;
r->normalized = 0;
#endif
secp256k1_fe_mul_inner(a->n, b->n, r->n);
}
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->magnitude <= 8);
r->magnitude = 1;
r->normalized = 0;
#endif
secp256k1_fe_sqr_inner(a->n, r->n);
}
}

19
src/field_5x52.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef _SECP256K1_FIELD_5x52_
#define _SECP256K1_FIELD_5x52_
#include <stdint.h>
extern "C" {
typedef struct {
// X = sum(i=0..4, elem[i]*2^52) mod n
uint64_t n[5];
#ifdef VERIFY
int magnitude;
int normalized;
#endif
} secp256k1_fe_t;
}
#endif

463
src/field_5x52_asm.asm Normal file
View File

@@ -0,0 +1,463 @@
;; Added by Diederik Huys, March 2013
;;
;; Provided public procedures:
;; secp256k1_fe_mul_inner
;; secp256k1_fe_sqr_inner
;;
;; Needed tools: YASM (http://yasm.tortall.net)
;;
;;
BITS 64
;; Procedure ExSetMult
;; Register Layout:
;; INPUT: rdi = a->n
;; rsi = b->n
;; rdx = r->a
;;
;; INTERNAL: rdx:rax = multiplication accumulator
;; r9:r8 = c
;; r10-r13 = t0-t3
;; r14 = b.n[0] / t4
;; r15 = b.n[1] / t5
;; rbx = b.n[2] / t6
;; rcx = b.n[3] / t7
;; rbp = Constant 0FFFFFFFFFFFFFh / t8
;; rsi = b.n / b.n[4] / t9
GLOBAL secp256k1_fe_mul_inner
ALIGN 32
secp256k1_fe_mul_inner:
push rbp
push rbx
push r12
push r13
push r14
push r15
push rdx
mov r14,[rsi+8*0] ; preload b.n[0]. This will be the case until
; b.n[0] is no longer needed, then we reassign
; r14 to t4
;; c=a.n[0] * b.n[0]
mov rax,[rdi+0*8] ; load a.n[0]
mov rbp,0FFFFFFFFFFFFFh
mul r14 ; rdx:rax=a.n[0]*b.n[0]
mov r15,[rsi+1*8]
mov r10,rbp ; load modulus into target register for t0
mov r8,rax
and r10,rax ; only need lower qword of c
shrd r8,rdx,52
xor r9,r9 ; c < 2^64, so we ditch the HO part
;; c+=a.n[0] * b.n[1] + a.n[1] * b.n[0]
mov rax,[rdi+0*8]
mul r15
add r8,rax
adc r9,rdx
mov rax,[rdi+1*8]
mul r14
mov r11,rbp
mov rbx,[rsi+2*8]
add r8,rax
adc r9,rdx
and r11,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[0 1 2] * b.n[2 1 0]
mov rax,[rdi+0*8]
mul rbx
add r8,rax
adc r9,rdx
mov rax,[rdi+1*8]
mul r15
add r8,rax
adc r9,rdx
mov rax,[rdi+2*8]
mul r14
mov r12,rbp
mov rcx,[rsi+3*8]
add r8,rax
adc r9,rdx
and r12,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[0 1 2 3] * b.n[3 2 1 0]
mov rax,[rdi+0*8]
mul rcx
add r8,rax
adc r9,rdx
mov rax,[rdi+1*8]
mul rbx
add r8,rax
adc r9,rdx
mov rax,[rdi+2*8]
mul r15
add r8,rax
adc r9,rdx
mov rax,[rdi+3*8]
mul r14
mov r13,rbp
mov rsi,[rsi+4*8] ; load b.n[4] and destroy pointer
add r8,rax
adc r9,rdx
and r13,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[0 1 2 3 4] * b.n[4 3 2 1 0]
mov rax,[rdi+0*8]
mul rsi
add r8,rax
adc r9,rdx
mov rax,[rdi+1*8]
mul rcx
add r8,rax
adc r9,rdx
mov rax,[rdi+2*8]
mul rbx
add r8,rax
adc r9,rdx
mov rax,[rdi+3*8]
mul r15
add r8,rax
adc r9,rdx
mov rax,[rdi+4*8]
mul r14
mov r14,rbp ; load modulus into t4 and destroy a.n[0]
add r8,rax
adc r9,rdx
and r14,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[1 2 3 4] * b.n[4 3 2 1]
mov rax,[rdi+1*8]
mul rsi
add r8,rax
adc r9,rdx
mov rax,[rdi+2*8]
mul rcx
add r8,rax
adc r9,rdx
mov rax,[rdi+3*8]
mul rbx
add r8,rax
adc r9,rdx
mov rax,[rdi+4*8]
mul r15
mov r15,rbp
add r8,rax
adc r9,rdx
and r15,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[2 3 4] * b.n[4 3 2]
mov rax,[rdi+2*8]
mul rsi
add r8,rax
adc r9,rdx
mov rax,[rdi+3*8]
mul rcx
add r8,rax
adc r9,rdx
mov rax,[rdi+4*8]
mul rbx
mov rbx,rbp
add r8,rax
adc r9,rdx
and rbx,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[3 4] * b.n[4 3]
mov rax,[rdi+3*8]
mul rsi
add r8,rax
adc r9,rdx
mov rax,[rdi+4*8]
mul rcx
mov rcx,rbp
add r8,rax
adc r9,rdx
and rcx,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[4] * b.n[4]
mov rax,[rdi+4*8]
mul rsi
;; mov rbp,rbp ; modulus already there!
add r8,rax
adc r9,rdx
and rbp,r8
shrd r8,r9,52
xor r9,r9
mov rsi,r8 ; load c into t9 and destroy b.n[4]
;; *******************************************************
common_exit_norm:
mov rdi,01000003D10h ; load constant
mov rax,r15 ; get t5
mul rdi
add rax,r10 ; +t0
adc rdx,0
mov r10,0FFFFFFFFFFFFFh ; modulus. Sadly, we ran out of registers!
mov r8,rax ; +c
and r10,rax
shrd r8,rdx,52
xor r9,r9
mov rax,rbx ; get t6
mul rdi
add rax,r11 ; +t1
adc rdx,0
mov r11,0FFFFFFFFFFFFFh ; modulus
add r8,rax ; +c
adc r9,rdx
and r11,r8
shrd r8,r9,52
xor r9,r9
mov rax,rcx ; get t7
mul rdi
add rax,r12 ; +t2
adc rdx,0
pop rbx ; retrieve pointer to this.n
mov r12,0FFFFFFFFFFFFFh ; modulus
add r8,rax ; +c
adc r9,rdx
and r12,r8
mov [rbx+2*8],r12 ; mov into this.n[2]
shrd r8,r9,52
xor r9,r9
mov rax,rbp ; get t8
mul rdi
add rax,r13 ; +t3
adc rdx,0
mov r13,0FFFFFFFFFFFFFh ; modulus
add r8,rax ; +c
adc r9,rdx
and r13,r8
mov [rbx+3*8],r13 ; -> this.n[3]
shrd r8,r9,52
xor r9,r9
mov rax,rsi ; get t9
mul rdi
add rax,r14 ; +t4
adc rdx,0
mov r14,0FFFFFFFFFFFFh ; !!!
add r8,rax ; +c
adc r9,rdx
and r14,r8
mov [rbx+4*8],r14 ; -> this.n[4]
shrd r8,r9,48 ; !!!
xor r9,r9
mov rax,01000003D1h
mul r8
add rax,r10
adc rdx,0
mov r10,0FFFFFFFFFFFFFh ; modulus
mov r8,rax
and rax,r10
shrd r8,rdx,52
mov [rbx+0*8],rax ; -> this.n[0]
add r8,r11
mov [rbx+1*8],r8 ; -> this.n[1]
pop r15
pop r14
pop r13
pop r12
pop rbx
pop rbp
ret
;; PROC ExSetSquare
;; Register Layout:
;; INPUT: rdi = a.n
;; rsi = this.a
;; INTERNAL: rdx:rax = multiplication accumulator
;; r9:r8 = c
;; r10-r13 = t0-t3
;; r14 = a.n[0] / t4
;; r15 = a.n[1] / t5
;; rbx = a.n[2] / t6
;; rcx = a.n[3] / t7
;; rbp = 0FFFFFFFFFFFFFh / t8
;; rsi = a.n[4] / a.n[4] /t9
GLOBAL secp256k1_fe_sqr_inner
ALIGN 32
secp256k1_fe_sqr_inner:
push rbp
push rbx
push r12
push r13
push r14
push r15
push rsi
mov rbp,0FFFFFFFFFFFFFh
;; c=a.n[0] * a.n[0]
mov r14,[rdi+0*8] ; r14=a.n[0]
mov r10,rbp ; modulus
mov rax,r14
mul rax
mov r15,[rdi+1*8] ; a.n[1]
add r14,r14 ; r14=2*a.n[0]
mov r8,rax
and r10,rax ; only need lower qword
shrd r8,rdx,52
xor r9,r9
;; c+=2*a.n[0] * a.n[1]
mov rax,r14 ; r14=2*a.n[0]
mul r15
mov rbx,[rdi+2*8] ; rbx=a.n[2]
mov r11,rbp ; modulus
add r8,rax
adc r9,rdx
and r11,r8
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[0]*a.n[2]+a.n[1]*a.n[1]
mov rax,r14
mul rbx
add r8,rax
adc r9,rdx
mov rax,r15
mov r12,rbp ; modulus
mul rax
mov rcx,[rdi+3*8] ; rcx=a.n[3]
add r15,r15 ; r15=a.n[1]*2
add r8,rax
adc r9,rdx
and r12,r8 ; only need lower dword
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[0]*a.n[3]+2*a.n[1]*a.n[2]
mov rax,r14
mul rcx
add r8,rax
adc r9,rdx
mov rax,r15 ; rax=2*a.n[1]
mov r13,rbp ; modulus
mul rbx
mov rsi,[rdi+4*8] ; rsi=a.n[4]
add r8,rax
adc r9,rdx
and r13,r8
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[0]*a.n[4]+2*a.n[1]*a.n[3]+a.n[2]*a.n[2]
mov rax,r14 ; last time we need 2*a.n[0]
mul rsi
add r8,rax
adc r9,rdx
mov rax,r15
mul rcx
mov r14,rbp ; modulus
add r8,rax
adc r9,rdx
mov rax,rbx
mul rax
add rbx,rbx ; rcx=2*a.n[2]
add r8,rax
adc r9,rdx
and r14,r8
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[1]*a.n[4]+2*a.n[2]*a.n[3]
mov rax,r15 ; last time we need 2*a.n[1]
mul rsi
add r8,rax
adc r9,rdx
mov rax,rbx
mul rcx
mov r15,rbp ; modulus
add r8,rax
adc r9,rdx
and r15,r8
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[2]*a.n[4]+a.n[3]*a.n[3]
mov rax,rbx ; last time we need 2*a.n[2]
mul rsi
add r8,rax
adc r9,rdx
mov rax,rcx ; a.n[3]
mul rax
mov rbx,rbp ; modulus
add r8,rax
adc r9,rdx
and rbx,r8 ; only need lower dword
lea rax,[2*rcx]
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[3]*a.n[4]
mul rsi
mov rcx,rbp ; modulus
add r8,rax
adc r9,rdx
and rcx,r8 ; only need lower dword
shrd r8,r9,52
xor r9,r9
;; c+=a.n[4]*a.n[4]
mov rax,rsi
mul rax
;; mov rbp,rbp ; modulus is already there!
add r8,rax
adc r9,rdx
and rbp,r8
shrd r8,r9,52
xor r9,r9
mov rsi,r8
;; *******************************************************
jmp common_exit_norm
end

2
src/field_5x52_asm.cpp Normal file
View File

@@ -0,0 +1,2 @@
extern "C" void __attribute__ ((sysv_abi)) secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r);
extern "C" void __attribute__ ((sysv_abi)) secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t *r);

100
src/field_5x52_int128.cpp Normal file
View File

@@ -0,0 +1,100 @@
#include "field.h"
extern "C" {
void static inline secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r) {
unsigned __int128 c = (__int128)a[0] * b[0];
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0
c = c + (__int128)a[0] * b[1] +
(__int128)a[1] * b[0];
uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF
c = c + (__int128)a[0] * b[2] +
(__int128)a[1] * b[1] +
(__int128)a[2] * b[0];
uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0
c = c + (__int128)a[0] * b[3] +
(__int128)a[1] * b[2] +
(__int128)a[2] * b[1] +
(__int128)a[3] * b[0];
uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280
c = c + (__int128)a[0] * b[4] +
(__int128)a[1] * b[3] +
(__int128)a[2] * b[2] +
(__int128)a[3] * b[1] +
(__int128)a[4] * b[0];
uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E
c = c + (__int128)a[1] * b[4] +
(__int128)a[2] * b[3] +
(__int128)a[3] * b[2] +
(__int128)a[4] * b[1];
uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE
c = c + (__int128)a[2] * b[4] +
(__int128)a[3] * b[3] +
(__int128)a[4] * b[2];
uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE
c = c + (__int128)a[3] * b[4] +
(__int128)a[4] * b[3];
uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE
c = c + (__int128)a[4] * b[4];
uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E
uint64_t t9 = c;
c = t0 + (__int128)t5 * 0x1000003D10ULL;
t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t1 + (__int128)t6 * 0x1000003D10ULL;
t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t2 + (__int128)t7 * 0x1000003D10ULL;
r[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t3 + (__int128)t8 * 0x1000003D10ULL;
r[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t4 + (__int128)t9 * 0x1000003D10ULL;
r[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110
c = t0 + (__int128)c * 0x1000003D1ULL;
r[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008
r[1] = t1 + c;
}
void static inline secp256k1_fe_sqr_inner(const uint64_t *a, uint64_t *r) {
__int128 c = (__int128)a[0] * a[0];
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0
c = c + (__int128)(a[0]*2) * a[1];
uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF
c = c + (__int128)(a[0]*2) * a[2] +
(__int128)a[1] * a[1];
uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0
c = c + (__int128)(a[0]*2) * a[3] +
(__int128)(a[1]*2) * a[2];
uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280
c = c + (__int128)(a[0]*2) * a[4] +
(__int128)(a[1]*2) * a[3] +
(__int128)a[2] * a[2];
uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E
c = c + (__int128)(a[1]*2) * a[4] +
(__int128)(a[2]*2) * a[3];
uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE
c = c + (__int128)(a[2]*2) * a[4] +
(__int128)a[3] * a[3];
uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE
c = c + (__int128)(a[3]*2) * a[4];
uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE
c = c + (__int128)a[4] * a[4];
uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E
uint64_t t9 = c;
c = t0 + (__int128)t5 * 0x1000003D10ULL;
t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t1 + (__int128)t6 * 0x1000003D10ULL;
t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t2 + (__int128)t7 * 0x1000003D10ULL;
r[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t3 + (__int128)t8 * 0x1000003D10ULL;
r[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t4 + (__int128)t9 * 0x1000003D10ULL;
r[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110
c = t0 + (__int128)c * 0x1000003D1ULL;
r[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008
r[1] = t1 + c;
}
}

373
src/group.cpp Normal file
View File

@@ -0,0 +1,373 @@
#include <string>
#include "num.h"
#include "field.h"
#include "group.h"
namespace secp256k1 {
GroupElem::GroupElem() {
fInfinity = true;
}
GroupElem::GroupElem(const secp256k1_fe_t &xin, const secp256k1_fe_t &yin) {
fInfinity = false;
x = xin;
y = yin;
}
bool GroupElem::IsInfinity() const {
return fInfinity;
}
void GroupElem::SetNeg(const GroupElem &p) {
*this = p;
secp256k1_fe_normalize(&y);
secp256k1_fe_negate(&y, &y, 1);
}
void GroupElem::GetX(secp256k1_fe_t &xout) {
xout = x;
}
void GroupElem::GetY(secp256k1_fe_t &yout) {
yout = y;
}
std::string GroupElem::ToString() const {
if (fInfinity)
return "(inf)";
secp256k1_fe_t xc = x, yc = y;
char xo[65], yo[65];
int xl = 65, yl = 65;
secp256k1_fe_get_hex(xo, &xl, &xc);
secp256k1_fe_get_hex(yo, &yl, &yc);
return "(" + std::string(xo) + "," + std::string(yo) + ")";
}
GroupElemJac::GroupElemJac() : GroupElem() {
secp256k1_fe_set_int(&z, 1);
}
GroupElemJac::GroupElemJac(const secp256k1_fe_t &xin, const secp256k1_fe_t &yin) : GroupElem(xin,yin) {
secp256k1_fe_set_int(&z, 1);
}
GroupElemJac::GroupElemJac(const GroupElem &in) : GroupElem(in) {
secp256k1_fe_set_int(&z, 1);
}
void GroupElemJac::SetJac(const GroupElemJac &jac) {
*this = jac;
}
void GroupElemJac::SetAffine(const GroupElem &aff) {
fInfinity = aff.fInfinity;
x = aff.x;
y = aff.y;
secp256k1_fe_set_int(&z, 1);
}
bool GroupElemJac::IsValid() const {
if (IsInfinity())
return false;
// y^2 = x^3 + 7
// (Y/Z^3)^2 = (X/Z^2)^3 + 7
// Y^2 / Z^6 = X^3 / Z^6 + 7
// Y^2 = X^3 + 7*Z^6
secp256k1_fe_t y2; secp256k1_fe_sqr(&y2, &y);
secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &x); secp256k1_fe_mul(&x3, &x3, &x);
secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &z);
secp256k1_fe_t z6; secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
secp256k1_fe_mul_int(&z6, 7);
secp256k1_fe_add(&x3, &z6);
secp256k1_fe_normalize(&y2);
secp256k1_fe_normalize(&x3);
return secp256k1_fe_equal(&y2, &x3);
}
void GroupElemJac::GetAffine(GroupElem &aff) {
secp256k1_fe_inv_var(&z, &z);
secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &z);
secp256k1_fe_t z3; secp256k1_fe_mul(&z3, &z, &z2);
secp256k1_fe_mul(&x, &x, &z2);
secp256k1_fe_mul(&y, &y, &z3);
secp256k1_fe_set_int(&z, 1);
aff.fInfinity = fInfinity;
aff.x = x;
aff.y = y;
}
void GroupElemJac::GetX(secp256k1_fe_t &xout) {
secp256k1_fe_t zi2; secp256k1_fe_inv_var(&zi2, &z); secp256k1_fe_sqr(&zi2, &zi2);
secp256k1_fe_mul(&xout, &x, &zi2);
}
void GroupElemJac::GetY(secp256k1_fe_t &yout) {
secp256k1_fe_t zi; secp256k1_fe_inv_var(&zi, &z);
secp256k1_fe_t zi3; secp256k1_fe_sqr(&zi3, &zi); secp256k1_fe_mul(&zi3, &zi, &zi3);
secp256k1_fe_mul(&yout, &y, &zi3);
}
bool GroupElemJac::IsInfinity() const {
return fInfinity;
}
void GroupElemJac::SetNeg(const GroupElemJac &p) {
*this = p;
secp256k1_fe_normalize(&y);
secp256k1_fe_negate(&y, &y, 1);
}
void GroupElemJac::SetCompressed(const secp256k1_fe_t &xin, bool fOdd) {
x = xin;
secp256k1_fe_t x2; secp256k1_fe_sqr(&x2, &x);
secp256k1_fe_t x3; secp256k1_fe_mul(&x3, &x, &x2);
fInfinity = false;
secp256k1_fe_t c; secp256k1_fe_set_int(&c, 7);
secp256k1_fe_add(&c, &x3);
secp256k1_fe_sqrt(&y, &c);
secp256k1_fe_set_int(&z, 1);
secp256k1_fe_normalize(&y);
if (secp256k1_fe_is_odd(&y) != fOdd)
secp256k1_fe_negate(&y, &y, 1);
}
void GroupElemJac::SetDouble(const GroupElemJac &p) {
secp256k1_fe_t t5 = p.y;
secp256k1_fe_normalize(&t5);
if (p.fInfinity || secp256k1_fe_is_zero(&t5)) {
fInfinity = true;
return;
}
secp256k1_fe_t t1,t2,t3,t4;
secp256k1_fe_mul(&z, &t5, &p.z);
secp256k1_fe_mul_int(&z, 2); // Z' = 2*Y*Z (2)
secp256k1_fe_sqr(&t1, &p.x);
secp256k1_fe_mul_int(&t1, 3); // T1 = 3*X^2 (3)
secp256k1_fe_sqr(&t2, &t1); // T2 = 9*X^4 (1)
secp256k1_fe_sqr(&t3, &t5);
secp256k1_fe_mul_int(&t3, 2); // T3 = 2*Y^2 (2)
secp256k1_fe_sqr(&t4, &t3);
secp256k1_fe_mul_int(&t4, 2); // T4 = 8*Y^4 (2)
secp256k1_fe_mul(&t3, &p.x, &t3); // T3 = 2*X*Y^2 (1)
x = t3;
secp256k1_fe_mul_int(&x, 4); // X' = 8*X*Y^2 (4)
secp256k1_fe_negate(&x, &x, 4); // X' = -8*X*Y^2 (5)
secp256k1_fe_add(&x, &t2); // X' = 9*X^4 - 8*X*Y^2 (6)
secp256k1_fe_negate(&t2, &t2, 1); // T2 = -9*X^4 (2)
secp256k1_fe_mul_int(&t3, 6); // T3 = 12*X*Y^2 (6)
secp256k1_fe_add(&t3, &t2); // T3 = 12*X*Y^2 - 9*X^4 (8)
secp256k1_fe_mul(&y, &t1, &t3); // Y' = 36*X^3*Y^2 - 27*X^6 (1)
secp256k1_fe_negate(&t2, &t4, 2); // T2 = -8*Y^4 (3)
secp256k1_fe_add(&y, &t2); // Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4)
fInfinity = false;
}
void GroupElemJac::SetAdd(const GroupElemJac &p, const GroupElemJac &q) {
if (p.fInfinity) {
*this = q;
return;
}
if (q.fInfinity) {
*this = p;
return;
}
fInfinity = false;
const secp256k1_fe_t &x1 = p.x, &y1 = p.y, &z1 = p.z, &x2 = q.x, &y2 = q.y, &z2 = q.z;
secp256k1_fe_t z22; secp256k1_fe_sqr(&z22, &z2);
secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &z1);
secp256k1_fe_t u1; secp256k1_fe_mul(&u1, &x1, &z22);
secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &x2, &z12);
secp256k1_fe_t s1; secp256k1_fe_mul(&s1, &y1, &z22); secp256k1_fe_mul(&s1, &s1, &z2);
secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &y2, &z12); secp256k1_fe_mul(&s2, &s2, &z1);
secp256k1_fe_normalize(&u1);
secp256k1_fe_normalize(&u2);
if (secp256k1_fe_equal(&u1, &u2)) {
secp256k1_fe_normalize(&s1);
secp256k1_fe_normalize(&s2);
if (secp256k1_fe_equal(&s1, &s2)) {
SetDouble(p);
} else {
fInfinity = true;
}
return;
}
secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
secp256k1_fe_t r; secp256k1_fe_negate(&r, &s1, 1); secp256k1_fe_add(&r, &s2);
secp256k1_fe_t r2; secp256k1_fe_sqr(&r2, &r);
secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h);
secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2);
secp256k1_fe_mul(&z, &z1, &z2); secp256k1_fe_mul(&z, &z, &h);
secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2);
x = t; secp256k1_fe_mul_int(&x, 2); secp256k1_fe_add(&x, &h3); secp256k1_fe_negate(&x, &x, 3); secp256k1_fe_add(&x, &r2);
secp256k1_fe_negate(&y, &x, 5); secp256k1_fe_add(&y, &t); secp256k1_fe_mul(&y, &y, &r);
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
secp256k1_fe_add(&y, &h3);
}
void GroupElemJac::SetAdd(const GroupElemJac &p, const GroupElem &q) {
if (p.fInfinity) {
x = q.x;
y = q.y;
fInfinity = q.fInfinity;
secp256k1_fe_set_int(&z, 1);
return;
}
if (q.fInfinity) {
*this = p;
return;
}
fInfinity = false;
const secp256k1_fe_t &x1 = p.x, &y1 = p.y, &z1 = p.z, &x2 = q.x, &y2 = q.y;
secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &z1);
secp256k1_fe_t u1 = x1; secp256k1_fe_normalize(&u1);
secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &x2, &z12);
secp256k1_fe_t s1 = y1; secp256k1_fe_normalize(&s1);
secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &y2, &z12); secp256k1_fe_mul(&s2, &s2, &z1);
secp256k1_fe_normalize(&u1);
secp256k1_fe_normalize(&u2);
if (secp256k1_fe_equal(&u1, &u2)) {
secp256k1_fe_normalize(&s1);
secp256k1_fe_normalize(&s2);
if (secp256k1_fe_equal(&s1, &s2)) {
SetDouble(p);
} else {
fInfinity = true;
}
return;
}
secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
secp256k1_fe_t r; secp256k1_fe_negate(&r, &s1, 1); secp256k1_fe_add(&r, &s2);
secp256k1_fe_t r2; secp256k1_fe_sqr(&r2, &r);
secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h);
secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2);
z = p.z; secp256k1_fe_mul(&z, &z, &h);
secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2);
x = t; secp256k1_fe_mul_int(&x, 2); secp256k1_fe_add(&x, &h3); secp256k1_fe_negate(&x, &x, 3); secp256k1_fe_add(&x, &r2);
secp256k1_fe_negate(&y, &x, 5); secp256k1_fe_add(&y, &t); secp256k1_fe_mul(&y, &y, &r);
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
secp256k1_fe_add(&y, &h3);
}
std::string GroupElemJac::ToString() const {
GroupElemJac cop = *this;
GroupElem aff;
cop.GetAffine(aff);
return aff.ToString();
}
void GroupElem::SetJac(GroupElemJac &jac) {
jac.GetAffine(*this);
}
static const unsigned char order_[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41};
static const unsigned char g_x_[] = {0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,
0x55,0xA0,0x62,0x95,0xCE,0x87,0x0B,0x07,
0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,
0x59,0xF2,0x81,0x5B,0x16,0xF8,0x17,0x98};
static const unsigned char g_y_[] = {0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,
0x5D,0xA4,0xFB,0xFC,0x0E,0x11,0x08,0xA8,
0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,
0x9C,0x47,0xD0,0x8F,0xFB,0x10,0xD4,0xB8};
// properties of secp256k1's efficiently computable endomorphism
static const unsigned char lambda_[] = {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,
0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,
0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,
0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72};
static const unsigned char beta_[] = {0x7a,0xe9,0x6a,0x2b,0x65,0x7c,0x07,0x10,
0x6e,0x64,0x47,0x9e,0xac,0x34,0x34,0xe9,
0x9c,0xf0,0x49,0x75,0x12,0xf5,0x89,0x95,
0xc1,0x39,0x6c,0x28,0x71,0x95,0x01,0xee};
static const unsigned char a1b2_[] = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,
0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15};
static const unsigned char b1_[] = {0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,
0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3};
static const unsigned char a2_[] = {0x01,
0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,
0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8};
GroupConstants::GroupConstants() {
secp256k1_num_init(&order);
secp256k1_num_init(&lambda);
secp256k1_num_init(&a1b2);
secp256k1_num_init(&b1);
secp256k1_num_init(&a2);
secp256k1_fe_set_b32(&g_x, g_x_);
secp256k1_fe_set_b32(&g_y, g_y_);
secp256k1_fe_set_b32(&beta, beta_);
g = GroupElem(g_x, g_y);
secp256k1_num_set_bin(&order, order_, sizeof(order_));
secp256k1_num_set_bin(&lambda, lambda_, sizeof(lambda_));
secp256k1_num_set_bin(&a1b2, a1b2_, sizeof(a1b2_));
secp256k1_num_set_bin(&b1, b1_, sizeof(b1_));
secp256k1_num_set_bin(&a2, a2_, sizeof(a2_));
}
GroupConstants::~GroupConstants() {
secp256k1_num_free(&order);
secp256k1_num_free(&lambda);
secp256k1_num_free(&a1b2);
secp256k1_num_free(&b1);
secp256k1_num_free(&a2);
}
const GroupConstants &GetGroupConst() {
static const GroupConstants group_const;
return group_const;
}
void GroupElemJac::SetMulLambda(const GroupElemJac &p) {
const secp256k1_fe_t &beta = GetGroupConst().beta;
*this = p;
secp256k1_fe_mul(&x, &x, &beta);
}
void SplitExp(const secp256k1_num_t &exp, secp256k1_num_t &exp1, secp256k1_num_t &exp2) {
const GroupConstants &c = GetGroupConst();
secp256k1_num_t bnc1, bnc2, bnt1, bnt2, bnn2;
secp256k1_num_init(&bnc1);
secp256k1_num_init(&bnc2);
secp256k1_num_init(&bnt1);
secp256k1_num_init(&bnt2);
secp256k1_num_init(&bnn2);
secp256k1_num_copy(&bnn2, &c.order);
secp256k1_num_shift(&bnn2, 1);
secp256k1_num_mul(&bnc1, &exp, &c.a1b2);
secp256k1_num_add(&bnc1, &bnc1, &bnn2);
secp256k1_num_div(&bnc1, &bnc1, &c.order);
secp256k1_num_mul(&bnc2, &exp, &c.b1);
secp256k1_num_add(&bnc2, &bnc2, &bnn2);
secp256k1_num_div(&bnc2, &bnc2, &c.order);
secp256k1_num_mul(&bnt1, &bnc1, &c.a1b2);
secp256k1_num_mul(&bnt2, &bnc2, &c.a2);
secp256k1_num_add(&bnt1, &bnt1, &bnt2);
secp256k1_num_sub(&exp1, &exp, &bnt1);
secp256k1_num_mul(&bnt1, &bnc1, &c.b1);
secp256k1_num_mul(&bnt2, &bnc2, &c.a1b2);
secp256k1_num_sub(&exp2, &bnt1, &bnt2);
secp256k1_num_free(&bnc1);
secp256k1_num_free(&bnc2);
secp256k1_num_free(&bnt1);
secp256k1_num_free(&bnt2);
secp256k1_num_free(&bnn2);
}
}

113
src/group.h Normal file
View File

@@ -0,0 +1,113 @@
#ifndef _SECP256K1_GROUP_
#define _SECP256K1_GROUP_
#include <string>
#include "num.h"
#include "field.h"
namespace secp256k1 {
class GroupElemJac;
/** Defines a point on the secp256k1 curve (y^2 = x^3 + 7) */
class GroupElem {
protected:
bool fInfinity;
secp256k1_fe_t x;
secp256k1_fe_t y;
public:
/** Creates the point at infinity */
GroupElem();
/** Creates the point with given affine coordinates */
GroupElem(const secp256k1_fe_t &xin, const secp256k1_fe_t &yin);
/** Checks whether this is the point at infinity */
bool IsInfinity() const;
void SetNeg(const GroupElem &p);
void GetX(secp256k1_fe_t &xout);
void GetY(secp256k1_fe_t &yout);
std::string ToString() const;
void SetJac(GroupElemJac &jac);
friend class GroupElemJac;
};
/** Represents a point on the secp256k1 curve, with jacobian coordinates */
class GroupElemJac : private GroupElem {
protected:
secp256k1_fe_t z;
public:
/** Creates the point at infinity */
GroupElemJac();
/** Creates the point with given affine coordinates */
GroupElemJac(const secp256k1_fe_t &xin, const secp256k1_fe_t &yin);
GroupElemJac(const GroupElem &in);
void SetJac(const GroupElemJac &jac);
void SetAffine(const GroupElem &aff);
/** Checks whether this is a non-infinite point on the curve */
bool IsValid() const;
/** Returns the affine coordinates of this point */
void GetAffine(GroupElem &aff);
void GetX(secp256k1_fe_t &xout);
void GetY(secp256k1_fe_t &yout);
bool IsInfinity() const;
void SetNeg(const GroupElemJac &p);
/** Sets this point to have a given X coordinate & given Y oddness */
void SetCompressed(const secp256k1_fe_t &xin, bool fOdd);
/** Sets this point to be the EC double of another */
void SetDouble(const GroupElemJac &p);
/** Sets this point to be the EC addition of two others */
void SetAdd(const GroupElemJac &p, const GroupElemJac &q);
/** Sets this point to be the EC addition of two others (one of which is in affine coordinates) */
void SetAdd(const GroupElemJac &p, const GroupElem &q);
std::string ToString() const;
void SetMulLambda(const GroupElemJac &p);
};
class GroupConstants {
private:
secp256k1_fe_t g_x;
secp256k1_fe_t g_y;
public:
secp256k1_num_t order;
GroupElem g;
secp256k1_fe_t beta;
secp256k1_num_t lambda, a1b2, b1, a2;
GroupConstants();
~GroupConstants();
};
const GroupConstants &GetGroupConst();
void SplitExp(const secp256k1_num_t &exp, secp256k1_num_t &exp1, secp256k1_num_t &exp2);
}
#endif

7
src/num.cpp Normal file
View File

@@ -0,0 +1,7 @@
#if defined(USE_NUM_GMP)
#include "num_gmp.cpp"
#elif defined(USE_NUM_OPENSSL)
#include "num_openssl.cpp"
#else
#error "Please select num implementation"
#endif

44
src/num.h Normal file
View File

@@ -0,0 +1,44 @@
#ifndef _SECP256K1_NUM_
#define _SECP256K1_NUM_
#if defined(USE_NUM_GMP)
#include "num_gmp.h"
#elif defined(USE_NUM_OPENSSL)
#include "num_openssl.h"
#else
#error "Please select num implementation"
#endif
extern "C" {
void static secp256k1_num_start(void);
void static secp256k1_num_init(secp256k1_num_t *r);
void static secp256k1_num_free(secp256k1_num_t *r);
void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a);
void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a);
void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen);
void static secp256k1_num_set_int(secp256k1_num_t *r, int a);
void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m);
void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m);
int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b);
void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
int static secp256k1_num_bits(const secp256k1_num_t *a);
int static secp256k1_num_shift(secp256k1_num_t *r, int bits);
int static secp256k1_num_is_zero(const secp256k1_num_t *a);
int static secp256k1_num_is_odd(const secp256k1_num_t *a);
int static secp256k1_num_is_neg(const secp256k1_num_t *a);
int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos);
void static secp256k1_num_inc(secp256k1_num_t *r);
void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen);
void static secp256k1_num_get_hex(char *r, int *rlen, const secp256k1_num_t *a);
void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits);
void static secp256k1_num_negate(secp256k1_num_t *r);
void static secp256k1_num_set_rand(secp256k1_num_t *r, const secp256k1_num_t *a);
}
#endif

155
src/num_builtin.h Normal file
View File

@@ -0,0 +1,155 @@
#ifndef _SECP256K1_NUM_GMP_
#define _SECP256K1_NUM_GMP_
#include <assert.h>
#include <string>
#include <string.h>
#include <stdlib.h>
namespace secp256k1 {
class Number {
private:
uint64_t n[8]; // 512 bits ought to be enough for everyone
int top; // number of used entries in n
void FixTop() {
while (top > 0 && n[top-1] == 0)
top--;
}
int GetNumBytes() {
if (top==0)
return 0;
int ret = 8*(top-1);
uint64_t h = n[top-1];
while (h>0) {
ret++;
h >>= 8;
}
return ret;
}
Number(const Number &c) {}
public:
Number() {
top = 0;
}
Number(const unsigned char *bin, int len) {
top = 0;
SetBytes(bin, len);
}
Number &operator=(const Number &x) {
for (int pos = 0; pos < x.top; pos++)
n[pos] = x.n[pos];
top = x.top;
}
void SetNumber(const Number &x) {
*this = x;
}
void SetBytes(const unsigned char *bin, unsigned int len) {
n[0] = n[1] = n[2] = n[3] = n[4] = n[5] = n[6] = n[7] = 0;
assert(len<=64);
for (int pos = 0; pos < len; pos++)
n[(len-1-pos)/8] |= ((uint64_t)(bin[pos])) << (((len-1-pos)%8)*8);
top = 8;
FixTop();
}
void GetBytes(unsigned char *bin, unsigned int len) {
unsigned int size = GetNumBytes();
assert(size <= len);
memset(bin,0,len);
for (int i=0; i<size; i++)
bin[i] = (n[(size-i-1)/8] >> (((size-1-i)%8)*8)) & 0xFF;
}
void SetInt(int x) {
n[0] = x;
top = 1;
FixTop();
}
void SetModInverse(const Number &x, const Number &m) {
mpz_invert(bn, x.bn, m.bn);
}
void SetModMul(const Number &a, const Number &b, const Number &m) {
mpz_mul(bn, a.bn, b.bn);
mpz_mod(bn, bn, m.bn);
}
void SetAdd(const Number &a1, const Number &a2) {
mpz_add(bn, a1.bn, a2.bn);
}
void SetSub(const Number &a1, const Number &a2) {
mpz_sub(bn, a1.bn, a2.bn);
}
void SetMult(const Number &a1, const Number &a2) {
mpz_mul(bn, a1.bn, a2.bn);
}
void SetDiv(const Number &a1, const Number &a2) {
mpz_tdiv_q(bn, a1.bn, a2.bn);
}
void SetMod(const Number &a, const Number &m) {
mpz_mod(bn, a.bn, m.bn);
}
int Compare(const Number &a) const {
return mpz_cmp(bn, a.bn);
}
int GetBits() const {
return mpz_sizeinbase(bn,2);
}
// return the lowest (rightmost) bits bits, and rshift them away
int ShiftLowBits(int bits) {
int ret = mpz_get_ui(bn) & ((1 << bits) - 1);
mpz_fdiv_q_2exp(bn, bn, bits);
return ret;
}
// check whether number is 0,
bool IsZero() const {
return mpz_size(bn) == 0;
}
bool IsOdd() const {
return mpz_get_ui(bn) & 1;
}
bool IsNeg() const {
return mpz_sgn(bn) < 0;
}
void Negate() {
mpz_neg(bn, bn);
}
void Shift1() {
mpz_fdiv_q_2exp(bn, bn, 1);
}
void Inc() {
mpz_add_ui(bn, bn, 1);
}
void SetHex(const std::string &str) {
mpz_set_str(bn, str.c_str(), 16);
}
void SetPseudoRand(const Number &max) {
number_state.gen(bn, max.bn);
}
void SplitInto(int bits, Number &low, Number &high) const {
mpz_t tmp;
mpz_init_set_ui(tmp,1);
mpz_mul_2exp(tmp,tmp,bits);
mpz_sub_ui(tmp,tmp,1);
mpz_and(low.bn, bn, tmp);
mpz_clear(tmp);
mpz_fdiv_q_2exp(high.bn, bn, bits);
}
std::string ToString() const {
char *str = (char*)malloc(mpz_sizeinbase(bn,16) + 2);
mpz_get_str(str, 16, bn);
std::string ret(str);
free(str);
return ret;
}
};
}
#endif

152
src/num_gmp.cpp Normal file
View File

@@ -0,0 +1,152 @@
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <gmp.h>
#include "num.h"
extern "C" {
typedef struct {
int initialized;
gmp_randstate_t rng;
} secp256k1_num_state_t;
static secp256k1_num_state_t secp256k1_num_state = {};
void static secp256k1_num_start(void) {
if (secp256k1_num_state.initialized)
return;
secp256k1_num_state.initialized = 1;
gmp_randinit_default(secp256k1_num_state.rng);
}
void static secp256k1_num_init(secp256k1_num_t *r) {
mpz_init(r->bn);
}
void static secp256k1_num_free(secp256k1_num_t *r) {
mpz_clear(r->bn);
}
void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
mpz_set(r->bn, a->bn);
}
void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
unsigned int size = (mpz_sizeinbase(a->bn,2)+7)/8;
assert(size <= rlen);
memset(r,0,rlen);
size_t count = 0;
mpz_export(r + rlen - size, &count, 1, 1, 1, 0, a->bn);
assert(count == 0 || size == count);
}
void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
mpz_import(r->bn, alen, 1, 1, 1, 0, a);
}
void static secp256k1_num_set_int(secp256k1_num_t *r, int a) {
mpz_set_si(r->bn, a);
}
void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) {
mpz_invert(r->bn, a->bn, m->bn);
}
void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m) {
mpz_mul(r->bn, a->bn, b->bn);
mpz_mod(r->bn, r->bn, m->bn);
}
int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) {
return mpz_cmp(a->bn, b->bn);
}
void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
mpz_add(r->bn, a->bn, b->bn);
}
void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
mpz_sub(r->bn, a->bn, b->bn);
}
void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
mpz_mul(r->bn, a->bn, b->bn);
}
void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
mpz_tdiv_q(r->bn, a->bn, b->bn);
}
void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
mpz_mod(r->bn, a->bn, b->bn);
}
int static secp256k1_num_bits(const secp256k1_num_t *a) {
return mpz_sizeinbase(a->bn,2);
}
int static secp256k1_num_shift(secp256k1_num_t *r, int bits) {
int ret = mpz_get_ui(r->bn) & ((1 << bits) - 1);
mpz_fdiv_q_2exp(r->bn, r->bn, bits);
return ret;
}
int static secp256k1_num_is_zero(const secp256k1_num_t *a) {
return mpz_size(a->bn) == 0;
}
int static secp256k1_num_is_odd(const secp256k1_num_t *a) {
return mpz_get_ui(a->bn) & 1;
}
int static secp256k1_num_is_neg(const secp256k1_num_t *a) {
return mpz_sgn(a->bn) < 0;
}
int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos) {
return mpz_tstbit(a->bn, pos);
}
void static secp256k1_num_inc(secp256k1_num_t *r) {
mpz_add_ui(r->bn, r->bn, 1);
}
void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen) {
char *str = (char*)malloc(alen+1);
memcpy(str, a, alen);
str[alen] = 0;
mpz_set_str(r->bn, str, 16);
free(str);
}
void static secp256k1_num_get_hex(char *r, int *rlen, const secp256k1_num_t *a) {
int len = mpz_sizeinbase(a->bn, 16) + 2;
if (*rlen < len) {
*rlen = len;
return;
}
mpz_get_str(r, 16, a->bn);
*rlen = len;
}
void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits) {
mpz_t tmp;
mpz_init_set_ui(tmp,1);
mpz_mul_2exp(tmp, tmp, bits);
mpz_sub_ui(tmp,tmp,1);
mpz_and(rl->bn, a->bn, tmp);
mpz_clear(tmp);
mpz_fdiv_q_2exp(rh->bn, a->bn, bits);
}
void static secp256k1_num_negate(secp256k1_num_t *r) {
mpz_neg(r->bn, r->bn);
}
void static secp256k1_num_set_rand(secp256k1_num_t *r, const secp256k1_num_t *a) {
mpz_urandomm(r->bn, secp256k1_num_state.rng, a->bn);
}
}

14
src/num_gmp.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef _SECP256K1_NUM_GMP_
#define _SECP256K1_NUM_GMP_
#include <gmp.h>
extern "C" {
typedef struct {
mpz_t bn;
} secp256k1_num_t;
}
#endif

146
src/num_openssl.cpp Normal file
View File

@@ -0,0 +1,146 @@
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include "num.h"
void static secp256k1_num_start() {
}
void static secp256k1_num_init(secp256k1_num_t *r) {
BN_init(&r->bn);
}
void static secp256k1_num_free(secp256k1_num_t *r) {
BN_free(&r->bn);
}
void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
BN_copy(&r->bn, &a->bn);
}
void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
unsigned int size = BN_num_bytes(&a->bn);
assert(size <= rlen);
memset(r,0,rlen);
BN_bn2bin(&a->bn, r + rlen - size);
}
void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
BN_bin2bn(a, alen, &r->bn);
}
void static secp256k1_num_set_int(secp256k1_num_t *r, int a) {
BN_set_word(&r->bn, a < 0 ? -a : a);
BN_set_negative(&r->bn, a < 0);
}
void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) {
BN_CTX *ctx = BN_CTX_new();
BN_mod_inverse(&r->bn, &a->bn, &m->bn, ctx);
BN_CTX_free(ctx);
}
void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m) {
BN_CTX *ctx = BN_CTX_new();
BN_mod_mul(&r->bn, &a->bn, &b->bn, &m->bn, ctx);
BN_CTX_free(ctx);
}
int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) {
return BN_cmp(&a->bn, &b->bn);
}
void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
BN_add(&r->bn, &a->bn, &b->bn);
}
void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
BN_sub(&r->bn, &a->bn, &b->bn);
}
void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
BN_CTX *ctx = BN_CTX_new();
BN_mul(&r->bn, &a->bn, &b->bn, ctx);
BN_CTX_free(ctx);
}
void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
BN_CTX *ctx = BN_CTX_new();
BN_div(&r->bn, NULL, &a->bn, &b->bn, ctx);
BN_CTX_free(ctx);
}
void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
BN_CTX *ctx = BN_CTX_new();
BN_nnmod(&r->bn, &a->bn, &b->bn, ctx);
BN_CTX_free(ctx);
}
int static secp256k1_num_bits(const secp256k1_num_t *a) {
return BN_num_bits(&a->bn);
}
int static secp256k1_num_shift(secp256k1_num_t *r, int bits) {
int ret = BN_is_zero(&r->bn) ? 0 : r->bn.d[0] & ((1 << bits) - 1);
BN_rshift(&r->bn, &r->bn, bits);
return ret;
}
int static secp256k1_num_is_zero(const secp256k1_num_t *a) {
return BN_is_zero(&a->bn);
}
int static secp256k1_num_is_odd(const secp256k1_num_t *a) {
return BN_is_odd(&a->bn);
}
int static secp256k1_num_is_neg(const secp256k1_num_t *a) {
return BN_is_negative(&a->bn);
}
int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos) {
return BN_is_bit_set(&a->bn, pos);
}
void static secp256k1_num_inc(secp256k1_num_t *r) {
BN_add_word(&r->bn, 1);
}
void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen) {
char *str = (char*)malloc(alen+1);
memcpy(str, a, alen);
str[alen] = 0;
BIGNUM *pbn = &r->bn;
BN_hex2bn(&pbn, str);
free(str);
}
void static secp256k1_num_get_hex(char *r, int *rlen, const secp256k1_num_t *a) {
char *str = BN_bn2hex(&a->bn);
int len = strlen(str) + 1;
if (len > *rlen) {
*rlen = strlen(str);
OPENSSL_free(str);
return;
}
memcpy(r, str, len);
OPENSSL_free(str);
*rlen = len;
}
void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits) {
BN_copy(&rl->bn, &a->bn);
BN_rshift(&rh->bn, &a->bn, bits);
BN_mask_bits(&rl->bn, bits);
}
void static secp256k1_num_negate(secp256k1_num_t *r) {
BN_set_negative(&r->bn, !BN_is_negative(&r->bn));
}
void static secp256k1_num_set_rand(secp256k1_num_t *r, const secp256k1_num_t *a) {
BN_pseudo_rand_range(&r->bn, &a->bn);
}

10
src/num_openssl.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef _SECP256K1_NUM_OPENSSL_
#define _SECP256K1_NUM_OPENSSL_
#include <openssl/bn.h>
typedef struct {
BIGNUM bn;
} secp256k1_num_t;
#endif

183
src/num_openssl_.cpp Normal file
View File

@@ -0,0 +1,183 @@
#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;
}
}

38
src/secp256k1.cpp Normal file
View File

@@ -0,0 +1,38 @@
#include "num.cpp"
#include "field.cpp"
#include "group.cpp"
#include "ecmult.cpp"
#include "ecdsa.cpp"
namespace secp256k1 {
int VerifyECDSA(const unsigned char *msg, int msglen, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) {
int ret = -3;
secp256k1_num_t m;
secp256k1_num_init(&m);
Signature s;
GroupElemJac q;
secp256k1_num_set_bin(&m, msg, msglen);
if (!ParsePubKey(q, pubkey, pubkeylen)) {
ret = -1;
goto end;
}
if (!s.Parse(sig, siglen)) {
fprintf(stderr, "Can't parse signature: ");
for (int i=0; i<siglen; i++) fprintf(stderr,"%02x", sig[i]);
fprintf(stderr, "\n");
ret = -2;
goto end;
}
if (!s.Verify(q, m)) {
ret = 0;
goto end;
}
ret = 1;
end:
secp256k1_num_free(&m);
return ret;
}
}

187
src/tests.cpp Normal file
View File

@@ -0,0 +1,187 @@
#include <assert.h>
#include "num.cpp"
#include "field.cpp"
#include "group.cpp"
#include "ecmult.cpp"
#include "ecdsa.cpp"
// #define COUNT 2
#define COUNT 100
using namespace secp256k1;
void test_run_ecmult_chain() {
// random starting point A (on the curve)
secp256k1_fe_t ax; secp256k1_fe_set_hex(&ax, "8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004", 64);
secp256k1_fe_t ay; secp256k1_fe_set_hex(&ay, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64);
GroupElemJac a(ax,ay);
// two random initial factors xn and gn
secp256k1_num_t xn;
secp256k1_num_init(&xn);
secp256k1_num_set_hex(&xn, "84cc5452f7fde1edb4d38a8ce9b1b84ccef31f146e569be9705d357a42985407", 64);
secp256k1_num_t gn;
secp256k1_num_init(&gn);
secp256k1_num_set_hex(&gn, "a1e58d22553dcd42b23980625d4c57a96e9323d42b3152e5ca2c3990edc7c9de", 64);
// two small multipliers to be applied to xn and gn in every iteration:
secp256k1_num_t xf;
secp256k1_num_init(&xf);
secp256k1_num_set_hex(&xf, "1337", 4);
secp256k1_num_t gf;
secp256k1_num_init(&gf);
secp256k1_num_set_hex(&gf, "7113", 4);
// accumulators with the resulting coefficients to A and G
secp256k1_num_t ae;
secp256k1_num_init(&ae);
secp256k1_num_set_int(&ae, 1);
secp256k1_num_t ge;
secp256k1_num_init(&ge);
secp256k1_num_set_int(&ge, 0);
// the point being computed
GroupElemJac x = a;
const secp256k1_num_t &order = GetGroupConst().order;
for (int i=0; i<200*COUNT; i++) {
// in each iteration, compute X = xn*X + gn*G;
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);
secp256k1_num_mod_mul(&ge, &ge, &xn, &order);
secp256k1_num_add(&ge, &ge, &gn);
secp256k1_num_mod(&ge, &ge, &order);
// modify xn and gn
secp256k1_num_mod_mul(&xn, &xn, &xf, &order);
secp256k1_num_mod_mul(&gn, &gn, &gf, &order);
}
std::string res = x.ToString();
if (COUNT == 100) {
assert(res == "(D6E96687F9B10D092A6F35439D86CEBEA4535D0D409F53586440BD74B933E830,B95CBCA2C77DA786539BE8FD53354D2D3B4F566AE658045407ED6015EE1B2A88)");
}
// redo the computation, but directly with the resulting ae and ge coefficients:
GroupElemJac x2; ECMult(x2, a, ae, ge);
std::string res2 = x2.ToString();
assert(res == res2);
secp256k1_num_free(&xn);
secp256k1_num_free(&gn);
secp256k1_num_free(&xf);
secp256k1_num_free(&gf);
secp256k1_num_free(&ae);
secp256k1_num_free(&ge);
}
void test_point_times_order(const GroupElemJac &point) {
// either the point is not on the curve, or multiplying it by the order results in O
if (!point.IsValid())
return;
const GroupConstants &c = GetGroupConst();
secp256k1_num_t zero;
secp256k1_num_init(&zero);
secp256k1_num_set_int(&zero, 0);
GroupElemJac res;
ECMult(res, point, c.order, zero); // calc res = order * point + 0 * G;
assert(res.IsInfinity());
secp256k1_num_free(&zero);
}
void test_run_point_times_order() {
secp256k1_fe_t x; secp256k1_fe_set_hex(&x, "02", 2);
for (int i=0; i<500; i++) {
GroupElemJac j; j.SetCompressed(x, true);
test_point_times_order(j);
secp256k1_fe_sqr(&x, &x);
}
char c[65]; int cl=65;
secp256k1_fe_get_hex(c, &cl, &x);
assert(strcmp(c, "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45") == 0);
}
void test_wnaf(const secp256k1_num_t &number, int w) {
secp256k1_num_t x, two, t;
secp256k1_num_init(&x);
secp256k1_num_init(&two);
secp256k1_num_init(&t);
secp256k1_num_set_int(&x, 0);
secp256k1_num_set_int(&two, 2);
WNAF<1023> wnaf(number, w);
int zeroes = -1;
for (int i=wnaf.GetSize()-1; i>=0; i--) {
secp256k1_num_mul(&x, &x, &two);
int v = wnaf.Get(i);
if (v) {
assert(zeroes == -1 || zeroes >= w-1); // check that distance between non-zero elements is at least w-1
zeroes=0;
assert((v & 1) == 1); // check non-zero elements are odd
assert(v <= (1 << (w-1)) - 1); // check range below
assert(v >= -(1 << (w-1)) - 1); // check range above
} else {
assert(zeroes != -1); // check that no unnecessary zero padding exists
zeroes++;
}
secp256k1_num_set_int(&t, v);
secp256k1_num_add(&x, &x, &t);
}
assert(secp256k1_num_cmp(&x, &number) == 0); // check that wnaf represents number
secp256k1_num_free(&x);
secp256k1_num_free(&two);
secp256k1_num_free(&t);
}
void test_run_wnaf() {
secp256k1_num_t range, min, n;
secp256k1_num_init(&range);
secp256k1_num_init(&min);
secp256k1_num_init(&n);
secp256k1_num_set_hex(&range, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 256);
secp256k1_num_copy(&min, &range);
secp256k1_num_shift(&min, 1);
secp256k1_num_negate(&min);
for (int i=0; i<COUNT; i++) {
secp256k1_num_set_rand(&n, &range);
secp256k1_num_add(&n, &n, &min);
test_wnaf(n, 4+(i%10));
}
secp256k1_num_free(&range);
secp256k1_num_free(&min);
secp256k1_num_free(&n);
}
void test_ecdsa_sign_verify() {
const GroupConstants &c = GetGroupConst();
secp256k1_num_t msg, key, nonce;
secp256k1_num_init(&msg);
secp256k1_num_set_rand(&msg, &c.order);
secp256k1_num_init(&key);
secp256k1_num_set_rand(&key, &c.order);
secp256k1_num_init(&nonce);
GroupElemJac pub; ECMultBase(pub, key);
Signature sig;
do {
secp256k1_num_set_rand(&nonce, &c.order);
} while(!sig.Sign(key, msg, nonce));
assert(sig.Verify(pub, msg));
secp256k1_num_inc(&msg);
assert(!sig.Verify(pub, msg));
secp256k1_num_free(&msg);
secp256k1_num_free(&key);
secp256k1_num_free(&nonce);
}
void test_run_ecdsa_sign_verify() {
for (int i=0; i<10*COUNT; i++) {
test_ecdsa_sign_verify();
}
}
int main(void) {
secp256k1_num_start();
secp256k1_fe_start();
test_run_wnaf();
test_run_point_times_order();
test_run_ecmult_chain();
test_run_ecdsa_sign_verify();
secp256k1_fe_stop();
return 0;
}