7a49cac Merge #410: Add string.h include to ecmult_impl 0bbd5d4 Add string.h include to ecmult_impl c5b32e1 Merge #405: Make secp256k1_fe_sqrt constant time 926836a Make secp256k1_fe_sqrt constant time e2a8e92 Merge #404: Replace 3M + 4S doubling formula with 2M + 5S one 8ec49d8 Add note about 2M + 5S doubling formula 5a91bd7 Merge #400: A couple minor cleanups ac01378 build: add -DSECP256K1_BUILD to benchmark_internal build flags a6c6f99 Remove a bunch of unused stdlib #includes 65285a6 Merge #403: configure: add flag to disable OpenSSL tests a9b2a5d configure: add flag to disable OpenSSL tests b340123 Merge #402: Add support for testing quadratic residues e6e9805 Add function for testing quadratic residue field/group elements. efd953a Add Jacobi symbol test via GMP fa36a0d Merge #401: ecmult_const: unify endomorphism and non-endomorphism skew cases c6191fd ecmult_const: unify endomorphism and non-endomorphism skew cases 0b3e618 Merge #378: .gitignore build-aux cleanup 6042217 Merge #384: JNI: align shared files copyright/comments to bitcoinj's 24ad20f Merge #399: build: verify that the native compiler works for static precomp b3be852 Merge #398: Test whether ECDH and Schnorr are enabled for JNI aa0b1fd build: verify that the native compiler works for static precomp eee808d Test whether ECDH and Schnorr are enabled for JNI 7b0fb18 Merge #366: ARM assembly implementation of field_10x26 inner (rebase of #173) 001f176 ARM assembly implementation of field_10x26 inner 0172be9 Merge #397: Small fixes for sha256 3f8b78e Fix undefs in hash_impl.h 2ab4695 Fix state size in sha256 struct 6875b01 Merge #386: Add some missing `VERIFY_CHECK(ctx != NULL)` 2c52b5d Merge #389: Cast pointers through uintptr_t under JNI 43097a4 Merge #390: Update bitcoin-core GitHub links 31c9c12 Merge #391: JNI: Only call ecdsa_verify if its inputs parsed correctly 1cb2302 Merge #392: Add testcase which hits additional branch in secp256k1_scalar_sqr d2ee340 Merge #388: bench_ecdh: fix call to secp256k1_context_create 093a497 Add testcase which hits additional branch in secp256k1_scalar_sqr a40c701 JNI: Only call ecdsa_verify if its inputs parsed correctly faa2a11 Update bitcoin-core GitHub links 47b9e78 Cast pointers through uintptr_t under JNI f36f9c6 bench_ecdh: fix call to secp256k1_context_create bcc4881 Add some missing `VERIFY_CHECK(ctx != NULL)` for functions that use `ARG_CHECK` 6ceea2c align shared files copyright/comments to bitcoinj's 70141a8 Update .gitignore 7b549b1 Merge #373: build: fix x86_64 asm detection for some compilers bc7c93c Merge #374: Add note about y=0 being possible on one of the sextic twists e457018 Merge #364: JNI rebased 86e2d07 JNI library: cleanup, removed unimplemented code 3093576a JNI library bd2895f Merge pull request #371 e72e93a Add note about y=0 being possible on one of the sextic twists 3f8fdfb build: fix x86_64 asm detection for some compilers e5a9047 [Trivial] Remove double semicolons c18b869 Merge pull request #360 3026daa Merge pull request #302 03d4611 Add sage verification script for the group laws a965937 Merge pull request #361 83221ec Add experimental features to configure 5d4c5a3 Prevent damage_array in the signature test from going out of bounds. 419bf7f Merge pull request #356 03d84a4 Benchmark against OpenSSL verification git-subtree-dir: src/secp256k1 git-subtree-split: 7a49cacd3937311fcb1cb36b6ba3336fca811991
289 lines
8.2 KiB
C
289 lines
8.2 KiB
C
/**********************************************************************
|
|
* Copyright (c) 2013, 2014 Pieter Wuille *
|
|
* Distributed under the MIT software license, see the accompanying *
|
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|
**********************************************************************/
|
|
|
|
#ifndef _SECP256K1_NUM_REPR_IMPL_H_
|
|
#define _SECP256K1_NUM_REPR_IMPL_H_
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <gmp.h>
|
|
|
|
#include "util.h"
|
|
#include "num.h"
|
|
|
|
#ifdef VERIFY
|
|
static void secp256k1_num_sanity(const secp256k1_num *a) {
|
|
VERIFY_CHECK(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0));
|
|
}
|
|
#else
|
|
#define secp256k1_num_sanity(a) do { } while(0)
|
|
#endif
|
|
|
|
static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a) {
|
|
*r = *a;
|
|
}
|
|
|
|
static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a) {
|
|
unsigned char tmp[65];
|
|
int len = 0;
|
|
int shift = 0;
|
|
if (a->limbs>1 || a->data[0] != 0) {
|
|
len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs);
|
|
}
|
|
while (shift < len && tmp[shift] == 0) shift++;
|
|
VERIFY_CHECK(len-shift <= (int)rlen);
|
|
memset(r, 0, rlen - len + shift);
|
|
if (len > shift) {
|
|
memcpy(r + rlen - len + shift, tmp + shift, len - shift);
|
|
}
|
|
memset(tmp, 0, sizeof(tmp));
|
|
}
|
|
|
|
static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen) {
|
|
int len;
|
|
VERIFY_CHECK(alen > 0);
|
|
VERIFY_CHECK(alen <= 64);
|
|
len = mpn_set_str(r->data, a, alen, 256);
|
|
if (len == 0) {
|
|
r->data[0] = 0;
|
|
len = 1;
|
|
}
|
|
VERIFY_CHECK(len <= NUM_LIMBS*2);
|
|
r->limbs = len;
|
|
r->neg = 0;
|
|
while (r->limbs > 1 && r->data[r->limbs-1]==0) {
|
|
r->limbs--;
|
|
}
|
|
}
|
|
|
|
static void secp256k1_num_add_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {
|
|
mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs);
|
|
r->limbs = a->limbs;
|
|
if (c != 0) {
|
|
VERIFY_CHECK(r->limbs < 2*NUM_LIMBS);
|
|
r->data[r->limbs++] = c;
|
|
}
|
|
}
|
|
|
|
static void secp256k1_num_sub_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {
|
|
mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs);
|
|
(void)c;
|
|
VERIFY_CHECK(c == 0);
|
|
r->limbs = a->limbs;
|
|
while (r->limbs > 1 && r->data[r->limbs-1]==0) {
|
|
r->limbs--;
|
|
}
|
|
}
|
|
|
|
static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m) {
|
|
secp256k1_num_sanity(r);
|
|
secp256k1_num_sanity(m);
|
|
|
|
if (r->limbs >= m->limbs) {
|
|
mp_limb_t t[2*NUM_LIMBS];
|
|
mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs);
|
|
memset(t, 0, sizeof(t));
|
|
r->limbs = m->limbs;
|
|
while (r->limbs > 1 && r->data[r->limbs-1]==0) {
|
|
r->limbs--;
|
|
}
|
|
}
|
|
|
|
if (r->neg && (r->limbs > 1 || r->data[0] != 0)) {
|
|
secp256k1_num_sub_abs(r, m, r);
|
|
r->neg = 0;
|
|
}
|
|
}
|
|
|
|
static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m) {
|
|
int i;
|
|
mp_limb_t g[NUM_LIMBS+1];
|
|
mp_limb_t u[NUM_LIMBS+1];
|
|
mp_limb_t v[NUM_LIMBS+1];
|
|
mp_size_t sn;
|
|
mp_size_t gn;
|
|
secp256k1_num_sanity(a);
|
|
secp256k1_num_sanity(m);
|
|
|
|
/** mpn_gcdext computes: (G,S) = gcdext(U,V), where
|
|
* * G = gcd(U,V)
|
|
* * G = U*S + V*T
|
|
* * U has equal or more limbs than V, and V has no padding
|
|
* If we set U to be (a padded version of) a, and V = m:
|
|
* G = a*S + m*T
|
|
* G = a*S mod m
|
|
* Assuming G=1:
|
|
* S = 1/a mod m
|
|
*/
|
|
VERIFY_CHECK(m->limbs <= NUM_LIMBS);
|
|
VERIFY_CHECK(m->data[m->limbs-1] != 0);
|
|
for (i = 0; i < m->limbs; i++) {
|
|
u[i] = (i < a->limbs) ? a->data[i] : 0;
|
|
v[i] = m->data[i];
|
|
}
|
|
sn = NUM_LIMBS+1;
|
|
gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs);
|
|
(void)gn;
|
|
VERIFY_CHECK(gn == 1);
|
|
VERIFY_CHECK(g[0] == 1);
|
|
r->neg = a->neg ^ m->neg;
|
|
if (sn < 0) {
|
|
mpn_sub(r->data, m->data, m->limbs, r->data, -sn);
|
|
r->limbs = m->limbs;
|
|
while (r->limbs > 1 && r->data[r->limbs-1]==0) {
|
|
r->limbs--;
|
|
}
|
|
} else {
|
|
r->limbs = sn;
|
|
}
|
|
memset(g, 0, sizeof(g));
|
|
memset(u, 0, sizeof(u));
|
|
memset(v, 0, sizeof(v));
|
|
}
|
|
|
|
static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b) {
|
|
int ret;
|
|
mpz_t ga, gb;
|
|
secp256k1_num_sanity(a);
|
|
secp256k1_num_sanity(b);
|
|
VERIFY_CHECK(!b->neg && (b->limbs > 0) && (b->data[0] & 1));
|
|
|
|
mpz_inits(ga, gb, NULL);
|
|
|
|
mpz_import(gb, b->limbs, -1, sizeof(mp_limb_t), 0, 0, b->data);
|
|
mpz_import(ga, a->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data);
|
|
if (a->neg) {
|
|
mpz_neg(ga, ga);
|
|
}
|
|
|
|
ret = mpz_jacobi(ga, gb);
|
|
|
|
mpz_clears(ga, gb, NULL);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int secp256k1_num_is_one(const secp256k1_num *a) {
|
|
return (a->limbs == 1 && a->data[0] == 1);
|
|
}
|
|
|
|
static int secp256k1_num_is_zero(const secp256k1_num *a) {
|
|
return (a->limbs == 1 && a->data[0] == 0);
|
|
}
|
|
|
|
static int secp256k1_num_is_neg(const secp256k1_num *a) {
|
|
return (a->limbs > 1 || a->data[0] != 0) && a->neg;
|
|
}
|
|
|
|
static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b) {
|
|
if (a->limbs > b->limbs) {
|
|
return 1;
|
|
}
|
|
if (a->limbs < b->limbs) {
|
|
return -1;
|
|
}
|
|
return mpn_cmp(a->data, b->data, a->limbs);
|
|
}
|
|
|
|
static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b) {
|
|
if (a->limbs > b->limbs) {
|
|
return 0;
|
|
}
|
|
if (a->limbs < b->limbs) {
|
|
return 0;
|
|
}
|
|
if ((a->neg && !secp256k1_num_is_zero(a)) != (b->neg && !secp256k1_num_is_zero(b))) {
|
|
return 0;
|
|
}
|
|
return mpn_cmp(a->data, b->data, a->limbs) == 0;
|
|
}
|
|
|
|
static void secp256k1_num_subadd(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b, int bneg) {
|
|
if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */
|
|
r->neg = a->neg;
|
|
if (a->limbs >= b->limbs) {
|
|
secp256k1_num_add_abs(r, a, b);
|
|
} else {
|
|
secp256k1_num_add_abs(r, b, a);
|
|
}
|
|
} else {
|
|
if (secp256k1_num_cmp(a, b) > 0) {
|
|
r->neg = a->neg;
|
|
secp256k1_num_sub_abs(r, a, b);
|
|
} else {
|
|
r->neg = b->neg ^ bneg;
|
|
secp256k1_num_sub_abs(r, b, a);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {
|
|
secp256k1_num_sanity(a);
|
|
secp256k1_num_sanity(b);
|
|
secp256k1_num_subadd(r, a, b, 0);
|
|
}
|
|
|
|
static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {
|
|
secp256k1_num_sanity(a);
|
|
secp256k1_num_sanity(b);
|
|
secp256k1_num_subadd(r, a, b, 1);
|
|
}
|
|
|
|
static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) {
|
|
mp_limb_t tmp[2*NUM_LIMBS+1];
|
|
secp256k1_num_sanity(a);
|
|
secp256k1_num_sanity(b);
|
|
|
|
VERIFY_CHECK(a->limbs + b->limbs <= 2*NUM_LIMBS+1);
|
|
if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) {
|
|
r->limbs = 1;
|
|
r->neg = 0;
|
|
r->data[0] = 0;
|
|
return;
|
|
}
|
|
if (a->limbs >= b->limbs) {
|
|
mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs);
|
|
} else {
|
|
mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs);
|
|
}
|
|
r->limbs = a->limbs + b->limbs;
|
|
if (r->limbs > 1 && tmp[r->limbs - 1]==0) {
|
|
r->limbs--;
|
|
}
|
|
VERIFY_CHECK(r->limbs <= 2*NUM_LIMBS);
|
|
mpn_copyi(r->data, tmp, r->limbs);
|
|
r->neg = a->neg ^ b->neg;
|
|
memset(tmp, 0, sizeof(tmp));
|
|
}
|
|
|
|
static void secp256k1_num_shift(secp256k1_num *r, int bits) {
|
|
if (bits % GMP_NUMB_BITS) {
|
|
/* Shift within limbs. */
|
|
mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS);
|
|
}
|
|
if (bits >= GMP_NUMB_BITS) {
|
|
int i;
|
|
/* Shift full limbs. */
|
|
for (i = 0; i < r->limbs; i++) {
|
|
int index = i + (bits / GMP_NUMB_BITS);
|
|
if (index < r->limbs && index < 2*NUM_LIMBS) {
|
|
r->data[i] = r->data[index];
|
|
} else {
|
|
r->data[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
while (r->limbs>1 && r->data[r->limbs-1]==0) {
|
|
r->limbs--;
|
|
}
|
|
}
|
|
|
|
static void secp256k1_num_negate(secp256k1_num *r) {
|
|
r->neg ^= 1;
|
|
}
|
|
|
|
#endif
|