0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-09 10:43:19 -05:00

Merge pull request #9 from sipa/cify

Second step in converting to C: field
This commit is contained in:
Pieter Wuille 2013-03-30 18:11:01 -07:00
commit f6ec29d956
9 changed files with 558 additions and 545 deletions

View file

@ -9,15 +9,17 @@
using namespace secp256k1;
int main() {
FieldElem x;
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_start();
secp256k1_num_init(&r);
secp256k1_num_init(&s);
secp256k1_num_init(&m);
Signature sig;
x.SetHex("a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f");
secp256k1_fe_set_hex(&x, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64);
int cnt = 0;
int good = 0;
for (int i=0; i<1000000; i++) {
@ -35,5 +37,7 @@ int main() {
secp256k1_num_free(&r);
secp256k1_num_free(&s);
secp256k1_num_free(&m);
secp256k1_fe_stop();
return 0;
}

View file

@ -8,15 +8,15 @@ namespace secp256k1 {
bool ParsePubKey(GroupElemJac &elem, const unsigned char *pub, int size) {
if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
FieldElem x;
x.SetBytes(pub+1);
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)) {
FieldElem x,y;
x.SetBytes(pub+1);
y.SetBytes(pub+33);
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) && y.IsOdd() != (pub[0] == 0x07))
if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07))
return false;
} else {
return false;
@ -81,9 +81,9 @@ bool Signature::RecomputeR(secp256k1_num_t &r2, const GroupElemJac &pubkey, cons
secp256k1_num_mod_mul(&u2, &sn, &r, &c.order);
GroupElemJac pr; ECMult(pr, pubkey, u2, u1);
if (!pr.IsInfinity()) {
FieldElem xr; pr.GetX(xr);
xr.Normalize();
unsigned char xrb[32]; xr.GetBytes(xrb);
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;
@ -108,11 +108,11 @@ bool Signature::Sign(const secp256k1_num_t &seckey, const secp256k1_num_t &messa
GroupElemJac rp;
ECMultBase(rp, nonce);
FieldElem rx;
secp256k1_fe_t rx;
rp.GetX(rx);
unsigned char b[32];
rx.Normalize();
rx.GetBytes(b);
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;

154
field.cpp
View file

@ -1,25 +1,151 @@
// just one implementation for now
#include "field_5x52.cpp"
namespace secp256k1 {
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
};
static const unsigned char field_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};
FieldConstants::FieldConstants() {
secp256k1_num_init(&field_p);
secp256k1_num_set_bin(&field_p, field_p_, sizeof(field_p_));
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;
}
}
FieldConstants::~FieldConstants() {
secp256k1_num_free(&field_p);
void static secp256k1_fe_stop(void) {
if (secp256k1_fe_consts != NULL) {
free((void*)secp256k1_fe_consts);
secp256k1_fe_consts = NULL;
}
}
const FieldConstants &GetFieldConst() {
static const FieldConstants field_const;
return field_const;
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_FIELDINVERSE_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
}

85
field.h
View file

@ -1,21 +1,88 @@
#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"
namespace secp256k1 {
typedef struct {
secp256k1_num_t p;
} secp256k1_fe_consts_t;
class FieldConstants {
public:
secp256k1_num_t field_p;
static const secp256k1_fe_consts_t *secp256k1_fe_consts = NULL;
FieldConstants();
~FieldConstants();
};
/** Initialize field element precomputation data. */
void static secp256k1_fe_start(void);
const FieldConstants &GetFieldConst();
/** 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

View file

@ -1,18 +1,12 @@
#include <assert.h>
#include <stdint.h>
#include <string>
#include <string.h>
#include "num.h"
#include "field.h"
#include <iostream>
using namespace std;
#ifdef INLINE_ASM
#include "lin64.h"
#endif
namespace secp256k1 {
/** 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
@ -21,30 +15,17 @@ namespace secp256k1 {
* output.
*/
FieldElem::FieldElem(int x) {
n[0] = x;
n[1] = n[2] = n[3] = n[4] = 0;
#ifdef VERIFY_MAGNITUDE
magnitude = 1;
normalized = true;
#endif
}
FieldElem::FieldElem(const unsigned char *b32) {
SetBytes(b32);
}
void FieldElem::Normalize() {
void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
uint64_t c;
c = n[0];
c = r->n[0];
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + n[1];
c = (c >> 52) + r->n[1];
uint64_t t1 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + n[2];
c = (c >> 52) + r->n[2];
uint64_t t2 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + n[3];
c = (c >> 52) + r->n[3];
uint64_t t3 = c & 0xFFFFFFFFFFFFFULL;
c = (c >> 52) + n[4];
c = (c >> 52) + r->n[4];
uint64_t t4 = c & 0x0FFFFFFFFFFFFULL;
c >>= 48;
@ -60,149 +41,166 @@ void FieldElem::Normalize() {
c = (c >> 52) + t4;
t4 = c & 0x0FFFFFFFFFFFFULL;
// Replace n's with t's if one of the n's overflows.
// If none of the n's overflow to begin with, the t's will just be the n's already and
// we effectively ignore the results of the previous computations.
n[0] = t0; n[1] = t1; n[2] = t2; n[3] = t3; n[4] = t4;
// Subtract p if result >= p
uint64_t mask = -(int64_t)((n[4] < 0xFFFFFFFFFFFFULL) | (n[3] < 0xFFFFFFFFFFFFFULL) | (n[2] < 0xFFFFFFFFFFFFFULL) | (n[1] < 0xFFFFFFFFFFFFFULL) | (n[0] < 0xFFFFEFFFFFC2FULL));
n[4] &= mask;
n[3] &= mask;
n[2] &= mask;
n[1] &= mask;
n[0] -= (~mask & 0xFFFFEFFFFFC2FULL);
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);
#ifdef VERIFY_MAGNITUDE
magnitude = 1;
normalized = true;
// 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
}
bool inline FieldElem::IsZero() const {
#ifdef VERIFY_MAGNITUDE
assert(normalized);
void static 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
return (n[0] == 0 && n[1] == 0 && n[2] == 0 && n[3] == 0 && n[4] == 0);
}
bool inline operator==(const FieldElem &a, const FieldElem &b) {
#ifdef VERIFY_MAGNITUDE
assert(a.normalized);
assert(b.normalized);
// TODO: not constant time!
int static secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->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]);
return (a->n[0] == 0 && a->n[1] == 0 && a->n[2] == 0 && a->n[3] == 0 && a->n[4] == 0);
}
void FieldElem::GetBytes(unsigned char *o) {
#ifdef VERIFY_MAGNITUDE
assert(normalized);
int static 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 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 |= ((n[limb] >> shift) & 0xF) << (4 * j);
c |= ((a->n[limb] >> shift) & 0xF) << (4 * j);
}
o[31-i] = c;
r[31-i] = c;
}
}
void FieldElem::SetBytes(const unsigned char *in) {
n[0] = n[1] = n[2] = n[3] = 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;
n[limb] |= (uint64_t)((in[31-i] >> (4*j)) & 0xF) << shift;
}
}
#ifdef VERIFY_MAGNITUDE
magnitude = 1;
normalized = true;
void static 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 inline FieldElem::SetNeg(const FieldElem &a, int magnitudeIn) {
#ifdef VERIFY_MAGNITUDE
assert(a.magnitude <= magnitudeIn);
magnitude = magnitudeIn + 1;
normalized = false;
void static secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
#ifdef VERIFY
r->magnitude *= a;
r->normalized = false;
#endif
n[0] = 0xFFFFEFFFFFC2FULL * (magnitudeIn + 1) - a.n[0];
n[1] = 0xFFFFFFFFFFFFFULL * (magnitudeIn + 1) - a.n[1];
n[2] = 0xFFFFFFFFFFFFFULL * (magnitudeIn + 1) - a.n[2];
n[3] = 0xFFFFFFFFFFFFFULL * (magnitudeIn + 1) - a.n[3];
n[4] = 0x0FFFFFFFFFFFFULL * (magnitudeIn + 1) - a.n[4];
r->n[0] *= a;
r->n[1] *= a;
r->n[2] *= a;
r->n[3] *= a;
r->n[4] *= a;
}
void inline FieldElem::operator*=(int v) {
#ifdef VERIFY_MAGNITUDE
magnitude *= v;
normalized = false;
void static secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
r->magnitude += a->magnitude;
r->normalized = 0;
#endif
n[0] *= v;
n[1] *= v;
n[2] *= v;
n[3] *= v;
n[4] *= v;
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 inline FieldElem::operator+=(const FieldElem &a) {
#ifdef VERIFY_MAGNITUDE
magnitude += a.magnitude;
normalized = false;
#endif
n[0] += a.n[0];
n[1] += a.n[1];
n[2] += a.n[2];
n[3] += a.n[3];
n[4] += a.n[4];
}
void FieldElem::SetMult(const FieldElem &a, const FieldElem &b) {
#ifdef VERIFY_MAGNITUDE
assert(a.magnitude <= 8);
assert(b.magnitude <= 8);
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);
#endif
#ifdef INLINE_ASM
ExSetMult((uint64_t *) a.n,(uint64_t *) b.n, (uint64_t *) n);
ExSetMult((uint64_t*)a->n, (uint64_t*)b->n, (uint64_t*)r->n);
#else
unsigned __int128 c = (__int128)a.n[0] * b.n[0];
unsigned __int128 c = (__int128)a->n[0] * b->n[0];
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0
c = c + (__int128)a.n[0] * b.n[1] +
(__int128)a.n[1] * b.n[0];
c = c + (__int128)a->n[0] * b->n[1] +
(__int128)a->n[1] * b->n[0];
uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF
c = c + (__int128)a.n[0] * b.n[2] +
(__int128)a.n[1] * b.n[1] +
(__int128)a.n[2] * b.n[0];
c = c + (__int128)a->n[0] * b->n[2] +
(__int128)a->n[1] * b->n[1] +
(__int128)a->n[2] * b->n[0];
uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0
c = c + (__int128)a.n[0] * b.n[3] +
(__int128)a.n[1] * b.n[2] +
(__int128)a.n[2] * b.n[1] +
(__int128)a.n[3] * b.n[0];
c = c + (__int128)a->n[0] * b->n[3] +
(__int128)a->n[1] * b->n[2] +
(__int128)a->n[2] * b->n[1] +
(__int128)a->n[3] * b->n[0];
uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280
c = c + (__int128)a.n[0] * b.n[4] +
(__int128)a.n[1] * b.n[3] +
(__int128)a.n[2] * b.n[2] +
(__int128)a.n[3] * b.n[1] +
(__int128)a.n[4] * b.n[0];
c = c + (__int128)a->n[0] * b->n[4] +
(__int128)a->n[1] * b->n[3] +
(__int128)a->n[2] * b->n[2] +
(__int128)a->n[3] * b->n[1] +
(__int128)a->n[4] * b->n[0];
uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E
c = c + (__int128)a.n[1] * b.n[4] +
(__int128)a.n[2] * b.n[3] +
(__int128)a.n[3] * b.n[2] +
(__int128)a.n[4] * b.n[1];
c = c + (__int128)a->n[1] * b->n[4] +
(__int128)a->n[2] * b->n[3] +
(__int128)a->n[3] * b->n[2] +
(__int128)a->n[4] * b->n[1];
uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE
c = c + (__int128)a.n[2] * b.n[4] +
(__int128)a.n[3] * b.n[3] +
(__int128)a.n[4] * b.n[2];
c = c + (__int128)a->n[2] * b->n[4] +
(__int128)a->n[3] * b->n[3] +
(__int128)a->n[4] * b->n[2];
uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE
c = c + (__int128)a.n[3] * b.n[4] +
(__int128)a.n[4] * b.n[3];
c = c + (__int128)a->n[3] * b->n[4] +
(__int128)a->n[4] * b->n[3];
uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE
c = c + (__int128)a.n[4] * b.n[4];
c = c + (__int128)a->n[4] * b->n[4];
uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E
uint64_t t9 = c;
@ -211,52 +209,52 @@ void FieldElem::SetMult(const FieldElem &a, const FieldElem &b) {
c = c + t1 + (__int128)t6 * 0x1000003D10ULL;
t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t2 + (__int128)t7 * 0x1000003D10ULL;
n[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
r->n[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t3 + (__int128)t8 * 0x1000003D10ULL;
n[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
r->n[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t4 + (__int128)t9 * 0x1000003D10ULL;
n[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110
r->n[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110
c = t0 + (__int128)c * 0x1000003D1ULL;
n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008
n[1] = t1 + c;
r->n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008
r->n[1] = t1 + c;
#endif
#ifdef VERIFY_MAGNITUDE
magnitude = 1;
normalized = false;
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 0;
#endif
}
void FieldElem::SetSquare(const FieldElem &a) {
#ifdef VERIFY_MAGNITUDE
assert(a.magnitude <= 8);
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
assert(a->magnitude <= 8);
#endif
#ifdef INLINE_ASM
ExSetSquare((uint64_t *)a.n,(uint64_t *)n);
ExSetSquare((uint64_t*)&a->n, (uint64_t*)&r->n);
#else
__int128 c = (__int128)a.n[0] * a.n[0];
__int128 c = (__int128)a->n[0] * a->n[0];
uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0
c = c + (__int128)(a.n[0]*2) * a.n[1];
c = c + (__int128)(a->n[0]*2) * a->n[1];
uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF
c = c + (__int128)(a.n[0]*2) * a.n[2] +
(__int128)a.n[1] * a.n[1];
c = c + (__int128)(a->n[0]*2) * a->n[2] +
(__int128)a->n[1] * a->n[1];
uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0
c = c + (__int128)(a.n[0]*2) * a.n[3] +
(__int128)(a.n[1]*2) * a.n[2];
c = c + (__int128)(a->n[0]*2) * a->n[3] +
(__int128)(a->n[1]*2) * a->n[2];
uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280
c = c + (__int128)(a.n[0]*2) * a.n[4] +
(__int128)(a.n[1]*2) * a.n[3] +
(__int128)a.n[2] * a.n[2];
c = c + (__int128)(a->n[0]*2) * a->n[4] +
(__int128)(a->n[1]*2) * a->n[3] +
(__int128)a->n[2] * a->n[2];
uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E
c = c + (__int128)(a.n[1]*2) * a.n[4] +
(__int128)(a.n[2]*2) * a.n[3];
c = c + (__int128)(a->n[1]*2) * a->n[4] +
(__int128)(a->n[2]*2) * a->n[3];
uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE
c = c + (__int128)(a.n[2]*2) * a.n[4] +
(__int128)a.n[3] * a.n[3];
c = c + (__int128)(a->n[2]*2) * a->n[4] +
(__int128)a->n[3] * a->n[3];
uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE
c = c + (__int128)(a.n[3]*2) * a.n[4];
c = c + (__int128)(a->n[3]*2) * a->n[4];
uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE
c = c + (__int128)a.n[4] * a.n[4];
c = c + (__int128)a->n[4] * a->n[4];
uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E
uint64_t t9 = c;
c = t0 + (__int128)t5 * 0x1000003D10ULL;
@ -264,149 +262,18 @@ void FieldElem::SetSquare(const FieldElem &a) {
c = c + t1 + (__int128)t6 * 0x1000003D10ULL;
t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t2 + (__int128)t7 * 0x1000003D10ULL;
n[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
r->n[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t3 + (__int128)t8 * 0x1000003D10ULL;
n[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
r->n[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10
c = c + t4 + (__int128)t9 * 0x1000003D10ULL;
n[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110
r->n[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110
c = t0 + (__int128)c * 0x1000003D1ULL;
n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008
n[1] = t1 + c;
r->n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008
r->n[1] = t1 + c;
#endif
#ifdef VERIFY_MAGNITUDE
assert(a.magnitude <= 8);
normalized = false;
#ifdef VERIFY
assert(a->magnitude <= 8);
a->normalized = 0;
#endif
}
void FieldElem::SetSquareRoot(const FieldElem &a) {
// calculate a^p, with p={15,780,1022,1023}
FieldElem a2; a2.SetSquare(a);
FieldElem a3; a3.SetMult(a2,a);
FieldElem a6; a6.SetSquare(a3);
FieldElem a12; a12.SetSquare(a6);
FieldElem a15; a15.SetMult(a12,a3);
FieldElem a30; a30.SetSquare(a15);
FieldElem a60; a60.SetSquare(a30);
FieldElem a120; a120.SetSquare(a60);
FieldElem a240; a240.SetSquare(a120);
FieldElem a255; a255.SetMult(a240,a15);
FieldElem a510; a510.SetSquare(a255);
FieldElem a750; a750.SetMult(a510,a240);
FieldElem a780; a780.SetMult(a750,a30);
FieldElem a1020; a1020.SetSquare(a510);
FieldElem a1022; a1022.SetMult(a1020,a2);
FieldElem a1023; a1023.SetMult(a1022,a);
FieldElem x = a15;
for (int i=0; i<21; i++) {
for (int j=0; j<10; j++) x.SetSquare(x);
x.SetMult(x,a1023);
}
for (int j=0; j<10; j++) x.SetSquare(x);
x.SetMult(x,a1022);
for (int i=0; i<2; i++) {
for (int j=0; j<10; j++) x.SetSquare(x);
x.SetMult(x,a1023);
}
for (int j=0; j<10; j++) x.SetSquare(x);
SetMult(x,a780);
}
bool FieldElem::IsOdd() const {
#ifdef VERIFY_MAGNITUDE
assert(normalized);
#endif
return n[0] & 1;
}
std::string FieldElem::ToString() {
unsigned char tmp[32];
Normalize();
GetBytes(tmp);
std::string ret;
for (int i=0; i<32; i++) {
static const char *c = "0123456789ABCDEF";
ret += c[(tmp[i] >> 4) & 0xF];
ret += c[(tmp[i]) & 0xF];
}
return ret;
}
void FieldElem::SetHex(const std::string &str) {
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 (unsigned int i=0; i<32; i++) {
if (str.length() > i*2)
tmp[32 - str.length()/2 + i] = (cvt[(unsigned char)str[2*i]] << 4) + cvt[(unsigned char)str[2*i+1]];
}
SetBytes(tmp);
}
// Nonbuiltin Field Inverse is not constant time.
void FieldElem::SetInverse(FieldElem &a) {
#if defined(USE_FIELDINVERSE_BUILTIN)
// calculate a^p, with p={45,63,1019,1023}
FieldElem a2; a2.SetSquare(a);
FieldElem a3; a3.SetMult(a2,a);
FieldElem a4; a4.SetSquare(a2);
FieldElem a5; a5.SetMult(a4,a);
FieldElem a10; a10.SetSquare(a5);
FieldElem a11; a11.SetMult(a10,a);
FieldElem a21; a21.SetMult(a11,a10);
FieldElem a42; a42.SetSquare(a21);
FieldElem a45; a45.SetMult(a42,a3);
FieldElem a63; a63.SetMult(a42,a21);
FieldElem a126; a126.SetSquare(a63);
FieldElem a252; a252.SetSquare(a126);
FieldElem a504; a504.SetSquare(a252);
FieldElem a1008; a1008.SetSquare(a504);
FieldElem a1019; a1019.SetMult(a1008,a11);
FieldElem a1023; a1023.SetMult(a1019,a4);
FieldElem x = a63;
for (int i=0; i<21; i++) {
for (int j=0; j<10; j++) x.SetSquare(x);
x.SetMult(x,a1023);
}
for (int j=0; j<10; j++) x.SetSquare(x);
x.SetMult(x,a1019);
for (int i=0; i<2; i++) {
for (int j=0; j<10; j++) x.SetSquare(x);
x.SetMult(x,a1023);
}
for (int j=0; j<10; j++) x.SetSquare(x);
SetMult(x,a45);
#else
unsigned char b[32];
a.Normalize();
a.GetBytes(b);
{
const secp256k1_num_t &p = GetFieldConst().field_p;
secp256k1_num_t n;
secp256k1_num_init(&n);
secp256k1_num_set_bin(&n, b, 32);
secp256k1_num_mod_inverse(&n, &n, &p);
secp256k1_num_get_bin(b, 32, &n);
secp256k1_num_free(&n);
}
SetBytes(b);
#endif
}
}

View file

@ -1,80 +1,15 @@
#ifndef _SECP256K1_FIELD_5x52_
#define _SECP256K1_FIELD_5x52_
using namespace std;
#include <stdint.h>
#include <string>
#include "num.h"
// #define VERIFY_MAGNITUDE 1
namespace secp256k1 {
/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
* represented as 5 uint64_t's in base 2^52. he 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.
*/
class FieldElem {
private:
typedef struct {
// X = sum(i=0..4, elem[i]*2^52) mod n
uint64_t n[5];
#ifdef VERIFY_MAGNITUDE
#ifdef VERIFY
int magnitude;
bool normalized;
int normalized;
#endif
public:
/** Creates a constant field element. Magnitude=1 */
FieldElem(int x = 0);
FieldElem(const unsigned char *b32);
/** Normalizes the internal representation entries. Magnitude=1 */
void Normalize();
bool IsZero() const;
bool friend operator==(const FieldElem &a, const FieldElem &b);
/** extract as 32-byte big endian array */
void GetBytes(unsigned char *o);
/** set value of 32-byte big endian array */
void SetBytes(const unsigned char *in);
/** Set a FieldElem to be the negative of another. Increases magnitude by one. */
void SetNeg(const FieldElem &a, int magnitudeIn);
/** Multiplies this FieldElem with an integer constant. Magnitude is multiplied by v */
void operator*=(int v);
void operator+=(const FieldElem &a);
/** Set this FieldElem to be the multiplication of two others. Magnitude=1 (variable time) */
void SetMult(const FieldElem &a, const FieldElem &b);
/** Set this FieldElem to be the square of another. Magnitude=1 (variable time) */
void SetSquare(const FieldElem &a);
/** Set this to be the (modular) square root of another FieldElem. Magnitude=1 */
void SetSquareRoot(const FieldElem &a);
bool IsOdd() const;
/** Set this to be the (modular) inverse of another FieldElem. Magnitude=1 (variable time) */
void SetInverse(FieldElem &a);
std::string ToString();
void SetHex(const std::string &str);
};
}
} secp256k1_fe_t;
#endif

261
group.cpp
View file

@ -10,7 +10,7 @@ GroupElem::GroupElem() {
fInfinity = true;
}
GroupElem::GroupElem(const FieldElem &xin, const FieldElem &yin) {
GroupElem::GroupElem(const secp256k1_fe_t &xin, const secp256k1_fe_t &yin) {
fInfinity = false;
x = xin;
y = yin;
@ -22,30 +22,40 @@ bool GroupElem::IsInfinity() const {
void GroupElem::SetNeg(const GroupElem &p) {
*this = p;
y.Normalize();
y.SetNeg(y, 1);
secp256k1_fe_normalize(&y);
secp256k1_fe_negate(&y, &y, 1);
}
void GroupElem::GetX(FieldElem &xout) {
void GroupElem::GetX(secp256k1_fe_t &xout) {
xout = x;
}
void GroupElem::GetY(FieldElem &yout) {
void GroupElem::GetY(secp256k1_fe_t &yout) {
yout = y;
}
std::string GroupElem::ToString() const {
if (fInfinity)
return "(inf)";
FieldElem xc = x, yc = y;
return "(" + xc.ToString() + "," + yc.ToString() + ")";
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(), z(1) {}
GroupElemJac::GroupElemJac() : GroupElem() {
secp256k1_fe_set_int(&z, 1);
}
GroupElemJac::GroupElemJac(const FieldElem &xin, const FieldElem &yin) : GroupElem(xin,yin), 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), z(1) {}
GroupElemJac::GroupElemJac(const GroupElem &in) : GroupElem(in) {
secp256k1_fe_set_int(&z, 1);
}
void GroupElemJac::SetJac(const GroupElemJac &jac) {
*this = jac;
@ -55,7 +65,7 @@ void GroupElemJac::SetAffine(const GroupElem &aff) {
fInfinity = aff.fInfinity;
x = aff.x;
y = aff.y;
z = FieldElem(1);
secp256k1_fe_set_int(&z, 1);
}
bool GroupElemJac::IsValid() const {
@ -65,43 +75,38 @@ bool GroupElemJac::IsValid() const {
// (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
FieldElem y2; y2.SetSquare(y);
FieldElem x3; x3.SetSquare(x); x3.SetMult(x3,x);
FieldElem z2; z2.SetSquare(z);
FieldElem z6; z6.SetSquare(z2); z6.SetMult(z6,z2);
z6 *= 7;
x3 += z6;
y2.Normalize();
x3.Normalize();
return y2 == x3;
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) {
z.SetInverse(z);
FieldElem z2;
z2.SetSquare(z);
FieldElem z3;
z3.SetMult(z,z2);
x.SetMult(x,z2);
y.SetMult(y,z3);
z = FieldElem(1);
secp256k1_fe_inv(&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(FieldElem &xout) {
FieldElem zi;
zi.SetInverse(z);
zi.SetSquare(zi);
xout.SetMult(x, zi);
void GroupElemJac::GetX(secp256k1_fe_t &xout) {
secp256k1_fe_t zi2; secp256k1_fe_inv(&zi2, &z); secp256k1_fe_sqr(&zi2, &zi2);
secp256k1_fe_mul(&xout, &x, &zi2);
}
void GroupElemJac::GetY(FieldElem &yout) {
FieldElem zi;
zi.SetInverse(z);
FieldElem zi3; zi3.SetSquare(zi); zi3.SetMult(zi, zi3);
yout.SetMult(y, zi3);
void GroupElemJac::GetY(secp256k1_fe_t &yout) {
secp256k1_fe_t zi; secp256k1_fe_inv(&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 {
@ -111,53 +116,53 @@ bool GroupElemJac::IsInfinity() const {
void GroupElemJac::SetNeg(const GroupElemJac &p) {
*this = p;
y.Normalize();
y.SetNeg(y, 1);
secp256k1_fe_normalize(&y);
secp256k1_fe_negate(&y, &y, 1);
}
void GroupElemJac::SetCompressed(const FieldElem &xin, bool fOdd) {
void GroupElemJac::SetCompressed(const secp256k1_fe_t &xin, bool fOdd) {
x = xin;
FieldElem x2; x2.SetSquare(x);
FieldElem x3; x3.SetMult(x,x2);
secp256k1_fe_t x2; secp256k1_fe_sqr(&x2, &x);
secp256k1_fe_t x3; secp256k1_fe_mul(&x3, &x, &x2);
fInfinity = false;
FieldElem c(7);
c += x3;
y.SetSquareRoot(c);
z = FieldElem(1);
y.Normalize();
if (y.IsOdd() != fOdd)
y.SetNeg(y,1);
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) {
FieldElem t5 = p.y;
t5.Normalize();
if (p.fInfinity || t5.IsZero()) {
secp256k1_fe_t t5 = p.y;
secp256k1_fe_normalize(&t5);
if (p.fInfinity || secp256k1_fe_is_zero(&t5)) {
fInfinity = true;
return;
}
FieldElem t1,t2,t3,t4;
z.SetMult(t5,p.z);
z *= 2; // Z' = 2*Y*Z (2)
t1.SetSquare(p.x);
t1 *= 3; // T1 = 3*X^2 (3)
t2.SetSquare(t1); // T2 = 9*X^4 (1)
t3.SetSquare(t5);
t3 *= 2; // T3 = 2*Y^2 (2)
t4.SetSquare(t3);
t4 *= 2; // T4 = 8*Y^4 (2)
t3.SetMult(p.x,t3); // T3 = 2*X*Y^2 (1)
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;
x *= 4; // X' = 8*X*Y^2 (4)
x.SetNeg(x,4); // X' = -8*X*Y^2 (5)
x += t2; // X' = 9*X^4 - 8*X*Y^2 (6)
t2.SetNeg(t2,1); // T2 = -9*X^4 (2)
t3 *= 6; // T3 = 12*X*Y^2 (6)
t3 += t2; // T3 = 12*X*Y^2 - 9*X^4 (8)
y.SetMult(t1,t3); // Y' = 36*X^3*Y^2 - 27*X^6 (1)
t2.SetNeg(t4,2); // T2 = -8*Y^4 (3)
y += t2; // Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4)
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;
}
@ -171,36 +176,36 @@ void GroupElemJac::SetAdd(const GroupElemJac &p, const GroupElemJac &q) {
return;
}
fInfinity = false;
const FieldElem &x1 = p.x, &y1 = p.y, &z1 = p.z, &x2 = q.x, &y2 = q.y, &z2 = q.z;
FieldElem z22; z22.SetSquare(z2);
FieldElem z12; z12.SetSquare(z1);
FieldElem u1; u1.SetMult(x1, z22);
FieldElem u2; u2.SetMult(x2, z12);
FieldElem s1; s1.SetMult(y1, z22); s1.SetMult(s1, z2);
FieldElem s2; s2.SetMult(y2, z12); s2.SetMult(s2, z1);
u1.Normalize();
u2.Normalize();
if (u1 == u2) {
s1.Normalize();
s2.Normalize();
if (s1 == s2) {
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;
}
FieldElem h; h.SetNeg(u1,1); h += u2;
FieldElem r; r.SetNeg(s1,1); r += s2;
FieldElem r2; r2.SetSquare(r);
FieldElem h2; h2.SetSquare(h);
FieldElem h3; h3.SetMult(h,h2);
z.SetMult(z1,z2); z.SetMult(z, h);
FieldElem t; t.SetMult(u1,h2);
x = t; x *= 2; x += h3; x.SetNeg(x,3); x += r2;
y.SetNeg(x,5); y += t; y.SetMult(y,r);
h3.SetMult(h3,s1); h3.SetNeg(h3,1);
y += h3;
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) {
@ -208,7 +213,7 @@ void GroupElemJac::SetAdd(const GroupElemJac &p, const GroupElem &q) {
x = q.x;
y = q.y;
fInfinity = q.fInfinity;
z = FieldElem(1);
secp256k1_fe_set_int(&z, 1);
return;
}
if (q.fInfinity) {
@ -216,35 +221,35 @@ void GroupElemJac::SetAdd(const GroupElemJac &p, const GroupElem &q) {
return;
}
fInfinity = false;
const FieldElem &x1 = p.x, &y1 = p.y, &z1 = p.z, &x2 = q.x, &y2 = q.y;
FieldElem z12; z12.SetSquare(z1);
FieldElem u1 = x1; u1.Normalize();
FieldElem u2; u2.SetMult(x2, z12);
FieldElem s1 = y1; s1.Normalize();
FieldElem s2; s2.SetMult(y2, z12); s2.SetMult(s2, z1);
u1.Normalize();
u2.Normalize();
if (u1 == u2) {
s1.Normalize();
s2.Normalize();
if (s1 == s2) {
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;
}
FieldElem h; h.SetNeg(u1,1); h += u2;
FieldElem r; r.SetNeg(s1,1); r += s2;
FieldElem r2; r2.SetSquare(r);
FieldElem h2; h2.SetSquare(h);
FieldElem h3; h3.SetMult(h,h2);
z = p.z; z.SetMult(z, h);
FieldElem t; t.SetMult(u1,h2);
x = t; x *= 2; x += h3; x.SetNeg(x,3); x += r2;
y.SetNeg(x,5); y += t; y.SetMult(y,r);
h3.SetMult(h3,s1); h3.SetNeg(h3,1);
y += h3;
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 {
@ -290,15 +295,19 @@ static const unsigned char a2_[] = {0x01,
0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,
0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8};
GroupConstants::GroupConstants() : g_x(g_x_), g_y(g_y_),
g(g_x,g_y),
beta(beta_) {
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_));
@ -320,9 +329,9 @@ const GroupConstants &GetGroupConst() {
}
void GroupElemJac::SetMulLambda(const GroupElemJac &p) {
FieldElem beta = GetGroupConst().beta;
const secp256k1_fe_t &beta = GetGroupConst().beta;
*this = p;
x.SetMult(x, beta);
secp256k1_fe_mul(&x, &x, &beta);
}
void SplitExp(const secp256k1_num_t &exp, secp256k1_num_t &exp1, secp256k1_num_t &exp2) {

28
group.h
View file

@ -14,8 +14,8 @@ class GroupElemJac;
class GroupElem {
protected:
bool fInfinity;
FieldElem x;
FieldElem y;
secp256k1_fe_t x;
secp256k1_fe_t y;
public:
@ -23,16 +23,16 @@ public:
GroupElem();
/** Creates the point with given affine coordinates */
GroupElem(const FieldElem &xin, const FieldElem &yin);
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(FieldElem &xout);
void GetX(secp256k1_fe_t &xout);
void GetY(FieldElem &yout);
void GetY(secp256k1_fe_t &yout);
std::string ToString() const;
@ -44,14 +44,14 @@ public:
/** Represents a point on the secp256k1 curve, with jacobian coordinates */
class GroupElemJac : private GroupElem {
protected:
FieldElem z;
secp256k1_fe_t z;
public:
/** Creates the point at infinity */
GroupElemJac();
/** Creates the point with given affine coordinates */
GroupElemJac(const FieldElem &xin, const FieldElem &yin);
GroupElemJac(const secp256k1_fe_t &xin, const secp256k1_fe_t &yin);
GroupElemJac(const GroupElem &in);
@ -65,15 +65,15 @@ public:
/** Returns the affine coordinates of this point */
void GetAffine(GroupElem &aff);
void GetX(FieldElem &xout);
void GetY(FieldElem &yout);
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 FieldElem &xin, bool fOdd);
void SetCompressed(const secp256k1_fe_t &xin, bool fOdd);
/** Sets this point to be the EC double of another */
void SetDouble(const GroupElemJac &p);
@ -91,13 +91,13 @@ public:
class GroupConstants {
private:
const FieldElem g_x;
const FieldElem g_y;
secp256k1_fe_t g_x;
secp256k1_fe_t g_y;
public:
secp256k1_num_t order;
const GroupElem g;
const FieldElem beta;
GroupElem g;
secp256k1_fe_t beta;
secp256k1_num_t lambda, a1b2, b1, a2;
GroupConstants();

View file

@ -13,8 +13,8 @@ using namespace secp256k1;
void test_run_ecmult_chain() {
// random starting point A (on the curve)
FieldElem ax; ax.SetHex("8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004");
FieldElem ay; ay.SetHex("a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f");
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;
@ -85,13 +85,15 @@ void test_point_times_order(const GroupElemJac &point) {
}
void test_run_point_times_order() {
FieldElem x; x.SetHex("02");
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);
x.SetSquare(x);
secp256k1_fe_sqr(&x, &x);
}
assert(x.ToString() == "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45"); // 0x02 ^ (2^500)
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) {
@ -173,10 +175,13 @@ void test_run_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;
}