Field 5x64

This commit is contained in:
Pieter Wuille 2013-06-08 19:02:48 +02:00
parent 561b0e1044
commit 1487ca95c6
4 changed files with 321 additions and 0 deletions

View File

@ -22,6 +22,8 @@
#include "field_10x26.h"
#elif defined(USE_FIELD_5X52)
#include "field_5x52.h"
#elif defined(USE_FIELD_5X64)
#include "field_5x64.h"
#else
#error "Please select field implementation"
#endif

19
src/field_5x64.h Normal file
View File

@ -0,0 +1,19 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_REPR_
#define _SECP256K1_FIELD_REPR_
#include <stdint.h>
typedef struct {
// X = sum(i=0..4, elem[i]*2^64) mod n
uint64_t n[5];
#ifdef VERIFY
int reduced; // n[4] == 0
int normalized; // reduced and X < 2^256 - 0x100003D1
#endif
} secp256k1_fe_t;
#endif

View File

@ -11,6 +11,8 @@
#include "field_10x26.h"
#elif defined(USE_FIELD_5X52)
#include "field_5x52.h"
#elif defined(USE_FIELD_5X64)
#include "field_5x64.h"
#else
#error "Please select field implementation"
#endif

298
src/impl/field_5x64.h Normal file
View File

@ -0,0 +1,298 @@
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
#define _SECP256K1_FIELD_REPR_IMPL_H_
#include <assert.h>
#include <string.h>
#include "../num.h"
#include "../field.h"
#include <stdio.h>
/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
* represented as 4 uint64_t's in base 2^64, and one overflow uint64_t.
*/
#define FULL_LIMB (0xFFFFFFFFFFFFFFFFULL)
#define LAST_LIMB (0xFFFFFFFEFFFFFC2FULL)
#define COMP_LIMB (0x00000001000003D1ULL)
void static secp256k1_fe_inner_start(void) {}
void static secp256k1_fe_inner_stop(void) {}
void static secp256k1_fe_reduce(secp256k1_fe_t *r) {
unsigned __int128 c = (unsigned __int128)r->n[4] * COMP_LIMB + r->n[0];
uint64_t n0 = c;
c = (c >> 64) + r->n[1];
uint64_t n1 = c;
c = (c >> 64) + r->n[2];
r->n[2] = c;
c = (c >> 64) + r->n[3];
r->n[3] = c;
c = (c >> 64) * COMP_LIMB + n0;
r->n[0] = c;
r->n[1] = n1 + (c >> 64);
assert(r->n[1] >= n1);
r->n[4] = 0;
#ifdef VERIFY
r->reduced = 1;
#endif
}
void static secp256k1_fe_normalize(secp256k1_fe_t *r) {
secp256k1_fe_reduce(r);
// Subtract p if result >= p
uint64_t mask = -(int64_t)((r->n[0] < LAST_LIMB) | (r->n[1] != ~0ULL) | (r->n[2] != ~0ULL) | (r->n[3] != ~0ULL));
r->n[0] -= (~mask & LAST_LIMB);
r->n[1] &= mask;
r->n[2] &= mask;
r->n[3] &= mask;
assert(r->n[4] == 0);
#ifdef VERIFY
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->reduced = 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);
}
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]);
}
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++) {
r->n[i/8] |= (uint64_t)a[31-i] << (i&7)*8;
}
#ifdef VERIFY
r->reduced = 1;
r->normalized = 0;
#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++) {
r[31-i] = a->n[i/8] >> ((i&7)*8);
}
}
void static inline secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *ac, int m) {
secp256k1_fe_t a = *ac;
secp256k1_fe_reduce(&a);
unsigned __int128 c = (unsigned __int128)(~a.n[0]) + LAST_LIMB + 1;
r->n[0] = c;
c = (c >> 64) + (~a.n[1]) + FULL_LIMB;
r->n[1] = c;
c = (c >> 64) + (~a.n[2]) + FULL_LIMB;
r->n[2] = c;
c = (c >> 64) + (~a.n[3]) + FULL_LIMB;
r->n[3] = c;
r->n[4] = 0;
#ifdef VERIFY
r->reduced = 1;
r->normalized = 0;
#endif
}
void static inline secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
#ifdef VERIFY
r->reduced = 0;
r->normalized = 0;
#endif
unsigned __int128 c = (unsigned __int128)r->n[0] * a;
r->n[0] = c;
c = (c >> 64) + (unsigned __int128)r->n[1] * a;
r->n[1] = c;
c = (c >> 64) + (unsigned __int128)r->n[2] * a;
r->n[2] = c;
c = (c >> 64) + (unsigned __int128)r->n[3] * a;
r->n[3] = c;
c = (c >> 64) + (unsigned __int128)r->n[4] * a;
r->n[4] = c;
}
void static inline secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#ifdef VERIFY
r->reduced = 0;
r->normalized = 0;
#endif
unsigned __int128 c = (unsigned __int128)r->n[0] + a->n[0];
r->n[0] = c;
c = (unsigned __int128)r->n[1] + a->n[1] + (c >> 64);
r->n[1] = c;
c = (unsigned __int128)r->n[2] + a->n[2] + (c >> 64);
r->n[2] = c;
c = (unsigned __int128)r->n[3] + a->n[3] + (c >> 64);
r->n[3] = c;
c = (unsigned __int128)r->n[4] + a->n[4] + (c >> 64);
r->n[4] = c;
assert((c >> 64) == 0);
}
#define muladd_c3(a,b,c0,c1,c2) { \
unsigned __int128 q1 = ((unsigned __int128)(a)) * (b) + (c0); \
(c0) = q1; \
unsigned __int128 q2 = (q1 >> 64) + (c1) + (((unsigned __int128)(c2)) << 64); \
(c1) = q2; \
(c2) = q2 >> 64; \
}
/*#define muladd_c3(a,b,c0,c1,c2) { \
unsigned __int128 q = (unsigned __int128)(a) * (b) + (c0); \
(c0) = q; \
(c1) += (q >> 64); \
(c2) += ((c1) < (q >> 64))?1:0; \
}*/
#define muladd2_c3(a,b,c0,c1,c2) { \
unsigned __int128 q = (unsigned __int128)(a) * (b); \
uint64_t t1 = (q >> 64); \
uint64_t t0 = q; \
uint64_t t2 = t1+t1; (c2) += (t2<t1)?1:0; \
t1 = t0+t0; t2 += (t1<t0)?1:0; \
(c0) += t1; t2 += ((c0)<t1)?1:0; \
(c1) += t2; (c2) += ((c1)<t2)?1:0; \
}
/*#define muladd2_c3(a,b,c0,c1,c2) { \
muladd_c3(a,b,c0,c1,c2); \
muladd_c3(a,b,c0,c1,c2); \
}*/
#define mul_c2(a,b,c0,c1) { \
unsigned __int128 q = (unsigned __int128)(a) * (b); \
(c0) = q; \
(c1) = (q >> 64); \
}
void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *ac, const secp256k1_fe_t *bc) {
secp256k1_fe_t a = *ac, b = *bc;
secp256k1_fe_reduce(&a);
secp256k1_fe_reduce(&b);
uint64_t c1,c2,c3;
c3=0;
mul_c2(a.n[0], b.n[0], c1, c2);
uint64_t r0 = c1; c1 = 0;
muladd_c3(a.n[0], b.n[1], c2, c3, c1);
muladd_c3(a.n[1], b.n[0], c2, c3, c1);
uint64_t r1 = c2; c2 = 0;
muladd_c3(a.n[2], b.n[0], c3, c1, c2);
muladd_c3(a.n[1], b.n[1], c3, c1, c2);
muladd_c3(a.n[0], b.n[2], c3, c1, c2);
uint64_t r2 = c3; c3 = 0;
muladd_c3(a.n[0], b.n[3], c1, c2, c3);
muladd_c3(a.n[1], b.n[2], c1, c2, c3);
muladd_c3(a.n[2], b.n[1], c1, c2, c3);
muladd_c3(a.n[3], b.n[0], c1, c2, c3);
uint64_t r3 = c1; c1 = 0;
muladd_c3(a.n[3], b.n[1], c2, c3, c1);
muladd_c3(a.n[2], b.n[2], c2, c3, c1);
muladd_c3(a.n[1], b.n[3], c2, c3, c1);
uint64_t r4 = c2; c2 = 0;
muladd_c3(a.n[2], b.n[3], c3, c1, c2);
muladd_c3(a.n[3], b.n[2], c3, c1, c2);
uint64_t r5 = c3; c3 = 0;
muladd_c3(a.n[3], b.n[3], c1, c2, c3);
uint64_t r6 = c1;
uint64_t r7 = c2;
assert(c3 == 0);
unsigned __int128 c = (unsigned __int128)r4 * COMP_LIMB + r0;
r->n[0] = c;
c = (unsigned __int128)r5 * COMP_LIMB + r1 + (c >> 64);
r->n[1] = c;
c = (unsigned __int128)r6 * COMP_LIMB + r2 + (c >> 64);
r->n[2] = c;
c = (unsigned __int128)r7 * COMP_LIMB + r3 + (c >> 64);
r->n[3] = c;
r->n[4] = c >> 64;
#ifdef VERIFY
r->normalized = 0;
r->reduced = 0;
#endif
secp256k1_fe_reduce(r);
}
/*void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
secp256k1_fe_mul(r, a, a);
}*/
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *ac) {
secp256k1_fe_t a = *ac;
secp256k1_fe_reduce(&a);
uint64_t c1,c2,c3;
c3=0;
mul_c2(a.n[0], a.n[0], c1, c2);
uint64_t r0 = c1; c1 = 0;
muladd2_c3(a.n[0], a.n[1], c2, c3, c1);
uint64_t r1 = c2; c2 = 0;
muladd2_c3(a.n[2], a.n[0], c3, c1, c2);
muladd_c3(a.n[1], a.n[1], c3, c1, c2);
uint64_t r2 = c3; c3 = 0;
muladd2_c3(a.n[0], a.n[3], c1, c2, c3);
muladd2_c3(a.n[1], a.n[2], c1, c2, c3);
uint64_t r3 = c1; c1 = 0;
muladd2_c3(a.n[3], a.n[1], c2, c3, c1);
muladd_c3(a.n[2], a.n[2], c2, c3, c1);
uint64_t r4 = c2; c2 = 0;
muladd2_c3(a.n[2], a.n[3], c3, c1, c2);
uint64_t r5 = c3; c3 = 0;
muladd_c3(a.n[3], a.n[3], c1, c2, c3);
uint64_t r6 = c1;
uint64_t r7 = c2;
assert(c3 == 0);
unsigned __int128 c = (unsigned __int128)r4 * COMP_LIMB + r0;
r->n[0] = c;
c = (unsigned __int128)r5 * COMP_LIMB + r1 + (c >> 64);
r->n[1] = c;
c = (unsigned __int128)r6 * COMP_LIMB + r2 + (c >> 64);
r->n[2] = c;
c = (unsigned __int128)r7 * COMP_LIMB + r3 + (c >> 64);
r->n[3] = c;
r->n[4] = c >> 64;
#ifdef VERIFY
r->normalized = 0;
r->reduced = 0;
#endif
secp256k1_fe_reduce(r);
}
#endif