Browse Source

Squashed 'src/secp256k1/' changes from ad2028f..b0210a9

b0210a9 Merge pull request #135
ee3eb4b Fix a memory leak and add a number of small tests.
4d879a3 Merge pull request #134
d5e8362 Merge pull request #127
7b92cf6 Merge pull request #132
0bf70a5 Merge pull request #133
29ae131 Make scalar_add_bit test's overflow detection exact
9048def Avoid undefined shift behaviour
efb7d4b Use constant-time conditional moves instead of byte slicing
d220062 Merge pull request #131
82f9254 Fix typo
601ca04 Merge pull request #129
35399e0 Bugfix: b is restricted, not r
c35ff1e Convert lambda splitter to pure scalar code.
cc604e9 Avoid division when decomposing scalars
ff8746d Add secp256k1_scalar_mul_shift_var
bd313f7 Merge pull request #119
276f987 Merge pull request #124
25d125e Merge pull request #126
24b3c65 Add a test case for ECDSA recomputing infinity
32600e5 Add a test for r >= order signature handling
4d4eeea Make secp256k1_fe_mul_inner use the r != property
be82e92 Require that r and b are different for field multiplication.
597128d Make num optional
659b554 Make constant initializers independent from num
0af5b47 Merge pull request #120
e2e8a36 Merge pull request #117
c76be9e Remove unused num functions
4285a98 Move lambda-splitting code to scalar.
f24041d Switch all EC/ECDSA logic from num to scalar
6794be6 Add scalar splitting functions
d1502eb Add secp256k1_scalar_inverse_var which delegates to GMP
b5c9ee7 Make test_point_times_order test meaningful again
0b73059 Switch wnaf splitting from num-based to scalar-based
1e6c77c Generalize secp256k1_scalar_get_bits
5213207 Add secp256k1_scalar_add_bit
3c0ae43 Merge pull request #122
6e05287 Do signature recovery/verification with 4 possible recid case
e3d692f Explain why no y=0 check is necessary for doubling
f7dc1c6 Optimize doubling: secp256k1 has no y=0 point
666d3b5 Merge pull request #121
2a54f9b Correct typo in comment
9d64145 Merge pull request #114
99f0728 Fix secp256k1_num_set_bin handling of 0
d907ebc Add bounds checking to field element setters
bb2cd94 Merge pull request #116
665775b Don't split the g factor when not using endomorphism
9431d6b Merge pull request #115
e2274c5 build: osx: attempt to work with homebrew keg-only packages

git-subtree-dir: src/secp256k1
git-subtree-split: b0210a95da433e048a11d298efbcc14eb423c95f
0.10
Pieter Wuille 10 years ago
parent
commit
87bddb7a3a
  1. 2
      .travis.yml
  2. 3
      Makefile.am
  3. 8
      build-aux/m4/bitcoin_secp.m4
  4. 55
      configure.ac
  5. 12
      include/secp256k1.h
  6. 14
      src/ecdsa.h
  7. 180
      src/ecdsa_impl.h
  8. 5
      src/eckey.h
  9. 33
      src/eckey_impl.h
  10. 2
      src/ecmult.h
  11. 19
      src/ecmult_gen_impl.h
  12. 99
      src/ecmult_impl.h
  13. 18
      src/field.h
  14. 45
      src/field_10x26_impl.h
  15. 38
      src/field_5x52_impl.h
  16. 84
      src/field_5x52_int128_impl.h
  17. 21
      src/field_gmp_impl.h
  18. 12
      src/field_impl.h
  19. 8
      src/group.h
  20. 86
      src/group_impl.h
  21. 42
      src/num.h
  22. 176
      src/num_gmp_impl.h
  23. 2
      src/num_impl.h
  24. 41
      src/scalar.h
  25. 102
      src/scalar_4x64_impl.h
  26. 126
      src/scalar_8x32_impl.h
  27. 152
      src/scalar_impl.h
  28. 47
      src/secp256k1.c
  29. 547
      src/tests.c
  30. 17
      src/util.h

2
.travis.yml

@ -18,6 +18,8 @@ env:
- FIELD=64bit ENDOMORPHISM=yes - FIELD=64bit ENDOMORPHISM=yes
- FIELD=32bit - FIELD=32bit
- FIELD=32bit ENDOMORPHISM=yes - FIELD=32bit ENDOMORPHISM=yes
- BIGNUM=none
- BIGNUM=none ENDOMORPHISM=yes
- BUILD=distcheck - BUILD=distcheck
- EXTRAFLAGS=CFLAGS=-DDETERMINISTIC - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC
before_script: ./autogen.sh before_script: ./autogen.sh

3
Makefile.am

@ -68,12 +68,13 @@ bench_sign_LDFLAGS = -static
bench_inv_SOURCES = src/bench_inv.c bench_inv_SOURCES = src/bench_inv.c
bench_inv_LDADD = $(COMMON_LIB) $(SECP_LIBS) bench_inv_LDADD = $(COMMON_LIB) $(SECP_LIBS)
bench_inv_LDFLAGS = -static bench_inv_LDFLAGS = -static
bench_inv_CPPFLAGS = $(SECP_INCLUDES)
endif endif
if USE_TESTS if USE_TESTS
noinst_PROGRAMS += tests noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c tests_SOURCES = src/tests.c
tests_CPPFLAGS = -DVERIFY $(SECP_TEST_INCLUDES) tests_CPPFLAGS = -DVERIFY $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
tests_LDADD = $(COMMON_LIB) $(SECP_LIBS) $(SECP_TEST_LIBS) tests_LDADD = $(COMMON_LIB) $(SECP_LIBS) $(SECP_TEST_LIBS)
tests_LDFLAGS = -static tests_LDFLAGS = -static
TESTS = tests TESTS = tests

8
build-aux/m4/bitcoin_secp.m4

@ -78,7 +78,13 @@ fi
dnl dnl
AC_DEFUN([SECP_GMP_CHECK],[ AC_DEFUN([SECP_GMP_CHECK],[
if test x"$has_gmp" != x"yes"; then if test x"$has_gmp" != x"yes"; then
AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS=-lgmp; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])]) CPPFLAGS_TEMP="$CPPFLAGS"
CPPFLAGS="$GMP_CPPFLAGS $CPPFLAGS"
LIBS_TEMP="$LIBS"
LIBS="$GMP_LIBS $LIBS"
AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS="$GMP_LIBS -lgmp"; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])])
CPPFLAGS="$CPPFLAGS_TEMP"
LIBS="$LIBS_TEMP"
fi fi
if test x"$set_field" = x"gmp" && test x"$has_gmp" != x"yes"; then if test x"$set_field" = x"gmp" && test x"$has_gmp" != x"yes"; then
AC_MSG_ERROR([$set_field field support explicitly requested but libgmp was not found]) AC_MSG_ERROR([$set_field field support explicitly requested but libgmp was not found])

55
configure.ac

@ -33,9 +33,34 @@ case $host in
esac esac
case $host_os in case $host_os in
darwin*) *darwin*)
CPPFLAGS="$CPPFLAGS -I/opt/local/include" if test x$cross_compiling != xyes; then
AC_PATH_PROG([BREW],brew,)
if test x$BREW != x; then
dnl These Homebrew packages may be keg-only, meaning that they won't be found
dnl in expected paths because they may conflict with system files. Ask
dnl Homebrew where each one is located, then adjust paths accordingly.
openssl_prefix=`$BREW --prefix openssl 2>/dev/null`
gmp_prefix=`$BREW --prefix gmp 2>/dev/null`
if test x$openssl_prefix != x; then
PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
export PKG_CONFIG_PATH
fi
if test x$gmp_prefix != x; then
GMP_CPPFLAGS="-I$gmp_prefix/include"
GMP_LIBS="-L$gmp_prefix/lib"
fi
else
AC_PATH_PROG([PORT],port,)
dnl if homebrew isn't installed and macports is, add the macports default paths
dnl as a last resort.
if test x$PORT != x; then
CPPFLAGS="$CPPFLAGS -isystem /opt/local/include"
LDFLAGS="$LDFLAGS -L/opt/local/lib" LDFLAGS="$LDFLAGS -L/opt/local/lib"
fi
fi
fi
;; ;;
esac esac
@ -70,7 +95,7 @@ AC_ARG_ENABLE(endomorphism,
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=gmp|64bit|64bit_asm|32bit|auto], AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=gmp|64bit|64bit_asm|32bit|auto],
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|auto], AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|none|auto],
[Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto]) [Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto])
AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
@ -154,7 +179,7 @@ if test x"$req_bignum" = x"auto"; then
fi fi
if test x"$set_bignum" = x; then if test x"$set_bignum" = x; then
AC_MSG_ERROR([no working bignum implementation found]) set_bignum=none
fi fi
else else
set_bignum=$req_bignum set_bignum=$req_bignum
@ -162,8 +187,7 @@ else
gmp) gmp)
SECP_GMP_CHECK SECP_GMP_CHECK
;; ;;
openssl) none)
SECP_OPENSSL_CHECK
;; ;;
*) *)
AC_MSG_ERROR([invalid bignum implementation selection]) AC_MSG_ERROR([invalid bignum implementation selection])
@ -197,8 +221,14 @@ esac
case $set_bignum in case $set_bignum in
gmp) gmp)
AC_DEFINE(HAVE_LIBGMP, 1, [Define this symbol if libgmp is installed]) AC_DEFINE(HAVE_LIBGMP, 1, [Define this symbol if libgmp is installed])
AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation]) AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation for num])
AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the USE_FIELD_INV_NUM implementation]) AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])
AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])
;;
none)
AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation])
AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation])
AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation])
;; ;;
*) *)
AC_MSG_ERROR([invalid bignum implementation]) AC_MSG_ERROR([invalid bignum implementation])
@ -236,10 +266,11 @@ fi
if test x"$set_field" = x"gmp" || test x"$set_bignum" = x"gmp"; then if test x"$set_field" = x"gmp" || test x"$set_bignum" = x"gmp"; then
SECP_LIBS="$SECP_LIBS $GMP_LIBS" SECP_LIBS="$SECP_LIBS $GMP_LIBS"
SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS"
fi fi
if test x"$use_endomorphism" = x"yes"; then if test x"$use_endomorphism" = x"yes"; then
AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism]) AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization])
fi fi
AC_MSG_NOTICE([Using field implementation: $set_field]) AC_MSG_NOTICE([Using field implementation: $set_field])
@ -256,4 +287,10 @@ AC_SUBST(YASM_BINFMT)
AM_CONDITIONAL([USE_ASM], [test x"$set_field" == x"64bit_asm"]) AM_CONDITIONAL([USE_ASM], [test x"$set_field" == x"64bit_asm"])
AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" != x"no"])
dnl make sure nothing new is exported so that we don't break the cache
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
unset PKG_CONFIG_PATH
PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP"
AC_OUTPUT AC_OUTPUT

12
include/secp256k1.h

@ -14,18 +14,6 @@ extern "C" {
# endif # endif
# endif # endif
# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
# if SECP256K1_GNUC_PREREQ(3,0)
# define SECP256K1_RESTRICT __restrict__
# elif (defined(_MSC_VER) && _MSC_VER >= 1400)
# define SECP256K1_RESTRICT __restrict
# else
# define SECP256K1_RESTRICT
# endif
# else
# define SECP256K1_RESTRICT restrict
# endif
# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) # if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
# if SECP256K1_GNUC_PREREQ(2,7) # if SECP256K1_GNUC_PREREQ(2,7)
# define SECP256K1_INLINE __inline__ # define SECP256K1_INLINE __inline__

14
src/ecdsa.h

@ -7,17 +7,21 @@
#ifndef _SECP256K1_ECDSA_ #ifndef _SECP256K1_ECDSA_
#define _SECP256K1_ECDSA_ #define _SECP256K1_ECDSA_
#include "num.h" #include "scalar.h"
#include "group.h"
static void secp256k1_ecsda_start(void);
static void secp256k1_ecdsa_stop(void);
typedef struct { typedef struct {
secp256k1_num_t r, s; secp256k1_scalar_t r, s;
} secp256k1_ecdsa_sig_t; } secp256k1_ecdsa_sig_t;
static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size); static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size);
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a); static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a);
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message); static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message);
static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid); static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid);
static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_num_t *message, int recid); static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid);
static void secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *r, const secp256k1_num_t *s); static void secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *r, const secp256k1_scalar_t *s);
#endif #endif

180
src/ecdsa_impl.h

@ -8,13 +8,51 @@
#ifndef _SECP256K1_ECDSA_IMPL_H_ #ifndef _SECP256K1_ECDSA_IMPL_H_
#define _SECP256K1_ECDSA_IMPL_H_ #define _SECP256K1_ECDSA_IMPL_H_
#include "num.h" #include "scalar.h"
#include "field.h" #include "field.h"
#include "group.h" #include "group.h"
#include "ecmult.h" #include "ecmult.h"
#include "ecmult_gen.h" #include "ecmult_gen.h"
#include "ecdsa.h" #include "ecdsa.h"
typedef struct {
secp256k1_fe_t order_as_fe;
secp256k1_fe_t p_minus_order;
} secp256k1_ecdsa_consts_t;
static const secp256k1_ecdsa_consts_t *secp256k1_ecdsa_consts = NULL;
static void secp256k1_ecdsa_start(void) {
if (secp256k1_ecdsa_consts != NULL)
return;
/* Allocate. */
secp256k1_ecdsa_consts_t *ret = (secp256k1_ecdsa_consts_t*)malloc(sizeof(secp256k1_ecdsa_consts_t));
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
};
secp256k1_fe_set_b32(&ret->order_as_fe, order);
secp256k1_fe_negate(&ret->p_minus_order, &ret->order_as_fe, 1);
secp256k1_fe_normalize(&ret->p_minus_order);
/* Set the global pointer. */
secp256k1_ecdsa_consts = ret;
}
static void secp256k1_ecdsa_stop(void) {
if (secp256k1_ecdsa_consts == NULL)
return;
secp256k1_ecdsa_consts_t *c = (secp256k1_ecdsa_consts_t*)secp256k1_ecdsa_consts;
secp256k1_ecdsa_consts = NULL;
free(c);
}
static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) { static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) {
if (sig[0] != 0x30) return 0; if (sig[0] != 0x30) return 0;
int lenr = sig[3]; int lenr = sig[3];
@ -26,18 +64,37 @@ static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned ch
if (lenr == 0) return 0; if (lenr == 0) return 0;
if (sig[lenr+4] != 0x02) return 0; if (sig[lenr+4] != 0x02) return 0;
if (lens == 0) return 0; if (lens == 0) return 0;
secp256k1_num_set_bin(&r->r, sig+4, lenr); const unsigned char *sp = sig + 6 + lenr;
secp256k1_num_set_bin(&r->s, sig+6+lenr, lens); while (lens > 0 && sp[0] == 0) {
lens--;
sp++;
}
if (lens > 32) return 0;
const unsigned char *rp = sig + 4;
while (lenr > 0 && rp[0] == 0) {
lenr--;
rp++;
}
if (lenr > 32) return 0;
unsigned char ra[32] = {0}, sa[32] = {0};
memcpy(ra + 32 - lenr, rp, lenr);
memcpy(sa + 32 - lens, sp, lens);
int overflow = 0;
secp256k1_scalar_set_b32(&r->r, ra, &overflow);
if (overflow) return 0;
secp256k1_scalar_set_b32(&r->s, sa, &overflow);
if (overflow) return 0;
return 1; return 1;
} }
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) { static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) {
int lenR = (secp256k1_num_bits(&a->r) + 7)/8; unsigned char r[33] = {0}, s[33] = {0};
if (lenR == 0 || secp256k1_num_get_bit(&a->r, lenR*8-1)) secp256k1_scalar_get_b32(&r[1], &a->r);
lenR++; secp256k1_scalar_get_b32(&s[1], &a->s);
int lenS = (secp256k1_num_bits(&a->s) + 7)/8; unsigned char *rp = r, *sp = s;
if (lenS == 0 || secp256k1_num_get_bit(&a->s, lenS*8-1)) int lenR = 33, lenS = 33;
lenS++; while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; }
while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; }
if (*size < 6+lenS+lenR) if (*size < 6+lenS+lenR)
return 0; return 0;
*size = 6 + lenS + lenR; *size = 6 + lenS + lenR;
@ -45,98 +102,67 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se
sig[1] = 4 + lenS + lenR; sig[1] = 4 + lenS + lenR;
sig[2] = 0x02; sig[2] = 0x02;
sig[3] = lenR; sig[3] = lenR;
secp256k1_num_get_bin(sig+4, lenR, &a->r); memcpy(sig+4, rp, lenR);
sig[4+lenR] = 0x02; sig[4+lenR] = 0x02;
sig[5+lenR] = lenS; sig[5+lenR] = lenS;
secp256k1_num_get_bin(sig+lenR+6, lenS, &a->s); memcpy(sig+lenR+6, sp, lenS);
return 1; return 1;
} }
static int secp256k1_ecdsa_sig_recompute(secp256k1_num_t *r2, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message) { static int secp256k1_ecdsa_sig_recompute(secp256k1_scalar_t *r2, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) {
const secp256k1_ge_consts_t *c = secp256k1_ge_consts; if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s))
if (secp256k1_num_is_neg(&sig->r) || secp256k1_num_is_neg(&sig->s))
return 0;
if (secp256k1_num_is_zero(&sig->r) || secp256k1_num_is_zero(&sig->s))
return 0;
if (secp256k1_num_cmp(&sig->r, &c->order) >= 0 || secp256k1_num_cmp(&sig->s, &c->order) >= 0)
return 0; return 0;
int ret = 0; int ret = 0;
secp256k1_num_t sn, u1, u2; secp256k1_scalar_t sn, u1, u2;
secp256k1_num_init(&sn); secp256k1_scalar_inverse_var(&sn, &sig->s);
secp256k1_num_init(&u1); secp256k1_scalar_mul(&u1, &sn, message);
secp256k1_num_init(&u2); secp256k1_scalar_mul(&u2, &sn, &sig->r);
secp256k1_num_mod_inverse(&sn, &sig->s, &c->order);
secp256k1_num_mod_mul(&u1, &sn, message, &c->order);
secp256k1_num_mod_mul(&u2, &sn, &sig->r, &c->order);
secp256k1_gej_t pubkeyj; secp256k1_gej_set_ge(&pubkeyj, pubkey); secp256k1_gej_t pubkeyj; secp256k1_gej_set_ge(&pubkeyj, pubkey);
secp256k1_gej_t pr; secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1); secp256k1_gej_t pr; secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1);
if (!secp256k1_gej_is_infinity(&pr)) { if (!secp256k1_gej_is_infinity(&pr)) {
secp256k1_fe_t xr; secp256k1_gej_get_x_var(&xr, &pr); secp256k1_fe_t xr; secp256k1_gej_get_x_var(&xr, &pr);
secp256k1_fe_normalize(&xr); secp256k1_fe_normalize(&xr);
unsigned char xrb[32]; secp256k1_fe_get_b32(xrb, &xr); unsigned char xrb[32]; secp256k1_fe_get_b32(xrb, &xr);
secp256k1_num_set_bin(r2, xrb, 32); secp256k1_scalar_set_b32(r2, xrb, NULL);
secp256k1_num_mod(r2, &c->order);
ret = 1; ret = 1;
} }
secp256k1_num_free(&sn);
secp256k1_num_free(&u1);
secp256k1_num_free(&u2);
return ret; return ret;
} }
static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_num_t *message, int recid) { static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) {
const secp256k1_ge_consts_t *c = secp256k1_ge_consts; if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s))
if (secp256k1_num_is_neg(&sig->r) || secp256k1_num_is_neg(&sig->s))
return 0;
if (secp256k1_num_is_zero(&sig->r) || secp256k1_num_is_zero(&sig->s))
return 0;
if (secp256k1_num_cmp(&sig->r, &c->order) >= 0 || secp256k1_num_cmp(&sig->s, &c->order) >= 0)
return 0; return 0;
secp256k1_num_t rx; unsigned char brx[32];
secp256k1_num_init(&rx); secp256k1_scalar_get_b32(brx, &sig->r);
secp256k1_num_copy(&rx, &sig->r); secp256k1_fe_t fx;
VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */
if (recid & 2) { if (recid & 2) {
secp256k1_num_add(&rx, &rx, &c->order); if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_consts->p_minus_order) >= 0)
if (secp256k1_num_cmp(&rx, &secp256k1_fe_consts->p) >= 0)
return 0; return 0;
secp256k1_fe_add(&fx, &secp256k1_ecdsa_consts->order_as_fe);
} }
unsigned char brx[32];
secp256k1_num_get_bin(brx, 32, &rx);
secp256k1_num_free(&rx);
secp256k1_fe_t fx;
secp256k1_fe_set_b32(&fx, brx);
secp256k1_ge_t x; secp256k1_ge_t x;
if (!secp256k1_ge_set_xo(&x, &fx, recid & 1)) if (!secp256k1_ge_set_xo(&x, &fx, recid & 1))
return 0; return 0;
secp256k1_gej_t xj; secp256k1_gej_t xj;
secp256k1_gej_set_ge(&xj, &x); secp256k1_gej_set_ge(&xj, &x);
secp256k1_num_t rn, u1, u2; secp256k1_scalar_t rn, u1, u2;
secp256k1_num_init(&rn); secp256k1_scalar_inverse_var(&rn, &sig->r);
secp256k1_num_init(&u1); secp256k1_scalar_mul(&u1, &rn, message);
secp256k1_num_init(&u2); secp256k1_scalar_negate(&u1, &u1);
secp256k1_num_mod_inverse(&rn, &sig->r, &c->order); secp256k1_scalar_mul(&u2, &rn, &sig->s);
secp256k1_num_mod_mul(&u1, &rn, message, &c->order);
secp256k1_num_sub(&u1, &c->order, &u1);
secp256k1_num_mod_mul(&u2, &rn, &sig->s, &c->order);
secp256k1_gej_t qj; secp256k1_gej_t qj;
secp256k1_ecmult(&qj, &xj, &u2, &u1); secp256k1_ecmult(&qj, &xj, &u2, &u1);
secp256k1_ge_set_gej_var(pubkey, &qj); secp256k1_ge_set_gej_var(pubkey, &qj);
secp256k1_num_free(&rn);
secp256k1_num_free(&u1);
secp256k1_num_free(&u2);
return !secp256k1_gej_is_infinity(&qj); return !secp256k1_gej_is_infinity(&qj);
} }
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message) { static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) {
secp256k1_num_t r2; secp256k1_scalar_t r2;
secp256k1_num_init(&r2);
int ret = 0; int ret = 0;
ret = secp256k1_ecdsa_sig_recompute(&r2, sig, pubkey, message) && secp256k1_num_cmp(&sig->r, &r2) == 0; ret = secp256k1_ecdsa_sig_recompute(&r2, sig, pubkey, message) && secp256k1_scalar_eq(&sig->r, &r2);
secp256k1_num_free(&r2);
return ret; return ret;
} }
@ -150,34 +176,30 @@ static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_
secp256k1_fe_normalize(&r.y); secp256k1_fe_normalize(&r.y);
secp256k1_fe_get_b32(b, &r.x); secp256k1_fe_get_b32(b, &r.x);
int overflow = 0; int overflow = 0;
secp256k1_scalar_t sigr; secp256k1_scalar_set_b32(&sig->r, b, &overflow);
secp256k1_scalar_set_b32(&sigr, b, &overflow);
if (recid) if (recid)
*recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
secp256k1_scalar_t n; secp256k1_scalar_t n;
secp256k1_scalar_mul(&n, &sigr, seckey); secp256k1_scalar_mul(&n, &sig->r, seckey);
secp256k1_scalar_add(&n, &n, message); secp256k1_scalar_add(&n, &n, message);
secp256k1_scalar_t sigs; secp256k1_scalar_inverse(&sig->s, nonce);
secp256k1_scalar_inverse(&sigs, nonce); secp256k1_scalar_mul(&sig->s, &sig->s, &n);
secp256k1_scalar_mul(&sigs, &sigs, &n);
secp256k1_scalar_clear(&n); secp256k1_scalar_clear(&n);
secp256k1_gej_clear(&rp); secp256k1_gej_clear(&rp);
secp256k1_ge_clear(&r); secp256k1_ge_clear(&r);
if (secp256k1_scalar_is_zero(&sigs)) if (secp256k1_scalar_is_zero(&sig->s))
return 0; return 0;
if (secp256k1_scalar_is_high(&sigs)) { if (secp256k1_scalar_is_high(&sig->s)) {
secp256k1_scalar_negate(&sigs, &sigs); secp256k1_scalar_negate(&sig->s, &sig->s);
if (recid) if (recid)
*recid ^= 1; *recid ^= 1;
} }
secp256k1_scalar_get_num(&sig->s, &sigs);
secp256k1_scalar_get_num(&sig->r, &sigr);
return 1; return 1;
} }
static void secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *r, const secp256k1_num_t *s) { static void secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *r, const secp256k1_scalar_t *s) {
secp256k1_num_copy(&sig->r, r); sig->r = *r;
secp256k1_num_copy(&sig->s, s); sig->s = *s;
} }
#endif #endif

5
src/eckey.h

@ -9,7 +9,6 @@
#include "group.h" #include "group.h"
#include "scalar.h" #include "scalar.h"
#include "num.h"
static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size); static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size);
static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed); static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed);
@ -18,8 +17,8 @@ static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned
static int secp256k1_eckey_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed); static int secp256k1_eckey_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed);
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak); static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak);
static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge_t *key, const secp256k1_num_t *tweak); static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak);
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak); static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak);
static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_num_t *tweak); static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak);
#endif #endif

33
src/eckey_impl.h

@ -9,7 +9,7 @@
#include "eckey.h" #include "eckey.h"
#include "num.h" #include "scalar.h"
#include "field.h" #include "field.h"
#include "group.h" #include "group.h"
#include "ecmult_gen.h" #include "ecmult_gen.h"
@ -17,12 +17,12 @@
static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size) { static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size) {
if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) { if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
secp256k1_fe_t x; secp256k1_fe_t x;
secp256k1_fe_set_b32(&x, pub+1); return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo(elem, &x, pub[0] == 0x03);
return secp256k1_ge_set_xo(elem, &x, pub[0] == 0x03);
} else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) { } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
secp256k1_fe_t x, y; secp256k1_fe_t x, y;
secp256k1_fe_set_b32(&x, pub+1); if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
secp256k1_fe_set_b32(&y, pub+33); return 0;
}
secp256k1_ge_set_xy(elem, &x, &y); secp256k1_ge_set_xy(elem, &x, &y);
if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07))
return 0; return 0;
@ -154,17 +154,12 @@ static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp
return 1; return 1;
} }
static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge_t *key, const secp256k1_num_t *tweak) { static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) {
if (secp256k1_num_cmp(tweak, &secp256k1_ge_consts->order) >= 0)
return 0;
secp256k1_gej_t pt; secp256k1_gej_t pt;
secp256k1_gej_set_ge(&pt, key); secp256k1_gej_set_ge(&pt, key);
secp256k1_num_t one; secp256k1_scalar_t one;
secp256k1_num_init(&one); secp256k1_scalar_set_int(&one, 1);
secp256k1_num_set_int(&one, 1);
secp256k1_ecmult(&pt, &pt, &one, tweak); secp256k1_ecmult(&pt, &pt, &one, tweak);
secp256k1_num_free(&one);
if (secp256k1_gej_is_infinity(&pt)) if (secp256k1_gej_is_infinity(&pt))
return 0; return 0;
@ -180,19 +175,15 @@ static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp
return 1; return 1;
} }
static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_num_t *tweak) { static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) {
if (secp256k1_num_is_zero(tweak)) if (secp256k1_scalar_is_zero(tweak))
return 0;
if (secp256k1_num_cmp(tweak, &secp256k1_ge_consts->order) >= 0)
return 0; return 0;
secp256k1_num_t zero; secp256k1_scalar_t zero;
secp256k1_num_init(&zero); secp256k1_scalar_set_int(&zero, 0);
secp256k1_num_set_int(&zero, 0);
secp256k1_gej_t pt; secp256k1_gej_t pt;
secp256k1_gej_set_ge(&pt, key); secp256k1_gej_set_ge(&pt, key);
secp256k1_ecmult(&pt, &pt, tweak, &zero); secp256k1_ecmult(&pt, &pt, tweak, &zero);
secp256k1_num_free(&zero);
secp256k1_ge_set_gej(key, &pt); secp256k1_ge_set_gej(key, &pt);
return 1; return 1;
} }

2
src/ecmult.h

@ -14,6 +14,6 @@ static void secp256k1_ecmult_start(void);
static void secp256k1_ecmult_stop(void); static void secp256k1_ecmult_stop(void);
/** Double multiply: R = na*A + ng*G */ /** Double multiply: R = na*A + ng*G */
static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_num_t *na, const secp256k1_num_t *ng); static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng);
#endif #endif

19
src/ecmult_gen_impl.h

@ -23,8 +23,8 @@ typedef struct {
* precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63). * precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63).
* None of the resulting prec group elements have a known scalar, and neither do any of * None of the resulting prec group elements have a known scalar, and neither do any of
* the intermediate sums while computing a*G. * the intermediate sums while computing a*G.
* To make memory access uniform, the bytes of prec(i, n_i) are sliced per value of n_i. */ */
unsigned char prec[64][sizeof(secp256k1_ge_t)][16]; /* prec[j][k][i] = k'th byte of (16^j * i * G + U_i) */ secp256k1_fe_t prec[64][16][2]; /* prec[j][i] = (16^j * i * G + U_i).{x,y} */
} secp256k1_ecmult_gen_consts_t; } secp256k1_ecmult_gen_consts_t;
static const secp256k1_ecmult_gen_consts_t *secp256k1_ecmult_gen_consts = NULL; static const secp256k1_ecmult_gen_consts_t *secp256k1_ecmult_gen_consts = NULL;
@ -45,7 +45,7 @@ static void secp256k1_ecmult_gen_start(void) {
{ {
static const unsigned char nums_b32[32] = "The scalar for this x is unknown"; static const unsigned char nums_b32[32] = "The scalar for this x is unknown";
secp256k1_fe_t nums_x; secp256k1_fe_t nums_x;
secp256k1_fe_set_b32(&nums_x, nums_b32); VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32));
secp256k1_ge_t nums_ge; secp256k1_ge_t nums_ge;
VERIFY_CHECK(secp256k1_ge_set_xo(&nums_ge, &nums_x, 0)); VERIFY_CHECK(secp256k1_ge_set_xo(&nums_ge, &nums_x, 0));
secp256k1_gej_set_ge(&nums_gej, &nums_ge); secp256k1_gej_set_ge(&nums_gej, &nums_ge);
@ -81,9 +81,9 @@ static void secp256k1_ecmult_gen_start(void) {
} }
for (int j=0; j<64; j++) { for (int j=0; j<64; j++) {
for (int i=0; i<16; i++) { for (int i=0; i<16; i++) {
const unsigned char* raw = (const unsigned char*)(&prec[j*16 + i]); VERIFY_CHECK(!secp256k1_ge_is_infinity(&prec[j*16 + i]));
for (size_t k=0; k<sizeof(secp256k1_ge_t); k++) ret->prec[j][i][0] = prec[j*16 + i].x;
ret->prec[j][k][i] = raw[k]; ret->prec[j][i][1] = prec[j*16 + i].y;
} }
} }
@ -104,11 +104,14 @@ static void secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_scalar_t *g
const secp256k1_ecmult_gen_consts_t *c = secp256k1_ecmult_gen_consts; const secp256k1_ecmult_gen_consts_t *c = secp256k1_ecmult_gen_consts;
secp256k1_gej_set_infinity(r); secp256k1_gej_set_infinity(r);
secp256k1_ge_t add; secp256k1_ge_t add;
add.infinity = 0;
int bits; int bits;
for (int j=0; j<64; j++) { for (int j=0; j<64; j++) {
bits = secp256k1_scalar_get_bits(gn, j * 4, 4); bits = secp256k1_scalar_get_bits(gn, j * 4, 4);
for (size_t k=0; k<sizeof(secp256k1_ge_t); k++) for (int i=0; i<16; i++) {
((unsigned char*)(&add))[k] = c->prec[j][k][bits]; secp256k1_fe_cmov(&add.x, &c->prec[j][i][0], i == bits);
secp256k1_fe_cmov(&add.y, &c->prec[j][i][1], i == bits);
}
secp256k1_gej_add_ge(r, r, &add); secp256k1_gej_add_ge(r, r, &add);
} }
bits = 0; bits = 0;

99
src/ecmult_impl.h

@ -7,8 +7,8 @@
#ifndef _SECP256K1_ECMULT_IMPL_H_ #ifndef _SECP256K1_ECMULT_IMPL_H_
#define _SECP256K1_ECMULT_IMPL_H_ #define _SECP256K1_ECMULT_IMPL_H_
#include "num.h"
#include "group.h" #include "group.h"
#include "scalar.h"
#include "ecmult.h" #include "ecmult.h"
/* optimal for 128-bit and 256-bit exponents. */ /* optimal for 128-bit and 256-bit exponents. */
@ -16,7 +16,11 @@
/** larger numbers may result in slightly better performance, at the cost of /** larger numbers may result in slightly better performance, at the cost of
exponentially larger precomputed tables. WINDOW_G == 14 results in 640 KiB. */ exponentially larger precomputed tables. WINDOW_G == 14 results in 640 KiB. */
#ifdef USE_ENDOMORPHISM
#define WINDOW_G 14 #define WINDOW_G 14
#else
#define WINDOW_G 15
#endif
/** Fill a table 'pre' with precomputed odd multiples of a. W determines the size of the table. /** Fill a table 'pre' with precomputed odd multiples of a. W determines the size of the table.
* pre will contains the values [1*a,3*a,5*a,...,(2^(w-1)-1)*a], so it needs place for * pre will contains the values [1*a,3*a,5*a,...,(2^(w-1)-1)*a], so it needs place for
@ -69,7 +73,9 @@ static void secp256k1_ecmult_table_precomp_ge_var(secp256k1_ge_t *pre, const sec
typedef struct { typedef struct {
/* For accelerating the computation of a*P + b*G: */ /* For accelerating the computation of a*P + b*G: */
secp256k1_ge_t pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of the generator */ secp256k1_ge_t pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of the generator */
#ifdef USE_ENDOMORPHISM
secp256k1_ge_t pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of 2^128*generator */ secp256k1_ge_t pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of 2^128*generator */
#endif
} secp256k1_ecmult_consts_t; } secp256k1_ecmult_consts_t;
static const secp256k1_ecmult_consts_t *secp256k1_ecmult_consts = NULL; static const secp256k1_ecmult_consts_t *secp256k1_ecmult_consts = NULL;
@ -85,14 +91,18 @@ static void secp256k1_ecmult_start(void) {
const secp256k1_ge_t *g = &secp256k1_ge_consts->g; const secp256k1_ge_t *g = &secp256k1_ge_consts->g;
secp256k1_gej_t gj; secp256k1_gej_set_ge(&gj, g); secp256k1_gej_t gj; secp256k1_gej_set_ge(&gj, g);
#ifdef USE_ENDOMORPHISM
/* calculate 2^128*generator */ /* calculate 2^128*generator */
secp256k1_gej_t g_128j = gj; secp256k1_gej_t g_128j = gj;
for (int i=0; i<128; i++) for (int i=0; i<128; i++)
secp256k1_gej_double_var(&g_128j, &g_128j); secp256k1_gej_double_var(&g_128j, &g_128j);
#endif
/* precompute the tables with odd multiples */ /* precompute the tables with odd multiples */
secp256k1_ecmult_table_precomp_ge_var(ret->pre_g, &gj, WINDOW_G); secp256k1_ecmult_table_precomp_ge_var(ret->pre_g, &gj, WINDOW_G);
#ifdef USE_ENDOMORPHISM
secp256k1_ecmult_table_precomp_ge_var(ret->pre_g_128, &g_128j, WINDOW_G); secp256k1_ecmult_table_precomp_ge_var(ret->pre_g_128, &g_128j, WINDOW_G);
#endif
/* Set the global pointer to the precomputation table. */ /* Set the global pointer to the precomputation table. */
secp256k1_ecmult_consts = ret; secp256k1_ecmult_consts = ret;
@ -111,56 +121,62 @@ static void secp256k1_ecmult_stop(void) {
* with the following guarantees: * with the following guarantees:
* - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1)
* - two non-zero entries in wnaf are separated by at least w-1 zeroes. * - two non-zero entries in wnaf are separated by at least w-1 zeroes.
* - the index of the highest non-zero entry in wnaf (=return value-1) is at most bits, where * - the number of set values in wnaf is returned. This number is at most 256, and at most one more
* bits is the number of bits necessary to represent the absolute value of the input. * - than the number of bits in the (absolute value) of the input.
*/ */
static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_num_t *a, int w) { static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w) {
int ret = 0; secp256k1_scalar_t s = *a;
int zeroes = 0;
secp256k1_num_t x;
secp256k1_num_copy(&x, a);
int sign = 1; int sign = 1;
if (secp256k1_num_is_neg(&x)) { if (secp256k1_scalar_get_bits(&s, 255, 1)) {
secp256k1_scalar_negate(&s, &s);
sign = -1; sign = -1;
secp256k1_num_negate(&x);
} }
while (!secp256k1_num_is_zero(&x)) {
while (!secp256k1_num_is_odd(&x)) { int set_bits = 0;
zeroes++; int bit = 0;
secp256k1_num_shift(&x, 1); while (bit < 256) {
if (secp256k1_scalar_get_bits(&s, bit, 1) == 0) {
bit++;
continue;
}
while (set_bits < bit) {
wnaf[set_bits++] = 0;
} }
int word = secp256k1_num_shift(&x, w); int now = w;
while (zeroes) { if (bit + now > 256) {
wnaf[ret++] = 0; now = 256 - bit;
zeroes--;
} }
int word = secp256k1_scalar_get_bits_var(&s, bit, now);
if (word & (1 << (w-1))) { if (word & (1 << (w-1))) {
secp256k1_num_inc(&x); secp256k1_scalar_add_bit(&s, bit + w);
wnaf[ret++] = sign * (word - (1 << w)); wnaf[set_bits++] = sign * (word - (1 << w));
} else { } else {
wnaf[ret++] = sign * word; wnaf[set_bits++] = sign * word;
} }
zeroes = w-1; bit += now;
} }
return ret; return set_bits;
} }
static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_num_t *na, const secp256k1_num_t *ng) { static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng) {
const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts; const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts;
#ifdef USE_ENDOMORPHISM #ifdef USE_ENDOMORPHISM
secp256k1_num_t na_1, na_lam; secp256k1_scalar_t na_1, na_lam;
/* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */
secp256k1_gej_split_exp_var(&na_1, &na_lam, na); secp256k1_scalar_split_lambda_var(&na_1, &na_lam, na);
/* build wnaf representation for na_1 and na_lam. */ /* build wnaf representation for na_1 and na_lam. */
int wnaf_na_1[129]; int bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A); int wnaf_na_1[130]; int bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A);
int wnaf_na_lam[129]; int bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A); int wnaf_na_lam[130]; int bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A);
VERIFY_CHECK(bits_na_1 <= 130);
VERIFY_CHECK(bits_na_lam <= 130);
int bits = bits_na_1; int bits = bits_na_1;
if (bits_na_lam > bits) bits = bits_na_lam; if (bits_na_lam > bits) bits = bits_na_lam;
#else #else
/* build wnaf representation for na. */ /* build wnaf representation for na. */
int wnaf_na[257]; int bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A); int wnaf_na[256]; int bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A);
int bits = bits_na; int bits = bits_na;
#endif #endif
@ -172,19 +188,22 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const
secp256k1_gej_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; secp256k1_gej_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
for (int i=0; i<ECMULT_TABLE_SIZE(WINDOW_A); i++) for (int i=0; i<ECMULT_TABLE_SIZE(WINDOW_A); i++)
secp256k1_gej_mul_lambda(&pre_a_lam[i], &pre_a[i]); secp256k1_gej_mul_lambda(&pre_a_lam[i], &pre_a[i]);
#endif
/* Splitted G factors. */ /* Splitted G factors. */
secp256k1_num_t ng_1, ng_128; secp256k1_scalar_t ng_1, ng_128;
/* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */
secp256k1_num_split(&ng_1, &ng_128, ng, 128); secp256k1_scalar_split_128(&ng_1, &ng_128, ng);
/* Build wnaf representation for ng_1 and ng_128 */ /* Build wnaf representation for ng_1 and ng_128 */
int wnaf_ng_1[129]; int bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G); int wnaf_ng_1[129]; int bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G);
int wnaf_ng_128[129]; int bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G); int wnaf_ng_128[129]; int bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G);
if (bits_ng_1 > bits) bits = bits_ng_1; if (bits_ng_1 > bits) bits = bits_ng_1;
if (bits_ng_128 > bits) bits = bits_ng_128; if (bits_ng_128 > bits) bits = bits_ng_128;
#else
int wnaf_ng[257]; int bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G);
if (bits_ng > bits) bits = bits_ng;
#endif
secp256k1_gej_set_infinity(r); secp256k1_gej_set_infinity(r);
secp256k1_gej_t tmpj; secp256k1_gej_t tmpj;
@ -202,12 +221,6 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const
ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_lam, n, WINDOW_A); ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_lam, n, WINDOW_A);
secp256k1_gej_add_var(r, r, &tmpj); secp256k1_gej_add_var(r, r, &tmpj);
} }
#else
if (i < bits_na && (n = wnaf_na[i])) {
ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A);
secp256k1_gej_add_var(r, r, &tmpj);
}
#endif
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
ECMULT_TABLE_GET_GE(&tmpa, c->pre_g, n, WINDOW_G); ECMULT_TABLE_GET_GE(&tmpa, c->pre_g, n, WINDOW_G);
secp256k1_gej_add_ge_var(r, r, &tmpa); secp256k1_gej_add_ge_var(r, r, &tmpa);
@ -216,6 +229,16 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const
ECMULT_TABLE_GET_GE(&tmpa, c->pre_g_128, n, WINDOW_G); ECMULT_TABLE_GET_GE(&tmpa, c->pre_g_128, n, WINDOW_G);
secp256k1_gej_add_ge_var(r, r, &tmpa); secp256k1_gej_add_ge_var(r, r, &tmpa);
} }
#else
if (i < bits_na && (n = wnaf_na[i])) {
ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A);
secp256k1_gej_add_var(r, r, &tmpj);
}
if (i < bits_ng && (n = wnaf_ng[i])) {
ECMULT_TABLE_GET_GE(&tmpa, c->pre_g, n, WINDOW_G);
secp256k1_gej_add_ge_var(r, r, &tmpa);
}
#endif
} }
} }

18
src/field.h

@ -33,7 +33,10 @@
#endif #endif
typedef struct { typedef struct {
#ifndef USE_NUM_NONE
secp256k1_num_t p; secp256k1_num_t p;
#endif
secp256k1_fe_t order;
} secp256k1_fe_consts_t; } secp256k1_fe_consts_t;
static const secp256k1_fe_consts_t *secp256k1_fe_consts = NULL; static const secp256k1_fe_consts_t *secp256k1_fe_consts = NULL;
@ -59,8 +62,11 @@ static int secp256k1_fe_is_odd(const secp256k1_fe_t *a);
/** Compare two field elements. Requires both inputs to be normalized */ /** Compare two field elements. Requires both inputs to be normalized */
static int secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b); static int 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. */ /** Compare two field elements. Requires both inputs to be normalized */
static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a); static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b);
/** Set a field element equal to 32-byte big endian value. If succesful, the resulting field element is normalized. */
static int 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 */ /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a); static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a);
@ -78,7 +84,7 @@ static void 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. /** 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). */ * The output magnitude is 1 (but not guaranteed to be normalized). */
static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b); static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b);
/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. /** 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). */ * The output magnitude is 1 (but not guaranteed to be normalized). */
@ -104,11 +110,13 @@ static void secp256k1_fe_inv_all(size_t len, secp256k1_fe_t r[len], const secp25
/** Potentially faster version of secp256k1_fe_inv_all, without constant-time guarantee. */ /** Potentially faster version of secp256k1_fe_inv_all, without constant-time guarantee. */
static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t r[len], const secp256k1_fe_t a[len]); static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t r[len], const secp256k1_fe_t a[len]);
/** Convert a field element to a hexadecimal string. */ /** Convert a field element to a hexadecimal string. */
static void secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a); static void secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a);
/** Convert a hexadecimal string to a field element. */ /** Convert a hexadecimal string to a field element. */
static void secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen); static int secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen);
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag);
#endif #endif

45
src/field_10x26_impl.h

@ -152,7 +152,21 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe_t *a, const se
| (t[5]^u[5]) | (t[6]^u[6]) | (t[7]^u[7]) | (t[8]^u[8]) | (t[9]^u[9])) == 0; | (t[5]^u[5]) | (t[6]^u[6]) | (t[7]^u[7]) | (t[8]^u[8]) | (t[9]^u[9])) == 0;
} }
static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
VERIFY_CHECK(b->normalized);
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
#endif
for (int i = 9; i >= 0; i--) {
if (a->n[i] > b->n[i]) return 1;
if (a->n[i] < b->n[i]) return -1;
}
return 0;
}
static int 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; r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
for (int i=0; i<32; i++) { for (int i=0; i<32; i++) {
@ -162,11 +176,15 @@ static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift; r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift;
} }
} }
if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) {
return 0;
}
#ifdef VERIFY #ifdef VERIFY
r->magnitude = 1; r->magnitude = 1;
r->normalized = 1; r->normalized = 1;
secp256k1_fe_verify(r); secp256k1_fe_verify(r);
#endif #endif
return 1;
} }
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
@ -253,7 +271,7 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1
#define VERIFY_BITS(x, n) do { } while(0) #define VERIFY_BITS(x, n) do { } while(0)
#endif #endif
SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uint32_t *b, uint32_t *r) { SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b, uint32_t *r) {
VERIFY_BITS(a[0], 30); VERIFY_BITS(a[0], 30);
VERIFY_BITS(a[1], 30); VERIFY_BITS(a[1], 30);
VERIFY_BITS(a[2], 30); VERIFY_BITS(a[2], 30);
@ -853,12 +871,13 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(const uint32_t *a, uint32_t
} }
static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) { static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) {
#ifdef VERIFY #ifdef VERIFY
VERIFY_CHECK(a->magnitude <= 8); VERIFY_CHECK(a->magnitude <= 8);
VERIFY_CHECK(b->magnitude <= 8); VERIFY_CHECK(b->magnitude <= 8);
secp256k1_fe_verify(a); secp256k1_fe_verify(a);
secp256k1_fe_verify(b); secp256k1_fe_verify(b);
VERIFY_CHECK(r != b);
#endif #endif
secp256k1_fe_mul_inner(a->n, b->n, r->n); secp256k1_fe_mul_inner(a->n, b->n, r->n);
#ifdef VERIFY #ifdef VERIFY
@ -881,4 +900,24 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#endif #endif
} }
static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) {
uint32_t mask0 = flag + ~((uint32_t)0), mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1);
r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1);
r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);
r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1);
r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1);
#ifdef VERIFY
if (flag) {
r->magnitude = a->magnitude;
r->normalized = a->normalized;
}
#endif
}
#endif #endif

38
src/field_5x52_impl.h

@ -150,7 +150,21 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe_t *a, const se
return ((t[0]^u[0]) | (t[1]^u[1]) | (t[2]^u[2]) | (t[3]^u[3]) | (t[4]^u[4])) == 0; return ((t[0]^u[0]) | (t[1]^u[1]) | (t[2]^u[2]) | (t[3]^u[3]) | (t[4]^u[4])) == 0;
} }
static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
VERIFY_CHECK(b->normalized);
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
#endif
for (int i = 4; i >= 0; i--) {
if (a->n[i] > b->n[i]) return 1;
if (a->n[i] < b->n[i]) return -1;
}
return 0;
}
static int 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; 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 i=0; i<32; i++) {
for (int j=0; j<2; j++) { for (int j=0; j<2; j++) {
@ -159,11 +173,15 @@ static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift; r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift;
} }
} }
if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) {
return 0;
}
#ifdef VERIFY #ifdef VERIFY
r->magnitude = 1; r->magnitude = 1;
r->normalized = 1; r->normalized = 1;
secp256k1_fe_verify(r); secp256k1_fe_verify(r);
#endif #endif
return 1;
} }
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
@ -229,12 +247,13 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1
#endif #endif
} }
static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) { static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) {
#ifdef VERIFY #ifdef VERIFY
VERIFY_CHECK(a->magnitude <= 8); VERIFY_CHECK(a->magnitude <= 8);
VERIFY_CHECK(b->magnitude <= 8); VERIFY_CHECK(b->magnitude <= 8);
secp256k1_fe_verify(a); secp256k1_fe_verify(a);
secp256k1_fe_verify(b); secp256k1_fe_verify(b);
VERIFY_CHECK(r != b);
#endif #endif
secp256k1_fe_mul_inner(a->n, b->n, r->n); secp256k1_fe_mul_inner(a->n, b->n, r->n);
#ifdef VERIFY #ifdef VERIFY
@ -257,4 +276,19 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
#endif #endif
} }
static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) {
uint64_t mask0 = flag + ~((uint64_t)0), mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
#ifdef VERIFY
if (flag) {
r->magnitude = a->magnitude;
r->normalized = a->normalized;
}
#endif
}
#endif #endif

84
src/field_5x52_int128_impl.h

@ -15,7 +15,7 @@
#define VERIFY_BITS(x, n) do { } while(0) #define VERIFY_BITS(x, n) do { } while(0)
#endif #endif
SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t *b, uint64_t *r) { SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b, uint64_t *r) {
VERIFY_BITS(a[0], 56); VERIFY_BITS(a[0], 56);
VERIFY_BITS(a[1], 56); VERIFY_BITS(a[1], 56);
VERIFY_BITS(a[2], 56); VERIFY_BITS(a[2], 56);
@ -26,6 +26,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin
VERIFY_BITS(b[2], 56); VERIFY_BITS(b[2], 56);
VERIFY_BITS(b[3], 56); VERIFY_BITS(b[3], 56);
VERIFY_BITS(b[4], 52); VERIFY_BITS(b[4], 52);
VERIFY_CHECK(r != b);
const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
/* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. /* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.
@ -33,15 +34,17 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin
* Note that [x 0 0 0 0 0] = [x*R]. * Note that [x 0 0 0 0 0] = [x*R].
*/ */
uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
__int128 c, d; __int128 c, d;
d = (__int128)a[0] * b[3] d = (__int128)a0 * b[3]
+ (__int128)a[1] * b[2] + (__int128)a1 * b[2]
+ (__int128)a[2] * b[1] + (__int128)a2 * b[1]
+ (__int128)a[3] * b[0]; + (__int128)a3 * b[0];
VERIFY_BITS(d, 114); VERIFY_BITS(d, 114);
/* [d 0 0 0] = [p3 0 0 0] */ /* [d 0 0 0] = [p3 0 0 0] */
c = (__int128)a[4] * b[4]; c = (__int128)a4 * b[4];
VERIFY_BITS(c, 112); VERIFY_BITS(c, 112);
/* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
d += (c & M) * R; c >>= 52; d += (c & M) * R; c >>= 52;
@ -53,11 +56,11 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin
VERIFY_BITS(d, 63); VERIFY_BITS(d, 63);
/* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
d += (__int128)a[0] * b[4] d += (__int128)a0 * b[4]
+ (__int128)a[1] * b[3] + (__int128)a1 * b[3]
+ (__int128)a[2] * b[2] + (__int128)a2 * b[2]
+ (__int128)a[3] * b[1] + (__int128)a3 * b[1]
+ (__int128)a[4] * b[0]; + (__int128)a4 * b[0];
VERIFY_BITS(d, 115); VERIFY_BITS(d, 115);
/* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
d += c * R; d += c * R;
@ -72,13 +75,13 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin
VERIFY_BITS(t4, 48); VERIFY_BITS(t4, 48);
/* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
c = (__int128)a[0] * b[0]; c = (__int128)a0 * b[0];
VERIFY_BITS(c, 112); VERIFY_BITS(c, 112);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */
d += (__int128)a[1] * b[4] d += (__int128)a1 * b[4]
+ (__int128)a[2] * b[3] + (__int128)a2 * b[3]
+ (__int128)a[3] * b[2] + (__int128)a3 * b[2]
+ (__int128)a[4] * b[1]; + (__int128)a4 * b[1];
VERIFY_BITS(d, 115); VERIFY_BITS(d, 115);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
uint64_t u0 = d & M; d >>= 52; uint64_t u0 = d & M; d >>= 52;
@ -92,48 +95,43 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(const uint64_t *a, const uin
c += (__int128)u0 * (R >> 4); c += (__int128)u0 * (R >> 4);
VERIFY_BITS(c, 115); VERIFY_BITS(c, 115);
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
uint64_t t0 = c & M; c >>= 52; r[0] = c & M; c >>= 52;
VERIFY_BITS(t0, 52); VERIFY_BITS(r[0], 52);
VERIFY_BITS(c, 61); VERIFY_BITS(c, 61);
/* [d 0 t4 t3 0 c t0] = [p8 0 0 p5 p4 p3 0 0 p0] */ /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */
c += (__int128)a[0] * b[1] c += (__int128)a0 * b[1]
+ (__int128)a[1] * b[0]; + (__int128)a1 * b[0];
VERIFY_BITS(c, 114); VERIFY_BITS(c, 114);
/* [d 0 t4 t3 0 c t0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */
d += (__int128)a[2] * b[4] d += (__int128)a2 * b[4]
+ (__int128)a[3] * b[3] + (__int128)a3 * b[3]
+ (__int128)a[4] * b[2]; + (__int128)a4 * b[2];
VERIFY_BITS(d, 114); VERIFY_BITS(d, 114);
/* [d 0 t4 t3 0 c t0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
c += (d & M) * R; d >>= 52; c += (d & M) * R; d >>= 52;
VERIFY_BITS(c, 115); VERIFY_BITS(c, 115);
VERIFY_BITS(d, 62); VERIFY_BITS(d, 62);
/* [d 0 0 t4 t3 0 c t0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
uint64_t t1 = c & M; c >>= 52; r[1] = c & M; c >>= 52;
VERIFY_BITS(t1, 52); VERIFY_BITS(r[1], 52);
VERIFY_BITS(c, 63); VERIFY_BITS(c, 63);
/* [d 0 0 t4 t3 c t1 t0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
c += (__int128)a[0] * b[2] c += (__int128)a0 * b[2]
+ (__int128)a[1] * b[1] + (__int128)a1 * b[1]
+ (__int128)a[2] * b[0]; + (__int128)a2 * b[0];
VERIFY_BITS(c, 114); VERIFY_BITS(c, 114);
/* [d 0 0 t4 t3 c t1 t0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */
d += (__int128)a[3] * b[4] d += (__int128)a3 * b[4]
+ (__int128)a[4] * b[3]; + (__int128)a4 * b[3];
VERIFY_BITS(d, 114); VERIFY_BITS(d, 114);
/* [d 0 0 t4 t3 c t1 t0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += (d & M) * R; d >>= 52; c += (d & M) * R; d >>= 52;
VERIFY_BITS(c, 115); VERIFY_BITS(c, 115);
VERIFY_BITS(d, 62); VERIFY_BITS(d, 62);
/* [d 0 0 0 t4 t3 c t1 t0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[0] = t0;
VERIFY_BITS(r[0], 52);
/* [d 0 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[1] = t1;
VERIFY_BITS(r[1], 52);
/* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[2] = c & M; c >>= 52; r[2] = c & M; c >>= 52;
VERIFY_BITS(r[2], 52); VERIFY_BITS(r[2], 52);

21
src/field_gmp_impl.h

@ -75,7 +75,15 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe_t *a, const se
return ret; return ret;
} }
static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
for (int i=FIELD_LIMBS; i>=0; i--) {
if (a->n[i] > b->n[i]) return 1;
if (a->n[i] < b->n[i]) return -1;
}
return 0;
}
static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
for (int i=0; i<FIELD_LIMBS+1; i++) for (int i=0; i<FIELD_LIMBS+1; i++)
r->n[i] = 0; r->n[i] = 0;
for (int i=0; i<256; i++) { for (int i=0; i<256; i++) {
@ -83,6 +91,7 @@ static void secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
int shift = i%GMP_NUMB_BITS; int shift = i%GMP_NUMB_BITS;
r->n[limb] |= (mp_limb_t)((a[31-i/8] >> (i%8)) & 0x1) << shift; r->n[limb] |= (mp_limb_t)((a[31-i/8] >> (i%8)) & 0x1) << shift;
} }
return (mpn_cmp(r->n, secp256k1_field_p, FIELD_LIMBS) < 0);
} }
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
@ -142,7 +151,8 @@ static void secp256k1_fe_reduce(secp256k1_fe_t *r, mp_limb_t *tmp) {
r->n[FIELD_LIMBS] = mpn_add(r->n, tmp, FIELD_LIMBS, q, 1+(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS); r->n[FIELD_LIMBS] = mpn_add(r->n, tmp, FIELD_LIMBS, q, 1+(33+GMP_NUMB_BITS-1)/GMP_NUMB_BITS);
} }
static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) { static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) {
VERIFY_CHECK(r != b);
secp256k1_fe_t ac = *a; secp256k1_fe_t ac = *a;
secp256k1_fe_t bc = *b; secp256k1_fe_t bc = *b;
secp256k1_fe_normalize(&ac); secp256k1_fe_normalize(&ac);
@ -160,4 +170,11 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
secp256k1_fe_reduce(r, tmp); secp256k1_fe_reduce(r, tmp);
} }
static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) {
mp_limb_t mask0 = flag + ~((mp_limb_t)0), mask1 = ~mask0;
for (int i = 0; i <= FIELD_LIMBS; i++) {
r->n[i] = (r->n[i] & mask0) | (a->n[i] & mask1);
}
}
#endif #endif

12
src/field_impl.h

@ -41,7 +41,7 @@ static void secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a) {
r[64] = 0x00; r[64] = 0x00;
} }
static void secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) { static int secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) {
unsigned char tmp[32] = {}; 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, 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,
@ -63,7 +63,7 @@ static void secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) {
if (alen > i*2) if (alen > i*2)
tmp[32 - alen/2 + i] = (cvt[(unsigned char)a[2*i]] << 4) + cvt[(unsigned char)a[2*i+1]]; 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); return secp256k1_fe_set_b32(r, tmp);
} }
static int secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a) { static int secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
@ -197,7 +197,7 @@ static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
for (int j=0; j<3; j++) secp256k1_fe_sqr(&t1, &t1); for (int j=0; j<3; j++) secp256k1_fe_sqr(&t1, &t1);
secp256k1_fe_mul(&t1, &t1, &x2); secp256k1_fe_mul(&t1, &t1, &x2);
for (int j=0; j<2; j++) secp256k1_fe_sqr(&t1, &t1); for (int j=0; j<2; j++) secp256k1_fe_sqr(&t1, &t1);
secp256k1_fe_mul(r, &t1, a); secp256k1_fe_mul(r, a, &t1);
} }
static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
@ -212,7 +212,7 @@ static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
secp256k1_num_set_bin(&n, b, 32); secp256k1_num_set_bin(&n, b, 32);
secp256k1_num_mod_inverse(&n, &n, &secp256k1_fe_consts->p); secp256k1_num_mod_inverse(&n, &n, &secp256k1_fe_consts->p);
secp256k1_num_get_bin(b, 32, &n); secp256k1_num_get_bin(b, 32, &n);
secp256k1_fe_set_b32(r, b); VERIFY_CHECK(secp256k1_fe_set_b32(r, b));
#else #else
#error "Please select field inverse implementation" #error "Please select field inverse implementation"
#endif #endif
@ -267,16 +267,20 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t r[len], const se
} }
static void secp256k1_fe_start(void) { static void secp256k1_fe_start(void) {
#ifndef USE_NUM_NONE
static const unsigned char secp256k1_fe_consts_p[] = { 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,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 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
}; };
#endif
if (secp256k1_fe_consts == NULL) { if (secp256k1_fe_consts == NULL) {
secp256k1_fe_inner_start(); secp256k1_fe_inner_start();
secp256k1_fe_consts_t *ret = (secp256k1_fe_consts_t*)malloc(sizeof(secp256k1_fe_consts_t)); secp256k1_fe_consts_t *ret = (secp256k1_fe_consts_t*)malloc(sizeof(secp256k1_fe_consts_t));
#ifndef USE_NUM_NONE
secp256k1_num_set_bin(&ret->p, secp256k1_fe_consts_p, sizeof(secp256k1_fe_consts_p)); secp256k1_num_set_bin(&ret->p, secp256k1_fe_consts_p, sizeof(secp256k1_fe_consts_p));
#endif
secp256k1_fe_consts = ret; secp256k1_fe_consts = ret;
} }
} }

8
src/group.h

@ -27,14 +27,11 @@ typedef struct {
/** Global constants related to the group */ /** Global constants related to the group */
typedef struct { typedef struct {
secp256k1_num_t order; /* the order of the curve (= order of its generator) */
secp256k1_num_t half_order; /* half the order of the curve (= order of its generator) */
secp256k1_ge_t g; /* the generator point */ secp256k1_ge_t g; /* the generator point */
#ifdef USE_ENDOMORPHISM #ifdef USE_ENDOMORPHISM
/* constants related to secp256k1's efficiently computable endomorphism */ /* constants related to secp256k1's efficiently computable endomorphism */
secp256k1_fe_t beta; secp256k1_fe_t beta;
secp256k1_num_t lambda, a1b2, b1, a2;
#endif #endif
} secp256k1_ge_consts_t; } secp256k1_ge_consts_t;
@ -112,10 +109,6 @@ static void secp256k1_gej_get_hex(char *r, int *rlen, const secp256k1_gej_t *a);
#ifdef USE_ENDOMORPHISM #ifdef USE_ENDOMORPHISM
/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ /** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */
static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a); static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a);
/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (given that a is
not more than 256 bits). */
static void secp256k1_gej_split_exp_var(secp256k1_num_t *r1, secp256k1_num_t *r2, const secp256k1_num_t *a);
#endif #endif
/** Clear a secp256k1_gej_t to prevent leaking sensitive information. */ /** Clear a secp256k1_gej_t to prevent leaking sensitive information. */
@ -124,5 +117,4 @@ static void secp256k1_gej_clear(secp256k1_gej_t *r);
/** Clear a secp256k1_ge_t to prevent leaking sensitive information. */ /** Clear a secp256k1_ge_t to prevent leaking sensitive information. */
static void secp256k1_ge_clear(secp256k1_ge_t *r); static void secp256k1_ge_clear(secp256k1_ge_t *r);
#endif #endif

86
src/group_impl.h

@ -208,29 +208,25 @@ static int secp256k1_ge_is_valid(const secp256k1_ge_t *a) {
} }
static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a) { static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
if (a->infinity) { // For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
r->infinity = 1; // Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
return; // y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
} r->infinity = a->infinity;
if (r->infinity) {
secp256k1_fe_t t5 = a->y;
secp256k1_fe_normalize(&t5);
if (secp256k1_fe_is_zero(&t5)) {
r->infinity = 1;
return; return;
} }
secp256k1_fe_t t1,t2,t3,t4; secp256k1_fe_t t1,t2,t3,t4;
secp256k1_fe_mul(&r->z, &t5, &a->z); secp256k1_fe_mul(&r->z, &a->z, &a->y);
secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */ secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */
secp256k1_fe_sqr(&t1, &a->x); secp256k1_fe_sqr(&t1, &a->x);
secp256k1_fe_mul_int(&t1, 3); /* T1 = 3*X^2 (3) */ secp256k1_fe_mul_int(&t1, 3); /* T1 = 3*X^2 (3) */
secp256k1_fe_sqr(&t2, &t1); /* T2 = 9*X^4 (1) */ secp256k1_fe_sqr(&t2, &t1); /* T2 = 9*X^4 (1) */
secp256k1_fe_sqr(&t3, &t5); secp256k1_fe_sqr(&t3, &a->y);
secp256k1_fe_mul_int(&t3, 2); /* T3 = 2*Y^2 (2) */ secp256k1_fe_mul_int(&t3, 2); /* T3 = 2*Y^2 (2) */
secp256k1_fe_sqr(&t4, &t3); secp256k1_fe_sqr(&t4, &t3);
secp256k1_fe_mul_int(&t4, 2); /* T4 = 8*Y^4 (2) */ secp256k1_fe_mul_int(&t4, 2); /* T4 = 8*Y^4 (2) */
secp256k1_fe_mul(&t3, &a->x, &t3); /* T3 = 2*X*Y^2 (1) */ secp256k1_fe_mul(&t3, &t3, &a->x); /* T3 = 2*X*Y^2 (1) */
r->x = t3; r->x = t3;
secp256k1_fe_mul_int(&r->x, 4); /* X' = 8*X*Y^2 (4) */ secp256k1_fe_mul_int(&r->x, 4); /* X' = 8*X*Y^2 (4) */
secp256k1_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */ secp256k1_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */
@ -241,7 +237,6 @@ static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *
secp256k1_fe_mul(&r->y, &t1, &t3); /* Y' = 36*X^3*Y^2 - 27*X^6 (1) */ secp256k1_fe_mul(&r->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_negate(&t2, &t4, 2); /* T2 = -8*Y^4 (3) */
secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */ secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */
r->infinity = 0;
} }
static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b) { static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
@ -342,7 +337,7 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c
* *
* Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives: * Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives:
* U1 = X1*Z2^2, U2 = X2*Z1^2 * U1 = X1*Z2^2, U2 = X2*Z1^2
* S1 = X1*Z2^3, S2 = X2*Z2^3 * S1 = Y1*Z2^3, S2 = Y2*Z1^3
* Z = Z1*Z2 * Z = Z1*Z2
* T = U1+U2 * T = U1+U2
* M = S1+S2 * M = S1+S2
@ -414,40 +409,9 @@ static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *
*r = *a; *r = *a;
secp256k1_fe_mul(&r->x, &r->x, beta); secp256k1_fe_mul(&r->x, &r->x, beta);
} }
static void secp256k1_gej_split_exp_var(secp256k1_num_t *r1, secp256k1_num_t *r2, const secp256k1_num_t *a) {
const secp256k1_ge_consts_t *c = secp256k1_ge_consts;
secp256k1_num_t bnc1, bnc2, bnt1, bnt2, bnn2;
secp256k1_num_copy(&bnn2, &c->order);
secp256k1_num_shift(&bnn2, 1);
secp256k1_num_mul(&bnc1, a, &c->a1b2);
secp256k1_num_add(&bnc1, &bnc1, &bnn2);
secp256k1_num_div(&bnc1, &bnc1, &c->order);
secp256k1_num_mul(&bnc2, a, &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(r1, a, &bnt1);
secp256k1_num_mul(&bnt1, &bnc1, &c->b1);
secp256k1_num_mul(&bnt2, &bnc2, &c->a1b2);
secp256k1_num_sub(r2, &bnt1, &bnt2);
}
#endif #endif
static void secp256k1_ge_start(void) { static void secp256k1_ge_start(void) {
static const unsigned char secp256k1_ge_consts_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 secp256k1_ge_consts_g_x[] = { static const unsigned char secp256k1_ge_consts_g_x[] = {
0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC, 0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,
0x55,0xA0,0x62,0x95,0xCE,0x87,0x0B,0x07, 0x55,0xA0,0x62,0x95,0xCE,0x87,0x0B,0x07,
@ -462,47 +426,21 @@ static void secp256k1_ge_start(void) {
}; };
#ifdef USE_ENDOMORPHISM #ifdef USE_ENDOMORPHISM
/* properties of secp256k1's efficiently computable endomorphism */ /* properties of secp256k1's efficiently computable endomorphism */
static const unsigned char secp256k1_ge_consts_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 secp256k1_ge_consts_beta[] = { static const unsigned char secp256k1_ge_consts_beta[] = {
0x7a,0xe9,0x6a,0x2b,0x65,0x7c,0x07,0x10, 0x7a,0xe9,0x6a,0x2b,0x65,0x7c,0x07,0x10,
0x6e,0x64,0x47,0x9e,0xac,0x34,0x34,0xe9, 0x6e,0x64,0x47,0x9e,0xac,0x34,0x34,0xe9,
0x9c,0xf0,0x49,0x75,0x12,0xf5,0x89,0x95, 0x9c,0xf0,0x49,0x75,0x12,0xf5,0x89,0x95,
0xc1,0x39,0x6c,0x28,0x71,0x95,0x01,0xee 0xc1,0x39,0x6c,0x28,0x71,0x95,0x01,0xee
}; };
static const unsigned char secp256k1_ge_consts_a1b2[] = {
0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,
0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15
};
static const unsigned char secp256k1_ge_consts_b1[] = {
0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,
0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3
};
static const unsigned char secp256k1_ge_consts_a2[] = {
0x01,
0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,
0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8
};
#endif #endif
if (secp256k1_ge_consts == NULL) { if (secp256k1_ge_consts == NULL) {
secp256k1_ge_consts_t *ret = (secp256k1_ge_consts_t*)malloc(sizeof(secp256k1_ge_consts_t)); secp256k1_ge_consts_t *ret = (secp256k1_ge_consts_t*)malloc(sizeof(secp256k1_ge_consts_t));
secp256k1_num_set_bin(&ret->order, secp256k1_ge_consts_order, sizeof(secp256k1_ge_consts_order));
secp256k1_num_copy(&ret->half_order, &ret->order);
secp256k1_num_shift(&ret->half_order, 1);
#ifdef USE_ENDOMORPHISM #ifdef USE_ENDOMORPHISM
secp256k1_num_set_bin(&ret->lambda, secp256k1_ge_consts_lambda, sizeof(secp256k1_ge_consts_lambda)); VERIFY_CHECK(secp256k1_fe_set_b32(&ret->beta, secp256k1_ge_consts_beta));
secp256k1_num_set_bin(&ret->a1b2, secp256k1_ge_consts_a1b2, sizeof(secp256k1_ge_consts_a1b2));
secp256k1_num_set_bin(&ret->a2, secp256k1_ge_consts_a2, sizeof(secp256k1_ge_consts_a2));
secp256k1_num_set_bin(&ret->b1, secp256k1_ge_consts_b1, sizeof(secp256k1_ge_consts_b1));
secp256k1_fe_set_b32(&ret->beta, secp256k1_ge_consts_beta);
#endif #endif
secp256k1_fe_t g_x, g_y; secp256k1_fe_t g_x, g_y;
secp256k1_fe_set_b32(&g_x, secp256k1_ge_consts_g_x); VERIFY_CHECK(secp256k1_fe_set_b32(&g_x, secp256k1_ge_consts_g_x));
secp256k1_fe_set_b32(&g_y, secp256k1_ge_consts_g_y); VERIFY_CHECK(secp256k1_fe_set_b32(&g_y, secp256k1_ge_consts_g_y));
secp256k1_ge_set_xy(&ret->g, &g_x, &g_y); secp256k1_ge_set_xy(&ret->g, &g_x, &g_y);
secp256k1_ge_consts = ret; secp256k1_ge_consts = ret;
} }

42
src/num.h

@ -7,6 +7,8 @@
#ifndef _SECP256K1_NUM_ #ifndef _SECP256K1_NUM_
#define _SECP256K1_NUM_ #define _SECP256K1_NUM_
#ifndef USE_NUM_NONE
#if defined HAVE_CONFIG_H #if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h" #include "libsecp256k1-config.h"
#endif #endif
@ -17,9 +19,6 @@
#error "Please select num implementation" #error "Please select num implementation"
#endif #endif
/** Clear a number to prevent the leak of sensitive data. */
static void secp256k1_num_clear(secp256k1_num_t *r);
/** Copy a number. */ /** Copy a number. */
static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a); static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a);
@ -30,15 +29,9 @@ static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const sec
/** Set a number to the value of a binary big-endian string. */ /** Set a number to the value of a binary big-endian string. */
static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen); static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen);
/** Set a number equal to a (signed) integer. */
static void secp256k1_num_set_int(secp256k1_num_t *r, int a);
/** Compute a modular inverse. The input must be less than the modulus. */ /** Compute a modular inverse. The input must be less than the modulus. */
static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m); static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m);
/** Multiply two numbers modulo another. */
static void secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m);
/** Compare the absolute value of two numbers. */ /** Compare the absolute value of two numbers. */
static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b); static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b);
@ -54,47 +47,22 @@ static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, cons
/** Multiply two (signed) numbers. */ /** Multiply two (signed) numbers. */
static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
/** Divide two (signed) numbers. */
static void secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b);
/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1, /** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1,
even if r was negative. */ even if r was negative. */
static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m); static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m);
/** Calculate the number of bits in (the absolute value of) a number. */ /** Right-shift the passed number by bits bits. */
static int secp256k1_num_bits(const secp256k1_num_t *a); static void secp256k1_num_shift(secp256k1_num_t *r, int bits);
/** Right-shift the passed number by bits bits, and return those bits. */
static int secp256k1_num_shift(secp256k1_num_t *r, int bits);
/** Check whether a number is zero. */ /** Check whether a number is zero. */
static int secp256k1_num_is_zero(const secp256k1_num_t *a); static int secp256k1_num_is_zero(const secp256k1_num_t *a);
/** Check whether a number is odd. */
static int secp256k1_num_is_odd(const secp256k1_num_t *a);
/** Check whether a number is strictly negative. */ /** Check whether a number is strictly negative. */
static int secp256k1_num_is_neg(const secp256k1_num_t *a); static int secp256k1_num_is_neg(const secp256k1_num_t *a);
/** Check whether a particular bit is set in a number. */
static int secp256k1_num_get_bit(const secp256k1_num_t *a, int pos);
/** Increase a number by 1. */
static void secp256k1_num_inc(secp256k1_num_t *r);
/** Set a number equal to the value of a hex string (unsigned). */
static void secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen);
/** Convert (the absolute value of) a number to a hexadecimal string. */
static void secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a);
/** Split a number into a low and high part. */
static void secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits);
/** Change a number's sign. */ /** Change a number's sign. */
static void secp256k1_num_negate(secp256k1_num_t *r); static void secp256k1_num_negate(secp256k1_num_t *r);
/** Get a bunch of bits from a number. */ #endif
static int secp256k1_num_get_bits(const secp256k1_num_t *a, int offset, int count);
#endif #endif

176
src/num_gmp_impl.h

@ -22,35 +22,10 @@ static void secp256k1_num_sanity(const secp256k1_num_t *a) {
#define secp256k1_num_sanity(a) do { } while(0) #define secp256k1_num_sanity(a) do { } while(0)
#endif #endif
static void secp256k1_num_init(secp256k1_num_t *r) {
r->neg = 0;
r->limbs = 1;
r->data[0] = 0;
}
static void secp256k1_num_clear(secp256k1_num_t *r) {
memset(r, 0, sizeof(*r));
}
static void secp256k1_num_free(secp256k1_num_t *r) {
(void)r;
}
static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) { static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) {
*r = *a; *r = *a;
} }
static int secp256k1_num_bits(const secp256k1_num_t *a) {
int ret=(a->limbs-1)*GMP_NUMB_BITS;
mp_limb_t x=a->data[a->limbs-1];
while (x) {
x >>= 1;
ret++;
}
return ret;
}
static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) { static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
unsigned char tmp[65]; unsigned char tmp[65];
int len = 0; int len = 0;
@ -71,18 +46,16 @@ static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, un
VERIFY_CHECK(alen > 0); VERIFY_CHECK(alen > 0);
VERIFY_CHECK(alen <= 64); VERIFY_CHECK(alen <= 64);
int len = mpn_set_str(r->data, a, alen, 256); int len = mpn_set_str(r->data, a, alen, 256);
if (len == 0) {
r->data[0] = 0;
len = 1;
}
VERIFY_CHECK(len <= NUM_LIMBS*2); VERIFY_CHECK(len <= NUM_LIMBS*2);
r->limbs = len; r->limbs = len;
r->neg = 0; r->neg = 0;
while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--; while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--;
} }
static void secp256k1_num_set_int(secp256k1_num_t *r, int a) {
r->limbs = 1;
r->neg = (a < 0);
r->data[0] = (a < 0) ? -a : a;
}
static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) {
mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs); mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs);
r->limbs = a->limbs; r->limbs = a->limbs;
@ -161,10 +134,6 @@ static int secp256k1_num_is_zero(const secp256k1_num_t *a) {
return (a->limbs == 1 && a->data[0] == 0); return (a->limbs == 1 && a->data[0] == 0);
} }
static int secp256k1_num_is_odd(const secp256k1_num_t *a) {
return a->data[0] & 1;
}
static int secp256k1_num_is_neg(const secp256k1_num_t *a) { static int secp256k1_num_is_neg(const secp256k1_num_t *a) {
return (a->limbs > 1 || a->data[0] != 0) && a->neg; return (a->limbs > 1 || a->data[0] != 0) && a->neg;
} }
@ -237,140 +206,27 @@ static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, cons
memset(tmp, 0, sizeof(tmp)); memset(tmp, 0, sizeof(tmp));
} }
static void secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { static void secp256k1_num_shift(secp256k1_num_t *r, int bits) {
secp256k1_num_sanity(a); if (bits % GMP_NUMB_BITS) {
secp256k1_num_sanity(b); // Shift within limbs.
if (b->limbs > a->limbs) { mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS);
r->limbs = 1;
r->data[0] = 0;
r->neg = 0;
return;
} }
if (bits >= GMP_NUMB_BITS) {
mp_limb_t quo[2*NUM_LIMBS+1]; // Shift full limbs.
mp_limb_t rem[2*NUM_LIMBS+1]; for (int i = 0; i < r->limbs; i++) {
mpn_tdiv_qr(quo, rem, 0, a->data, a->limbs, b->data, b->limbs); int index = i + (bits / GMP_NUMB_BITS);
mpn_copyi(r->data, quo, a->limbs - b->limbs + 1); if (index < r->limbs && index < 2*NUM_LIMBS) {
r->limbs = a->limbs - b->limbs + 1; r->data[i] = r->data[index];
while (r->limbs > 1 && r->data[r->limbs - 1]==0) r->limbs--; } else {
r->neg = a->neg ^ b->neg; r->data[i] = 0;
}
static void secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m) {
secp256k1_num_mul(r, a, b);
secp256k1_num_mod(r, m);
}
static int secp256k1_num_shift(secp256k1_num_t *r, int bits) {
VERIFY_CHECK(bits <= GMP_NUMB_BITS);
mp_limb_t ret = mpn_rshift(r->data, r->data, r->limbs, bits);
if (r->limbs>1 && r->data[r->limbs-1]==0) r->limbs--;
ret >>= (GMP_NUMB_BITS - bits);
return ret;
}
static int secp256k1_num_get_bit(const secp256k1_num_t *a, int pos) {
return (a->limbs*GMP_NUMB_BITS > pos) && ((a->data[pos/GMP_NUMB_BITS] >> (pos % GMP_NUMB_BITS)) & 1);
} }
static void secp256k1_num_inc(secp256k1_num_t *r) {
mp_limb_t ret = mpn_add_1(r->data, r->data, r->limbs, (mp_limb_t)1);
if (ret) {
VERIFY_CHECK(r->limbs < 2*NUM_LIMBS);
r->data[r->limbs++] = ret;
} }
} }
static void secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen) {
static const unsigned char 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
};
unsigned char num[257] = {};
for (int i=0; i<alen; i++) {
num[i] = cvt[(unsigned char)a[i]];
}
r->limbs = mpn_set_str(r->data, num, alen, 16);
r->neg = 0;
while (r->limbs>1 && r->data[r->limbs-1]==0) r->limbs--; while (r->limbs>1 && r->data[r->limbs-1]==0) r->limbs--;
} }
static void secp256k1_num_get_hex(char *r, int rlen, const secp256k1_num_t *a) {
static const unsigned char cvt[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
unsigned char *tmp = malloc(257);
mp_size_t len = mpn_get_str(tmp, 16, (mp_limb_t*)a->data, a->limbs);
VERIFY_CHECK(len <= rlen);
for (int i=0; i<len; i++) {
VERIFY_CHECK(rlen-len+i >= 0);
VERIFY_CHECK(rlen-len+i < rlen);
VERIFY_CHECK(tmp[i] < 16);
r[rlen-len+i] = cvt[tmp[i]];
}
for (int i=0; i<rlen-len; i++) {
VERIFY_CHECK(i >= 0);
VERIFY_CHECK(i < rlen);
r[i] = cvt[0];
}
free(tmp);
}
static void secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits) {
VERIFY_CHECK(bits > 0);
rh->neg = a->neg;
if (bits >= a->limbs * GMP_NUMB_BITS) {
*rl = *a;
rh->limbs = 1;
rh->data[0] = 0;
return;
}
rl->limbs = 0;
rl->neg = a->neg;
int left = bits;
while (left >= GMP_NUMB_BITS) {
rl->data[rl->limbs] = a->data[rl->limbs];
rl->limbs++;
left -= GMP_NUMB_BITS;
}
if (left == 0) {
mpn_copyi(rh->data, a->data + rl->limbs, a->limbs - rl->limbs);
rh->limbs = a->limbs - rl->limbs;
} else {
mpn_rshift(rh->data, a->data + rl->limbs, a->limbs - rl->limbs, left);
rh->limbs = a->limbs - rl->limbs;
while (rh->limbs>1 && rh->data[rh->limbs-1]==0) rh->limbs--;
}
if (left > 0) {
rl->data[rl->limbs] = a->data[rl->limbs] & ((((mp_limb_t)1) << left) - 1);
rl->limbs++;
}
while (rl->limbs>1 && rl->data[rl->limbs-1]==0) rl->limbs--;
}
static void secp256k1_num_negate(secp256k1_num_t *r) { static void secp256k1_num_negate(secp256k1_num_t *r) {
r->neg ^= 1; r->neg ^= 1;
} }
static int secp256k1_num_get_bits(const secp256k1_num_t *a, int offset, int count) {
int ret = 0;
for (int i = 0; i < count; i++) {
ret |= ((a->data[(offset + i) / GMP_NUMB_BITS] >> ((offset + i) % GMP_NUMB_BITS)) & 1) << i;
}
return ret;
}
#endif #endif

2
src/num_impl.h

@ -15,6 +15,8 @@
#if defined(USE_NUM_GMP) #if defined(USE_NUM_GMP)
#include "num_gmp_impl.h" #include "num_gmp_impl.h"
#elif defined(USE_NUM_NONE)
/* Nothing. */
#else #else
#error "Please select num implementation" #error "Please select num implementation"
#endif #endif

41
src/scalar.h

@ -21,20 +21,32 @@
#error "Please select scalar implementation" #error "Please select scalar implementation"
#endif #endif
static void secp256k1_scalar_start(void);
static void secp256k1_scalar_stop(void);
/** Clear a scalar to prevent the leak of sensitive data. */ /** Clear a scalar to prevent the leak of sensitive data. */
static void secp256k1_scalar_clear(secp256k1_scalar_t *r); static void secp256k1_scalar_clear(secp256k1_scalar_t *r);
/** Access bits from a scalar. */ /** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */
static int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, int offset, int count); static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count);
/** Access bits from a scalar. Not constant time. */
static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count);
/** Set a scalar from a big endian byte array. */ /** Set a scalar from a big endian byte array. */
static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *bin, int *overflow); static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *bin, int *overflow);
/** Set a scalar to an unsigned integer. */
static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v);
/** Convert a scalar to a byte array. */ /** Convert a scalar to a byte array. */
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a); static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a);
/** Add two scalars together (modulo the group order). */ /** Add two scalars together (modulo the group order). Returns whether it overflowed. */
static void secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b);
/** Add a power of two to a scalar. The result is not allowed to overflow. */
static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit);
/** Multiply two scalars (modulo the group order). */ /** Multiply two scalars (modulo the group order). */
static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b);
@ -45,6 +57,9 @@ static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t
/** Compute the inverse of a scalar (modulo the group order). */ /** Compute the inverse of a scalar (modulo the group order). */
static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *a);
/** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */
static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a);
/** Compute the complement of a scalar (modulo the group order). */ /** Compute the complement of a scalar (modulo the group order). */
static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a);
@ -57,7 +72,25 @@ static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a);
/** Check whether a scalar is higher than the group order divided by 2. */ /** Check whether a scalar is higher than the group order divided by 2. */
static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a); static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a);
#ifndef USE_NUM_NONE
/** Convert a scalar to a number. */ /** Convert a scalar to a number. */
static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a); static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a);
/** Get the order of the group as a number. */
static void secp256k1_scalar_order_get_num(secp256k1_num_t *r);
#endif
/** Compare two scalars. */
static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b);
static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a);
#ifdef USE_ENDOMORPHISM
/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */
static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a);
#endif
/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */
static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift);
#endif #endif

102
src/scalar_4x64_impl.h

@ -33,9 +33,27 @@ SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) {
r->d[3] = 0; r->d[3] = 0;
} }
SECP256K1_INLINE static int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, int offset, int count) { SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) {
VERIFY_CHECK((offset + count - 1) / 64 == offset / 64); r->d[0] = v;
return (a->d[offset / 64] >> (offset % 64)) & ((((uint64_t)1) << count) - 1); r->d[1] = 0;
r->d[2] = 0;
r->d[3] = 0;
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) {
VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6);
return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1);
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) {
VERIFY_CHECK(count < 32);
VERIFY_CHECK(offset + count <= 256);
if ((offset + count - 1) >> 6 == offset >> 6) {
return secp256k1_scalar_get_bits(a, offset, count);
} else {
VERIFY_CHECK((offset >> 6) + 1 < 4);
return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & ((((uint64_t)1) << count) - 1);
}
} }
SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) { SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) {
@ -63,7 +81,7 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsig
return overflow; return overflow;
} }
static void secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
uint128_t t = (uint128_t)a->d[0] + b->d[0]; uint128_t t = (uint128_t)a->d[0] + b->d[0];
r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)a->d[1] + b->d[1]; t += (uint128_t)a->d[1] + b->d[1];
@ -72,7 +90,26 @@ static void secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t
r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)a->d[3] + b->d[3]; t += (uint128_t)a->d[3] + b->d[3];
r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
secp256k1_scalar_reduce(r, t + secp256k1_scalar_check_overflow(r)); int overflow = t + secp256k1_scalar_check_overflow(r);
VERIFY_CHECK(overflow == 0 || overflow == 1);
secp256k1_scalar_reduce(r, overflow);
return overflow;
}
static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) {
VERIFY_CHECK(bit < 256);
uint128_t t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F));
r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)r->d[2] + (((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F));
r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)r->d[3] + (((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F));
r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL;
#ifdef VERIFY
VERIFY_CHECK((t >> 64) == 0);
VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
#endif
} }
static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) { static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) {
@ -280,13 +317,11 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l
secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r));
} }
static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
/* 160 bit accumulator. */ /* 160 bit accumulator. */
uint64_t c0 = 0, c1 = 0; uint64_t c0 = 0, c1 = 0;
uint32_t c2 = 0; uint32_t c2 = 0;
uint64_t l[8];
/* l[0..7] = a[0..3] * b[0..3]. */ /* l[0..7] = a[0..3] * b[0..3]. */
muladd_fast(a->d[0], b->d[0]); muladd_fast(a->d[0], b->d[0]);
extract_fast(l[0]); extract_fast(l[0]);
@ -313,17 +348,13 @@ static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t
extract_fast(l[6]); extract_fast(l[6]);
VERIFY_CHECK(c1 <= 0); VERIFY_CHECK(c1 <= 0);
l[7] = c0; l[7] = c0;
secp256k1_scalar_reduce_512(r, l);
} }
static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a) {
/* 160 bit accumulator. */ /* 160 bit accumulator. */
uint64_t c0 = 0, c1 = 0; uint64_t c0 = 0, c1 = 0;
uint32_t c2 = 0; uint32_t c2 = 0;
uint64_t l[8];
/* l[0..7] = a[0..3] * b[0..3]. */ /* l[0..7] = a[0..3] * b[0..3]. */
muladd_fast(a->d[0], a->d[0]); muladd_fast(a->d[0], a->d[0]);
extract_fast(l[0]); extract_fast(l[0]);
@ -344,8 +375,6 @@ static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t
extract_fast(l[6]); extract_fast(l[6]);
VERIFY_CHECK(c1 == 0); VERIFY_CHECK(c1 == 0);
l[7] = c0; l[7] = c0;
secp256k1_scalar_reduce_512(r, l);
} }
#undef sumadd #undef sumadd
@ -356,4 +385,47 @@ static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t
#undef extract #undef extract
#undef extract_fast #undef extract_fast
static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
uint64_t l[8];
secp256k1_scalar_mul_512(l, a, b);
secp256k1_scalar_reduce_512(r, l);
}
static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) {
uint64_t l[8];
secp256k1_scalar_sqr_512(l, a);
secp256k1_scalar_reduce_512(r, l);
}
static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) {
r1->d[0] = a->d[0];
r1->d[1] = a->d[1];
r1->d[2] = 0;
r1->d[3] = 0;
r2->d[0] = a->d[2];
r2->d[1] = a->d[3];
r2->d[2] = 0;
r2->d[3] = 0;
}
SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0;
}
SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) {
VERIFY_CHECK(shift >= 256);
uint64_t l[8];
secp256k1_scalar_mul_512(l, a, b);
unsigned int shiftlimbs = shift >> 6;
unsigned int shiftlow = shift & 0x3F;
unsigned int shifthigh = 64 - shiftlow;
r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0;
if ((l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1) {
secp256k1_scalar_add_bit(r, 0);
}
}
#endif #endif

126
src/scalar_8x32_impl.h

@ -45,9 +45,31 @@ SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) {
r->d[7] = 0; r->d[7] = 0;
} }
SECP256K1_INLINE static int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, int offset, int count) { SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) {
VERIFY_CHECK((offset + count - 1) / 32 == offset / 32); r->d[0] = v;
return (a->d[offset / 32] >> (offset % 32)) & ((1 << count) - 1); r->d[1] = 0;
r->d[2] = 0;
r->d[3] = 0;
r->d[4] = 0;
r->d[5] = 0;
r->d[6] = 0;
r->d[7] = 0;
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) {
VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5);
return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1);
}
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) {
VERIFY_CHECK(count < 32);
VERIFY_CHECK(offset + count <= 256);
if ((offset + count - 1) >> 5 == offset >> 5) {
return secp256k1_scalar_get_bits(a, offset, count);
} else {
VERIFY_CHECK((offset >> 5) + 1 < 8);
return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & ((((uint32_t)1) << count) - 1);
}
} }
SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) { SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) {
@ -89,7 +111,7 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint3
return overflow; return overflow;
} }
static void secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
uint64_t t = (uint64_t)a->d[0] + b->d[0]; uint64_t t = (uint64_t)a->d[0] + b->d[0];
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[1] + b->d[1]; t += (uint64_t)a->d[1] + b->d[1];
@ -106,7 +128,34 @@ static void secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t
r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; r->d[6] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)a->d[7] + b->d[7]; t += (uint64_t)a->d[7] + b->d[7];
r->d[7] = t & 0xFFFFFFFFULL; t >>= 32; r->d[7] = t & 0xFFFFFFFFULL; t >>= 32;
secp256k1_scalar_reduce(r, t + secp256k1_scalar_check_overflow(r)); int overflow = t + secp256k1_scalar_check_overflow(r);
VERIFY_CHECK(overflow == 0 || overflow == 1);
secp256k1_scalar_reduce(r, overflow);
return overflow;
}
static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) {
VERIFY_CHECK(bit < 256);
uint64_t t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F));
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F));
r->d[1] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[2] + (((uint32_t)((bit >> 5) == 2)) << (bit & 0x1F));
r->d[2] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[3] + (((uint32_t)((bit >> 5) == 3)) << (bit & 0x1F));
r->d[3] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[4] + (((uint32_t)((bit >> 5) == 4)) << (bit & 0x1F));
r->d[4] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[5] + (((uint32_t)((bit >> 5) == 5)) << (bit & 0x1F));
r->d[5] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[6] + (((uint32_t)((bit >> 5) == 6)) << (bit & 0x1F));
r->d[6] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F));
r->d[7] = t & 0xFFFFFFFFULL;
#ifdef VERIFY
VERIFY_CHECK((t >> 32) == 0);
VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
#endif
} }
static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) { static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) {
@ -405,12 +454,10 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l
secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r));
} }
static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { static void secp256k1_scalar_mul_512(uint32_t l[16], const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
/* 96 bit accumulator. */ /* 96 bit accumulator. */
uint32_t c0 = 0, c1 = 0, c2 = 0; uint32_t c0 = 0, c1 = 0, c2 = 0;
uint32_t l[16];
/* l[0..15] = a[0..7] * b[0..7]. */ /* l[0..15] = a[0..7] * b[0..7]. */
muladd_fast(a->d[0], b->d[0]); muladd_fast(a->d[0], b->d[0]);
extract_fast(l[0]); extract_fast(l[0]);
@ -493,16 +540,12 @@ static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t
extract_fast(l[14]); extract_fast(l[14]);
VERIFY_CHECK(c1 == 0); VERIFY_CHECK(c1 == 0);
l[15] = c0; l[15] = c0;
secp256k1_scalar_reduce_512(r, l);
} }
static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { static void secp256k1_scalar_sqr_512(uint32_t l[16], const secp256k1_scalar_t *a) {
/* 96 bit accumulator. */ /* 96 bit accumulator. */
uint32_t c0 = 0, c1 = 0, c2 = 0; uint32_t c0 = 0, c1 = 0, c2 = 0;
uint32_t l[16];
/* l[0..15] = a[0..7]^2. */ /* l[0..15] = a[0..7]^2. */
muladd_fast(a->d[0], a->d[0]); muladd_fast(a->d[0], a->d[0]);
extract_fast(l[0]); extract_fast(l[0]);
@ -557,8 +600,6 @@ static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t
extract_fast(l[14]); extract_fast(l[14]);
VERIFY_CHECK(c1 == 0); VERIFY_CHECK(c1 == 0);
l[15] = c0; l[15] = c0;
secp256k1_scalar_reduce_512(r, l);
} }
#undef sumadd #undef sumadd
@ -569,4 +610,59 @@ static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t
#undef extract #undef extract
#undef extract_fast #undef extract_fast
static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
uint32_t l[16];
secp256k1_scalar_mul_512(l, a, b);
secp256k1_scalar_reduce_512(r, l);
}
static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) {
uint32_t l[16];
secp256k1_scalar_sqr_512(l, a);
secp256k1_scalar_reduce_512(r, l);
}
static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) {
r1->d[0] = a->d[0];
r1->d[1] = a->d[1];
r1->d[2] = a->d[2];
r1->d[3] = a->d[3];
r1->d[4] = 0;
r1->d[5] = 0;
r1->d[6] = 0;
r1->d[7] = 0;
r2->d[0] = a->d[4];
r2->d[1] = a->d[5];
r2->d[2] = a->d[6];
r2->d[3] = a->d[7];
r2->d[4] = 0;
r2->d[5] = 0;
r2->d[6] = 0;
r2->d[7] = 0;
}
SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) {
return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0;
}
SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) {
VERIFY_CHECK(shift >= 256);
uint32_t l[16];
secp256k1_scalar_mul_512(l, a, b);
unsigned int shiftlimbs = shift >> 5;
unsigned int shiftlow = shift & 0x1F;
unsigned int shifthigh = 32 - shiftlow;
r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 480 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[1] = shift < 480 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[2] = shift < 448 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 416 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[3] = shift < 416 ? (l[3 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[4 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[4] = shift < 384 ? (l[4 + shiftlimbs] >> shiftlow | (shift < 352 && shiftlow ? (l[5 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0;
r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0;
if ((l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1) {
secp256k1_scalar_add_bit(r, 0);
}
}
#endif #endif

152
src/scalar_impl.h

@ -9,6 +9,7 @@
#include <string.h> #include <string.h>
#include "group.h"
#include "scalar.h" #include "scalar.h"
#if defined HAVE_CONFIG_H #if defined HAVE_CONFIG_H
@ -23,12 +24,132 @@
#error "Please select scalar implementation" #error "Please select scalar implementation"
#endif #endif
typedef struct {
#ifndef USE_NUM_NONE
secp256k1_num_t order;
#endif
#ifdef USE_ENDOMORPHISM
secp256k1_scalar_t minus_lambda, minus_b1, minus_b2, g1, g2;
#endif
} secp256k1_scalar_consts_t;
static const secp256k1_scalar_consts_t *secp256k1_scalar_consts = NULL;
static void secp256k1_scalar_start(void) {
if (secp256k1_scalar_consts != NULL)
return;
/* Allocate. */
secp256k1_scalar_consts_t *ret = (secp256k1_scalar_consts_t*)malloc(sizeof(secp256k1_scalar_consts_t));
#ifndef USE_NUM_NONE
static const unsigned char secp256k1_scalar_consts_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
};
secp256k1_num_set_bin(&ret->order, secp256k1_scalar_consts_order, sizeof(secp256k1_scalar_consts_order));
#endif
#ifdef USE_ENDOMORPHISM
/**
* Lambda is a scalar which has the property for secp256k1 that point multiplication by
* it is efficiently computable (see secp256k1_gej_mul_lambda). */
static const unsigned char secp256k1_scalar_consts_lambda[32] = {
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
};
/**
* "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm
* (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1
* and k2 have a small size.
* It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are:
*
* - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}
* - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3}
* - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8}
* - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}
*
* The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives
* k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and
* compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2.
*
* g1, g2 are precomputed constants used to replace division with a rounded multiplication
* when decomposing the scalar for an endomorphism-based point multiplication.
*
* The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve
* Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5.
*
* The derivation is described in the paper "Efficient Software Implementation of Public-Key
* Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez),
* Section 4.3 (here we use a somewhat higher-precision estimate):
* d = a1*b2 - b1*a2
* g1 = round((2^272)*b2/d)
* g2 = round((2^272)*b1/d)
*
* (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found
* as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda').
*/
static const unsigned char secp256k1_scalar_consts_minus_b1[32] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,
0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3
};
static const unsigned char secp256k1_scalar_consts_b2[32] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,
0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15
};
static const unsigned char secp256k1_scalar_consts_g1[32] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x86,
0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,
0x90,0xe4,0x92,0x84,0xeb,0x15,0x3d,0xab
};
static const unsigned char secp256k1_scalar_consts_g2[32] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0x43,
0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,
0x7f,0xa9,0x0a,0xbf,0xe4,0xc4,0x22,0x12
};
secp256k1_scalar_set_b32(&ret->minus_lambda, secp256k1_scalar_consts_lambda, NULL);
secp256k1_scalar_negate(&ret->minus_lambda, &ret->minus_lambda);
secp256k1_scalar_set_b32(&ret->minus_b1, secp256k1_scalar_consts_minus_b1, NULL);
secp256k1_scalar_set_b32(&ret->minus_b2, secp256k1_scalar_consts_b2, NULL);
secp256k1_scalar_negate(&ret->minus_b2, &ret->minus_b2);
secp256k1_scalar_set_b32(&ret->g1, secp256k1_scalar_consts_g1, NULL);
secp256k1_scalar_set_b32(&ret->g2, secp256k1_scalar_consts_g2, NULL);
#endif
/* Set the global pointer. */
secp256k1_scalar_consts = ret;
}
static void secp256k1_scalar_stop(void) {
if (secp256k1_scalar_consts == NULL)
return;
secp256k1_scalar_consts_t *c = (secp256k1_scalar_consts_t*)secp256k1_scalar_consts;
secp256k1_scalar_consts = NULL;
free(c);
}
#ifndef USE_NUM_NONE
static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a) { static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a) {
unsigned char c[32]; unsigned char c[32];
secp256k1_scalar_get_b32(c, a); secp256k1_scalar_get_b32(c, a);
secp256k1_num_set_bin(r, c, 32); secp256k1_num_set_bin(r, c, 32);
} }
static void secp256k1_scalar_order_get_num(secp256k1_num_t *r) {
*r = secp256k1_scalar_consts->order;
}
#endif
static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) { static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) {
/* First compute x ^ (2^N - 1) for some values of N. */ /* First compute x ^ (2^N - 1) for some values of N. */
@ -181,4 +302,35 @@ static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scal
secp256k1_scalar_mul(r, t, &x6); /* 111111 */ secp256k1_scalar_mul(r, t, &x6); /* 111111 */
} }
static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) {
#if defined(USE_SCALAR_INV_BUILTIN)
secp256k1_scalar_inverse(r, x);
#elif defined(USE_SCALAR_INV_NUM)
unsigned char b[32];
secp256k1_scalar_get_b32(b, x);
secp256k1_num_t n;
secp256k1_num_set_bin(&n, b, 32);
secp256k1_num_mod_inverse(&n, &n, &secp256k1_scalar_consts->order);
secp256k1_num_get_bin(b, 32, &n);
secp256k1_scalar_set_b32(r, b, NULL);
#else
#error "Please select scalar inverse implementation"
#endif
}
#ifdef USE_ENDOMORPHISM
static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) {
VERIFY_CHECK(r1 != a);
VERIFY_CHECK(r2 != a);
secp256k1_scalar_t c1, c2;
secp256k1_scalar_mul_shift_var(&c1, a, &secp256k1_scalar_consts->g1, 272);
secp256k1_scalar_mul_shift_var(&c2, a, &secp256k1_scalar_consts->g2, 272);
secp256k1_scalar_mul(&c1, &c1, &secp256k1_scalar_consts->minus_b1);
secp256k1_scalar_mul(&c2, &c2, &secp256k1_scalar_consts->minus_b2);
secp256k1_scalar_add(r2, &c1, &c2);
secp256k1_scalar_mul(r1, r2, &secp256k1_scalar_consts->minus_lambda);
secp256k1_scalar_add(r1, r1, a);
}
#endif
#endif #endif

47
src/secp256k1.c

@ -21,6 +21,8 @@
void secp256k1_start(unsigned int flags) { void secp256k1_start(unsigned int flags) {
secp256k1_fe_start(); secp256k1_fe_start();
secp256k1_ge_start(); secp256k1_ge_start();
secp256k1_scalar_start();
secp256k1_ecdsa_start();
if (flags & SECP256K1_START_SIGN) { if (flags & SECP256K1_START_SIGN) {
secp256k1_ecmult_gen_start(); secp256k1_ecmult_gen_start();
} }
@ -32,6 +34,8 @@ void secp256k1_start(unsigned int flags) {
void secp256k1_stop(void) { void secp256k1_stop(void) {
secp256k1_ecmult_stop(); secp256k1_ecmult_stop();
secp256k1_ecmult_gen_stop(); secp256k1_ecmult_gen_stop();
secp256k1_ecdsa_stop();
secp256k1_scalar_stop();
secp256k1_ge_stop(); secp256k1_ge_stop();
secp256k1_fe_stop(); secp256k1_fe_stop();
} }
@ -43,11 +47,13 @@ int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen, const unsigned
DEBUG_CHECK(sig != NULL); DEBUG_CHECK(sig != NULL);
DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(pubkey != NULL);
unsigned char msg32[32] = {0};
memcpy(msg32 + 32 - msglen, msg, msglen);
int ret = -3; int ret = -3;
secp256k1_num_t m; secp256k1_scalar_t m;
secp256k1_ecdsa_sig_t s; secp256k1_ecdsa_sig_t s;
secp256k1_ge_t q; secp256k1_ge_t q;
secp256k1_num_set_bin(&m, msg, msglen); secp256k1_scalar_set_b32(&m, msg32, NULL);
if (!secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) { if (!secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) {
ret = -1; ret = -1;
@ -123,8 +129,8 @@ int secp256k1_ecdsa_sign_compact(const unsigned char *message, int messagelen, u
ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, recid); ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, recid);
} }
if (ret) { if (ret) {
secp256k1_num_get_bin(sig64, 32, &sig.r); secp256k1_scalar_get_b32(sig64, &sig.r);
secp256k1_num_get_bin(sig64 + 32, 32, &sig.s); secp256k1_scalar_get_b32(sig64 + 32, &sig.s);
} }
secp256k1_scalar_clear(&msg); secp256k1_scalar_clear(&msg);
secp256k1_scalar_clear(&non); secp256k1_scalar_clear(&non);
@ -142,11 +148,20 @@ int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen, const
DEBUG_CHECK(recid >= 0 && recid <= 3); DEBUG_CHECK(recid >= 0 && recid <= 3);
int ret = 0; int ret = 0;
secp256k1_num_t m; unsigned char msg32[32] = {0};
memcpy(msg32 + 32 - msglen, msg, msglen);
secp256k1_scalar_t m;
secp256k1_ecdsa_sig_t sig; secp256k1_ecdsa_sig_t sig;
secp256k1_num_set_bin(&sig.r, sig64, 32); int overflow = 0;
secp256k1_num_set_bin(&sig.s, sig64 + 32, 32); secp256k1_scalar_set_b32(&sig.r, sig64, &overflow);
secp256k1_num_set_bin(&m, msg, msglen); if (overflow) {
return 0;
}
secp256k1_scalar_set_b32(&sig.s, sig64 + 32, &overflow);
if (overflow) {
return 0;
}
secp256k1_scalar_set_b32(&m, msg32, NULL);
secp256k1_ge_t q; secp256k1_ge_t q;
if (secp256k1_ecdsa_sig_recover(&sig, &q, &m, recid)) { if (secp256k1_ecdsa_sig_recover(&sig, &q, &m, recid)) {
@ -224,8 +239,12 @@ int secp256k1_ec_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const un
DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(pubkey != NULL);
DEBUG_CHECK(tweak != NULL); DEBUG_CHECK(tweak != NULL);
secp256k1_num_t term; secp256k1_scalar_t term;
secp256k1_num_set_bin(&term, tweak, 32); int overflow = 0;
secp256k1_scalar_set_b32(&term, tweak, &overflow);
if (overflow) {
return 0;
}
secp256k1_ge_t p; secp256k1_ge_t p;
int ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); int ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
if (ret) { if (ret) {
@ -264,8 +283,12 @@ int secp256k1_ec_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const un
DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(pubkey != NULL);
DEBUG_CHECK(tweak != NULL); DEBUG_CHECK(tweak != NULL);
secp256k1_num_t factor; secp256k1_scalar_t factor;
secp256k1_num_set_bin(&factor, tweak, 32); int overflow = 0;
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
if (overflow) {
return 0;
}
secp256k1_ge_t p; secp256k1_ge_t p;
int ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); int ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
if (ret) { if (ret) {

547
src/tests.c

@ -23,23 +23,13 @@
static int count = 64; static int count = 64;
/***** NUM TESTS *****/
void random_num_negate(secp256k1_num_t *num) {
if (secp256k1_rand32() & 1)
secp256k1_num_negate(num);
}
void random_field_element_test(secp256k1_fe_t *fe) { void random_field_element_test(secp256k1_fe_t *fe) {
do { do {
unsigned char b32[32]; unsigned char b32[32];
secp256k1_rand256_test(b32); secp256k1_rand256_test(b32);
secp256k1_num_t num; if (secp256k1_fe_set_b32(fe, b32)) {
secp256k1_num_set_bin(&num, b32, 32);
if (secp256k1_num_cmp(&num, &secp256k1_fe_consts->p) >= 0)
continue;
secp256k1_fe_set_b32(fe, b32);
break; break;
}
} while(1); } while(1);
} }
@ -75,19 +65,6 @@ void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge
gej->infinity = ge->infinity; gej->infinity = ge->infinity;
} }
void random_num_order_test(secp256k1_num_t *num) {
do {
unsigned char b32[32];
secp256k1_rand256_test(b32);
secp256k1_num_set_bin(num, b32, 32);
if (secp256k1_num_is_zero(num))
continue;
if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0)
continue;
break;
} while(1);
}
void random_scalar_order_test(secp256k1_scalar_t *num) { void random_scalar_order_test(secp256k1_scalar_t *num) {
do { do {
unsigned char b32[32]; unsigned char b32[32];
@ -100,82 +77,36 @@ void random_scalar_order_test(secp256k1_scalar_t *num) {
} while(1); } while(1);
} }
void random_num_order(secp256k1_num_t *num) { void random_scalar_order(secp256k1_scalar_t *num) {
do { do {
unsigned char b32[32]; unsigned char b32[32];
secp256k1_rand256(b32); secp256k1_rand256(b32);
secp256k1_num_set_bin(num, b32, 32); int overflow = 0;
if (secp256k1_num_is_zero(num)) secp256k1_scalar_set_b32(num, b32, &overflow);
continue; if (overflow || secp256k1_scalar_is_zero(num))
if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0)
continue; continue;
break; break;
} while(1); } while(1);
} }
void test_num_copy_inc_cmp(void) { /***** NUM TESTS *****/
secp256k1_num_t n1,n2;
random_num_order(&n1);
secp256k1_num_copy(&n2, &n1);
CHECK(secp256k1_num_eq(&n1, &n2));
CHECK(secp256k1_num_eq(&n2, &n1));
secp256k1_num_inc(&n2);
CHECK(!secp256k1_num_eq(&n1, &n2));
CHECK(!secp256k1_num_eq(&n2, &n1));
}
void test_num_get_set_hex(void) { #ifndef USE_NUM_NONE
secp256k1_num_t n1,n2; void random_num_negate(secp256k1_num_t *num) {
random_num_order_test(&n1); if (secp256k1_rand32() & 1)
char c[64]; secp256k1_num_negate(num);
secp256k1_num_get_hex(c, 64, &n1);
secp256k1_num_set_hex(&n2, c, 64);
CHECK(secp256k1_num_eq(&n1, &n2));
for (int i=0; i<64; i++) {
/* check whether the lower 4 bits correspond to the last hex character */
int low1 = secp256k1_num_shift(&n1, 4);
int lowh = c[63];
int low2 = ((lowh>>6)*9+(lowh-'0'))&15;
CHECK(low1 == low2);
/* shift bits off the hex representation, and compare */
memmove(c+1, c, 63);
c[0] = '0';
secp256k1_num_set_hex(&n2, c, 64);
CHECK(secp256k1_num_eq(&n1, &n2));
}
} }
void test_num_get_set_bin(void) { void random_num_order_test(secp256k1_num_t *num) {
secp256k1_num_t n1,n2; secp256k1_scalar_t sc;
random_num_order_test(&n1); random_scalar_order_test(&sc);
unsigned char c[32]; secp256k1_scalar_get_num(num, &sc);
secp256k1_num_get_bin(c, 32, &n1);
secp256k1_num_set_bin(&n2, c, 32);
CHECK(secp256k1_num_eq(&n1, &n2));
for (int i=0; i<32; i++) {
/* check whether the lower 8 bits correspond to the last byte */
int low1 = secp256k1_num_shift(&n1, 8);
int low2 = c[31];
CHECK(low1 == low2);
/* shift bits off the byte representation, and compare */
memmove(c+1, c, 31);
c[0] = 0;
secp256k1_num_set_bin(&n2, c, 32);
CHECK(secp256k1_num_eq(&n1, &n2));
}
} }
void run_num_int(void) { void random_num_order(secp256k1_num_t *num) {
secp256k1_num_t n1; secp256k1_scalar_t sc;
for (int i=-255; i<256; i++) { random_scalar_order(&sc);
unsigned char c1[3] = {}; secp256k1_scalar_get_num(num, &sc);
c1[2] = abs(i);
unsigned char c2[3] = {0x11,0x22,0x33};
secp256k1_num_set_int(&n1, i);
secp256k1_num_get_bin(c2, 3, &n1);
CHECK(memcmp(c1, c2, 3) == 0);
}
} }
void test_num_negate(void) { void test_num_negate(void) {
@ -229,82 +160,84 @@ void test_num_add_sub(void) {
void run_num_smalltests(void) { void run_num_smalltests(void) {
for (int i=0; i<100*count; i++) { for (int i=0; i<100*count; i++) {
test_num_copy_inc_cmp();
test_num_get_set_hex();
test_num_get_set_bin();
test_num_negate(); test_num_negate();
test_num_add_sub(); test_num_add_sub();
} }
run_num_int();
} }
#endif
/***** SCALAR TESTS *****/ /***** SCALAR TESTS *****/
int secp256k1_scalar_eq(const secp256k1_scalar_t *s1, const secp256k1_scalar_t *s2) {
secp256k1_scalar_t t;
secp256k1_scalar_negate(&t, s2);
secp256k1_scalar_add(&t, &t, s1);
int ret = secp256k1_scalar_is_zero(&t);
return ret;
}
void scalar_test(void) { void scalar_test(void) {
unsigned char c[32]; unsigned char c[32];
/* Set 's' to a random scalar, with value 'snum'. */ /* Set 's' to a random scalar, with value 'snum'. */
secp256k1_rand256_test(c);
secp256k1_scalar_t s; secp256k1_scalar_t s;
secp256k1_scalar_set_b32(&s, c, NULL); random_scalar_order_test(&s);
secp256k1_num_t snum;
secp256k1_num_set_bin(&snum, c, 32);
secp256k1_num_mod(&snum, &secp256k1_ge_consts->order);
/* Set 's1' to a random scalar, with value 's1num'. */ /* Set 's1' to a random scalar, with value 's1num'. */
secp256k1_rand256_test(c);
secp256k1_scalar_t s1; secp256k1_scalar_t s1;
secp256k1_scalar_set_b32(&s1, c, NULL); random_scalar_order_test(&s1);
secp256k1_num_t s1num;
secp256k1_num_set_bin(&s1num, c, 32);
secp256k1_num_mod(&s1num, &secp256k1_ge_consts->order);
/* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */ /* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */
secp256k1_rand256_test(c);
secp256k1_scalar_t s2; secp256k1_scalar_t s2;
int overflow = 0; random_scalar_order_test(&s2);
secp256k1_scalar_set_b32(&s2, c, &overflow); secp256k1_scalar_get_b32(c, &s2);
secp256k1_num_t s2num;
secp256k1_num_set_bin(&s2num, c, 32); #ifndef USE_NUM_NONE
secp256k1_num_mod(&s2num, &secp256k1_ge_consts->order); secp256k1_num_t snum, s1num, s2num;
secp256k1_scalar_get_num(&snum, &s);
secp256k1_scalar_get_num(&s1num, &s1);
secp256k1_scalar_get_num(&s2num, &s2);
secp256k1_num_t order;
secp256k1_scalar_order_get_num(&order);
secp256k1_num_t half_order = order;
secp256k1_num_shift(&half_order, 1);
#endif
{ {
/* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */ /* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */
secp256k1_num_t n, t, m; secp256k1_scalar_t n;
secp256k1_num_set_int(&n, 0); secp256k1_scalar_set_int(&n, 0);
secp256k1_num_set_int(&m, 16);
for (int i = 0; i < 256; i += 4) { for (int i = 0; i < 256; i += 4) {
secp256k1_num_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4)); secp256k1_scalar_t t;
secp256k1_num_mul(&n, &n, &m); secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4));
secp256k1_num_add(&n, &n, &t); for (int j = 0; j < 4; j++) {
secp256k1_scalar_add(&n, &n, &n);
}
secp256k1_scalar_add(&n, &n, &t);
} }
CHECK(secp256k1_num_eq(&n, &snum)); CHECK(secp256k1_scalar_eq(&n, &s));
} }
{ {
/* Test that get_b32 returns the same as get_bin on the number. */ /* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */
unsigned char r1[32]; secp256k1_scalar_t n;
secp256k1_scalar_get_b32(r1, &s2); secp256k1_scalar_set_int(&n, 0);
unsigned char r2[32]; int i = 0;
secp256k1_num_get_bin(r2, 32, &s2num); while (i < 256) {
CHECK(memcmp(r1, r2, 32) == 0); int now = (secp256k1_rand32() % 15) + 1;
/* If no overflow occurred when assigning, it should also be equal to the original byte array. */ if (now + i > 256) {
CHECK((memcmp(r1, c, 32) == 0) == (overflow == 0)); now = 256 - i;
}
secp256k1_scalar_t t;
secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits_var(&s, 256 - now - i, now));
for (int j = 0; j < now; j++) {
secp256k1_scalar_add(&n, &n, &n);
}
secp256k1_scalar_add(&n, &n, &t);
i += now;
}
CHECK(secp256k1_scalar_eq(&n, &s));
} }
#ifndef USE_NUM_NONE
{ {
/* Test that adding the scalars together is equal to adding their numbers together modulo the order. */ /* Test that adding the scalars together is equal to adding their numbers together modulo the order. */
secp256k1_num_t rnum; secp256k1_num_t rnum;
secp256k1_num_add(&rnum, &snum, &s2num); secp256k1_num_add(&rnum, &snum, &s2num);
secp256k1_num_mod(&rnum, &secp256k1_ge_consts->order); secp256k1_num_mod(&rnum, &order);
secp256k1_scalar_t r; secp256k1_scalar_t r;
secp256k1_scalar_add(&r, &s, &s2); secp256k1_scalar_add(&r, &s, &s2);
secp256k1_num_t r2num; secp256k1_num_t r2num;
@ -316,7 +249,7 @@ void scalar_test(void) {
/* Test that multipying the scalars is equal to multiplying their numbers modulo the order. */ /* Test that multipying the scalars is equal to multiplying their numbers modulo the order. */
secp256k1_num_t rnum; secp256k1_num_t rnum;
secp256k1_num_mul(&rnum, &snum, &s2num); secp256k1_num_mul(&rnum, &snum, &s2num);
secp256k1_num_mod(&rnum, &secp256k1_ge_consts->order); secp256k1_num_mod(&rnum, &order);
secp256k1_scalar_t r; secp256k1_scalar_t r;
secp256k1_scalar_mul(&r, &s, &s2); secp256k1_scalar_mul(&r, &s, &s2);
secp256k1_num_t r2num; secp256k1_num_t r2num;
@ -333,14 +266,14 @@ void scalar_test(void) {
/* Check that comparison with zero matches comparison with zero on the number. */ /* Check that comparison with zero matches comparison with zero on the number. */
CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s)); CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s));
/* Check that comparison with the half order is equal to testing for high scalar. */ /* Check that comparison with the half order is equal to testing for high scalar. */
CHECK(secp256k1_scalar_is_high(&s) == (secp256k1_num_cmp(&snum, &secp256k1_ge_consts->half_order) > 0)); CHECK(secp256k1_scalar_is_high(&s) == (secp256k1_num_cmp(&snum, &half_order) > 0));
secp256k1_scalar_t neg; secp256k1_scalar_t neg;
secp256k1_scalar_negate(&neg, &s); secp256k1_scalar_negate(&neg, &s);
secp256k1_num_t negnum; secp256k1_num_t negnum;
secp256k1_num_sub(&negnum, &secp256k1_ge_consts->order, &snum); secp256k1_num_sub(&negnum, &order, &snum);
secp256k1_num_mod(&negnum, &secp256k1_ge_consts->order); secp256k1_num_mod(&negnum, &order);
/* Check that comparison with the half order is equal to testing for high scalar after negation. */ /* Check that comparison with the half order is equal to testing for high scalar after negation. */
CHECK(secp256k1_scalar_is_high(&neg) == (secp256k1_num_cmp(&negnum, &secp256k1_ge_consts->half_order) > 0)); CHECK(secp256k1_scalar_is_high(&neg) == (secp256k1_num_cmp(&negnum, &half_order) > 0));
/* Negating should change the high property, unless the value was already zero. */ /* Negating should change the high property, unless the value was already zero. */
CHECK((secp256k1_scalar_is_high(&s) == secp256k1_scalar_is_high(&neg)) == secp256k1_scalar_is_zero(&s)); CHECK((secp256k1_scalar_is_high(&s) == secp256k1_scalar_is_high(&neg)) == secp256k1_scalar_is_zero(&s));
secp256k1_num_t negnum2; secp256k1_num_t negnum2;
@ -355,16 +288,37 @@ void scalar_test(void) {
CHECK(secp256k1_scalar_is_zero(&neg)); CHECK(secp256k1_scalar_is_zero(&neg));
} }
{
/* Test secp256k1_scalar_mul_shift_var. */
secp256k1_scalar_t r;
unsigned int shift = 256 + (secp256k1_rand32() % 257);
secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift);
secp256k1_num_t rnum;
secp256k1_num_mul(&rnum, &s1num, &s2num);
secp256k1_num_shift(&rnum, shift - 1);
secp256k1_num_t one;
unsigned char cone[1] = {0x01};
secp256k1_num_set_bin(&one, cone, 1);
secp256k1_num_add(&rnum, &rnum, &one);
secp256k1_num_shift(&rnum, 1);
secp256k1_num_t rnum2;
secp256k1_scalar_get_num(&rnum2, &r);
CHECK(secp256k1_num_eq(&rnum, &rnum2));
}
#endif
{ {
/* Test that scalar inverses are equal to the inverse of their number modulo the order. */ /* Test that scalar inverses are equal to the inverse of their number modulo the order. */
if (!secp256k1_scalar_is_zero(&s)) { if (!secp256k1_scalar_is_zero(&s)) {
secp256k1_scalar_t inv; secp256k1_scalar_t inv;
secp256k1_scalar_inverse(&inv, &s); secp256k1_scalar_inverse(&inv, &s);
#ifndef USE_NUM_NONE
secp256k1_num_t invnum; secp256k1_num_t invnum;
secp256k1_num_mod_inverse(&invnum, &snum, &secp256k1_ge_consts->order); secp256k1_num_mod_inverse(&invnum, &snum, &order);
secp256k1_num_t invnum2; secp256k1_num_t invnum2;
secp256k1_scalar_get_num(&invnum2, &inv); secp256k1_scalar_get_num(&invnum2, &inv);
CHECK(secp256k1_num_eq(&invnum, &invnum2)); CHECK(secp256k1_num_eq(&invnum, &invnum2));
#endif
secp256k1_scalar_mul(&inv, &inv, &s); secp256k1_scalar_mul(&inv, &inv, &s);
/* Multiplying a scalar with its inverse must result in one. */ /* Multiplying a scalar with its inverse must result in one. */
CHECK(secp256k1_scalar_is_one(&inv)); CHECK(secp256k1_scalar_is_one(&inv));
@ -382,6 +336,23 @@ void scalar_test(void) {
CHECK(secp256k1_scalar_eq(&r1, &r2)); CHECK(secp256k1_scalar_eq(&r1, &r2));
} }
{
/* Test add_bit. */
int bit = secp256k1_rand32() % 256;
secp256k1_scalar_t b;
secp256k1_scalar_set_int(&b, 1);
CHECK(secp256k1_scalar_is_one(&b));
for (int i = 0; i < bit; i++) {
secp256k1_scalar_add(&b, &b, &b);
}
secp256k1_scalar_t r1 = s1, r2 = s1;
if (!secp256k1_scalar_add(&r1, &r1, &b)) {
/* No overflow happened. */
secp256k1_scalar_add_bit(&r2, bit);
CHECK(secp256k1_scalar_eq(&r1, &r2));
}
}
{ {
/* Test commutativity of mul. */ /* Test commutativity of mul. */
secp256k1_scalar_t r1, r2; secp256k1_scalar_t r1, r2;
@ -428,20 +399,49 @@ void scalar_test(void) {
secp256k1_scalar_mul(&r2, &s1, &s1); secp256k1_scalar_mul(&r2, &s1, &s1);
CHECK(secp256k1_scalar_eq(&r1, &r2)); CHECK(secp256k1_scalar_eq(&r1, &r2));
} }
} }
void run_scalar_tests(void) { void run_scalar_tests(void) {
for (int i = 0; i < 128 * count; i++) { for (int i = 0; i < 128 * count; i++) {
scalar_test(); scalar_test();
} }
{
/* (-1)+1 should be zero. */
secp256k1_scalar_t s, o;
secp256k1_scalar_set_int(&s, 1);
secp256k1_scalar_negate(&o, &s);
secp256k1_scalar_add(&o, &o, &s);
CHECK(secp256k1_scalar_is_zero(&o));
}
#ifndef USE_NUM_NONE
{
/* A scalar with value of the curve order should be 0. */
secp256k1_num_t order;
secp256k1_scalar_order_get_num(&order);
unsigned char bin[32];
secp256k1_num_get_bin(bin, 32, &order);
secp256k1_scalar_t zero;
int overflow = 0;
secp256k1_scalar_set_b32(&zero, bin, &overflow);
CHECK(overflow == 1);
CHECK(secp256k1_scalar_is_zero(&zero));
}
#endif
} }
/***** FIELD TESTS *****/ /***** FIELD TESTS *****/
void random_fe(secp256k1_fe_t *x) { void random_fe(secp256k1_fe_t *x) {
unsigned char bin[32]; unsigned char bin[32];
do {
secp256k1_rand256(bin); secp256k1_rand256(bin);
secp256k1_fe_set_b32(x, bin); if (secp256k1_fe_set_b32(x, bin)) {
return;
}
} while(1);
} }
void random_fe_non_zero(secp256k1_fe_t *nz) { void random_fe_non_zero(secp256k1_fe_t *nz) {
@ -617,9 +617,17 @@ void gej_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
} }
void test_ge(void) { void test_ge(void) {
char ca[135];
char cb[68];
int rlen;
secp256k1_ge_t a, b, i, n; secp256k1_ge_t a, b, i, n;
random_group_element_test(&a); random_group_element_test(&a);
random_group_element_test(&b); random_group_element_test(&b);
rlen = sizeof(ca);
secp256k1_ge_get_hex(ca,&rlen,&a);
CHECK(rlen > 4 && rlen <= (int)sizeof(ca));
rlen = sizeof(cb);
secp256k1_ge_get_hex(cb,&rlen,&b); /* Intentionally undersized buffer. */
n = a; n = a;
secp256k1_fe_normalize(&a.y); secp256k1_fe_normalize(&a.y);
secp256k1_fe_negate(&n.y, &a.y, 1); secp256k1_fe_negate(&n.y, &a.y, 1);
@ -697,39 +705,51 @@ void run_ge(void) {
void run_ecmult_chain(void) { void run_ecmult_chain(void) {
/* random starting point A (on the curve) */ /* random starting point A (on the curve) */
secp256k1_fe_t ax; secp256k1_fe_set_hex(&ax, "8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004", 64); secp256k1_fe_t ax; VERIFY_CHECK(secp256k1_fe_set_hex(&ax, "8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004", 64));
secp256k1_fe_t ay; secp256k1_fe_set_hex(&ay, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64); secp256k1_fe_t ay; VERIFY_CHECK(secp256k1_fe_set_hex(&ay, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64));
secp256k1_gej_t a; secp256k1_gej_set_xy(&a, &ax, &ay); secp256k1_gej_t a; secp256k1_gej_set_xy(&a, &ax, &ay);
/* two random initial factors xn and gn */ /* two random initial factors xn and gn */
secp256k1_num_t xn; static const unsigned char xni[32] = {
secp256k1_num_set_hex(&xn, "84cc5452f7fde1edb4d38a8ce9b1b84ccef31f146e569be9705d357a42985407", 64); 0x84, 0xcc, 0x54, 0x52, 0xf7, 0xfd, 0xe1, 0xed,
secp256k1_num_t gn; 0xb4, 0xd3, 0x8a, 0x8c, 0xe9, 0xb1, 0xb8, 0x4c,
secp256k1_num_set_hex(&gn, "a1e58d22553dcd42b23980625d4c57a96e9323d42b3152e5ca2c3990edc7c9de", 64); 0xce, 0xf3, 0x1f, 0x14, 0x6e, 0x56, 0x9b, 0xe9,
0x70, 0x5d, 0x35, 0x7a, 0x42, 0x98, 0x54, 0x07
};
secp256k1_scalar_t xn;
secp256k1_scalar_set_b32(&xn, xni, NULL);
static const unsigned char gni[32] = {
0xa1, 0xe5, 0x8d, 0x22, 0x55, 0x3d, 0xcd, 0x42,
0xb2, 0x39, 0x80, 0x62, 0x5d, 0x4c, 0x57, 0xa9,
0x6e, 0x93, 0x23, 0xd4, 0x2b, 0x31, 0x52, 0xe5,
0xca, 0x2c, 0x39, 0x90, 0xed, 0xc7, 0xc9, 0xde
};
secp256k1_scalar_t gn;
secp256k1_scalar_set_b32(&gn, gni, NULL);
/* two small multipliers to be applied to xn and gn in every iteration: */ /* two small multipliers to be applied to xn and gn in every iteration: */
secp256k1_num_t xf; static const unsigned char xfi[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x13,0x37};
secp256k1_num_set_hex(&xf, "1337", 4); secp256k1_scalar_t xf;
secp256k1_num_t gf; secp256k1_scalar_set_b32(&xf, xfi, NULL);
secp256k1_num_set_hex(&gf, "7113", 4); static const unsigned char gfi[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x71,0x13};
secp256k1_scalar_t gf;
secp256k1_scalar_set_b32(&gf, gfi, NULL);
/* accumulators with the resulting coefficients to A and G */ /* accumulators with the resulting coefficients to A and G */
secp256k1_num_t ae; secp256k1_scalar_t ae;
secp256k1_num_set_int(&ae, 1); secp256k1_scalar_set_int(&ae, 1);
secp256k1_num_t ge; secp256k1_scalar_t ge;
secp256k1_num_set_int(&ge, 0); secp256k1_scalar_set_int(&ge, 0);
/* the point being computed */ /* the point being computed */
secp256k1_gej_t x = a; secp256k1_gej_t x = a;
const secp256k1_num_t *order = &secp256k1_ge_consts->order;
for (int i=0; i<200*count; i++) { for (int i=0; i<200*count; i++) {
/* in each iteration, compute X = xn*X + gn*G; */ /* in each iteration, compute X = xn*X + gn*G; */
secp256k1_ecmult(&x, &x, &xn, &gn); secp256k1_ecmult(&x, &x, &xn, &gn);
/* also compute ae and ge: the actual accumulated factors for A and G */ /* 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) */ /* 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_scalar_mul(&ae, &ae, &xn);
secp256k1_num_mod_mul(&ge, &ge, &xn, order); secp256k1_scalar_mul(&ge, &ge, &xn);
secp256k1_num_add(&ge, &ge, &gn); secp256k1_scalar_add(&ge, &ge, &gn);
secp256k1_num_mod(&ge, order);
/* modify xn and gn */ /* modify xn and gn */
secp256k1_num_mod_mul(&xn, &xn, &xf, order); secp256k1_scalar_mul(&xn, &xn, &xf);
secp256k1_num_mod_mul(&gn, &gn, &gf, order); secp256k1_scalar_mul(&gn, &gn, &gf);
/* verify */ /* verify */
if (i == 19999) { if (i == 19999) {
@ -749,17 +769,25 @@ void run_ecmult_chain(void) {
} }
void test_point_times_order(const secp256k1_gej_t *point) { void test_point_times_order(const secp256k1_gej_t *point) {
/* multiplying a point by the order results in O */ /* X * (point + G) + (order-X) * (pointer + G) = 0 */
const secp256k1_num_t *order = &secp256k1_ge_consts->order; secp256k1_scalar_t x;
secp256k1_num_t zero; random_scalar_order_test(&x);
secp256k1_num_set_int(&zero, 0); secp256k1_scalar_t nx;
secp256k1_gej_t res; secp256k1_scalar_negate(&nx, &x);
secp256k1_ecmult(&res, point, order, order); /* calc res = order * point + order * G; */ secp256k1_gej_t res1, res2;
CHECK(secp256k1_gej_is_infinity(&res)); secp256k1_ecmult(&res1, point, &x, &x); /* calc res1 = x * point + x * G; */
secp256k1_ecmult(&res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */
secp256k1_gej_add_var(&res1, &res1, &res2);
CHECK(secp256k1_gej_is_infinity(&res1));
CHECK(secp256k1_gej_is_valid(&res1) == 0);
secp256k1_ge_t res3;
secp256k1_ge_set_gej(&res3, &res1);
CHECK(secp256k1_ge_is_infinity(&res3));
CHECK(secp256k1_ge_is_valid(&res3) == 0);
} }
void run_point_times_order(void) { void run_point_times_order(void) {
secp256k1_fe_t x; secp256k1_fe_set_hex(&x, "02", 2); secp256k1_fe_t x; VERIFY_CHECK(secp256k1_fe_set_hex(&x, "02", 2));
for (int i=0; i<500; i++) { for (int i=0; i<500; i++) {
secp256k1_ge_t p; secp256k1_ge_t p;
if (secp256k1_ge_set_xo(&p, &x, 1)) { if (secp256k1_ge_set_xo(&p, &x, 1)) {
@ -776,15 +804,16 @@ void run_point_times_order(void) {
CHECK(strcmp(c, "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45") == 0); CHECK(strcmp(c, "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45") == 0);
} }
void test_wnaf(const secp256k1_num_t *number, int w) { void test_wnaf(const secp256k1_scalar_t *number, int w) {
secp256k1_num_t x, two, t; secp256k1_scalar_t x, two, t;
secp256k1_num_set_int(&x, 0); secp256k1_scalar_set_int(&x, 0);
secp256k1_num_set_int(&two, 2); secp256k1_scalar_set_int(&two, 2);
int wnaf[257]; int wnaf[256];
int bits = secp256k1_ecmult_wnaf(wnaf, number, w); int bits = secp256k1_ecmult_wnaf(wnaf, number, w);
CHECK(bits <= 256);
int zeroes = -1; int zeroes = -1;
for (int i=bits-1; i>=0; i--) { for (int i=bits-1; i>=0; i--) {
secp256k1_num_mul(&x, &x, &two); secp256k1_scalar_mul(&x, &x, &two);
int v = wnaf[i]; int v = wnaf[i];
if (v) { if (v) {
CHECK(zeroes == -1 || zeroes >= w-1); /* check that distance between non-zero elements is at least w-1 */ CHECK(zeroes == -1 || zeroes >= w-1); /* check that distance between non-zero elements is at least w-1 */
@ -796,18 +825,23 @@ void test_wnaf(const secp256k1_num_t *number, int w) {
CHECK(zeroes != -1); /* check that no unnecessary zero padding exists */ CHECK(zeroes != -1); /* check that no unnecessary zero padding exists */
zeroes++; zeroes++;
} }
secp256k1_num_set_int(&t, v); if (v >= 0) {
secp256k1_num_add(&x, &x, &t); secp256k1_scalar_set_int(&t, v);
} else {
secp256k1_scalar_set_int(&t, -v);
secp256k1_scalar_negate(&t, &t);
}
secp256k1_scalar_add(&x, &x, &t);
} }
CHECK(secp256k1_num_eq(&x, number)); /* check that wnaf represents number */ CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */
} }
void run_wnaf(void) { void run_wnaf(void) {
secp256k1_num_t n; secp256k1_scalar_t n;
for (int i=0; i<count; i++) { for (int i=0; i<count; i++) {
random_num_order(&n); random_scalar_order(&n);
if (i % 1) if (i % 1)
secp256k1_num_negate(&n); secp256k1_scalar_negate(&n, &n);
test_wnaf(&n, 4+(i%10)); test_wnaf(&n, 4+(i%10));
} }
} }
@ -820,18 +854,22 @@ void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *key, cons
} }
void test_ecdsa_sign_verify(void) { void test_ecdsa_sign_verify(void) {
int recid;
int getrec;
secp256k1_scalar_t msg, key; secp256k1_scalar_t msg, key;
random_scalar_order_test(&msg); random_scalar_order_test(&msg);
random_scalar_order_test(&key); random_scalar_order_test(&key);
secp256k1_gej_t pubj; secp256k1_ecmult_gen(&pubj, &key); secp256k1_gej_t pubj; secp256k1_ecmult_gen(&pubj, &key);
secp256k1_ge_t pub; secp256k1_ge_set_gej(&pub, &pubj); secp256k1_ge_t pub; secp256k1_ge_set_gej(&pub, &pubj);
secp256k1_ecdsa_sig_t sig; secp256k1_ecdsa_sig_t sig;
random_sign(&sig, &key, &msg, NULL); getrec = secp256k1_rand32()&1;
secp256k1_num_t msg_num; random_sign(&sig, &key, &msg, getrec?&recid:NULL);
secp256k1_scalar_get_num(&msg_num, &msg); if (getrec) CHECK(recid >= 0 && recid < 4);
CHECK(secp256k1_ecdsa_sig_verify(&sig, &pub, &msg_num)); CHECK(secp256k1_ecdsa_sig_verify(&sig, &pub, &msg));
secp256k1_num_inc(&msg_num); secp256k1_scalar_t one;
CHECK(!secp256k1_ecdsa_sig_verify(&sig, &pub, &msg_num)); secp256k1_scalar_set_int(&one, 1);
secp256k1_scalar_add(&msg, &msg, &one);
CHECK(!secp256k1_ecdsa_sig_verify(&sig, &pub, &msg));
} }
void run_ecdsa_sign_verify(void) { void run_ecdsa_sign_verify(void) {
@ -846,11 +884,11 @@ void test_ecdsa_end_to_end(void) {
/* Generate a random key and message. */ /* Generate a random key and message. */
{ {
secp256k1_num_t msg, key; secp256k1_scalar_t msg, key;
random_num_order_test(&msg); random_scalar_order_test(&msg);
random_num_order_test(&key); random_scalar_order_test(&key);
secp256k1_num_get_bin(privkey, 32, &key); secp256k1_scalar_get_b32(privkey, &key);
secp256k1_num_get_bin(message, 32, &msg); secp256k1_scalar_get_b32(message, &msg);
} }
/* Construct and verify corresponding public key. */ /* Construct and verify corresponding public key. */
@ -935,7 +973,8 @@ void run_ecdsa_end_to_end(void) {
} }
} }
void test_ecdsa_infinity(void) { /* Tests several edge cases. */
void test_ecdsa_edge_cases(void) {
const unsigned char msg32[32] = { const unsigned char msg32[32] = {
'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's',
@ -943,8 +982,8 @@ void test_ecdsa_infinity(void) {
's', 's', 'a', 'g', 'e', '.', '.', '.' 's', 's', 'a', 'g', 'e', '.', '.', '.'
}; };
const unsigned char sig64[64] = { const unsigned char sig64[64] = {
// Generated by signing the above message with nonce 'This is the nonce we will use...' /* Generated by signing the above message with nonce 'This is the nonce we will use...'
// and secret key 0 (which is not valid), resulting in recid 0. * and secret key 0 (which is not valid), resulting in recid 0. */
0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8,
0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96,
0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63,
@ -960,10 +999,93 @@ void test_ecdsa_infinity(void) {
CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 1)); CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 1));
CHECK(!secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 2)); CHECK(!secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 2));
CHECK(!secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 3)); CHECK(!secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 3));
/* signature (r,s) = (4,4), which can be recovered with all 4 recids. */
const unsigned char sigb64[64] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
};
unsigned char pubkeyb[33];
int pubkeyblen = 33;
for (int recid = 0; recid < 4; recid++) {
/* (4,4) encoded in DER. */
unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04};
/* (order + r,4) encoded in DER. */
unsigned char sigbderlong[40] = {
0x30, 0x26, 0x02, 0x21, 0x00, 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, 0x45, 0x02, 0x01, 0x04
};
CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigb64, pubkeyb, &pubkeyblen, 1, recid));
CHECK(secp256k1_ecdsa_verify(msg32, 32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1);
for (int recid2 = 0; recid2 < 4; recid2++) {
unsigned char pubkey2b[33];
int pubkey2blen = 33;
CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigb64, pubkey2b, &pubkey2blen, 1, recid2));
/* Verifying with (order + r,4) should always fail. */
CHECK(secp256k1_ecdsa_verify(msg32, 32, sigbderlong, sizeof(sigbderlong), pubkey2b, pubkey2blen) != 1);
}
/* Damage signature. */
sigbder[7]++;
CHECK(secp256k1_ecdsa_verify(msg32, 32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0);
}
/* Test the case where ECDSA recomputes a point that is infinity. */
{
secp256k1_ecdsa_sig_t sig;
secp256k1_scalar_set_int(&sig.s, 1);
secp256k1_scalar_negate(&sig.s, &sig.s);
secp256k1_scalar_inverse(&sig.s, &sig.s);
secp256k1_scalar_set_int(&sig.r, 1);
secp256k1_gej_t keyj;
secp256k1_ecmult_gen(&keyj, &sig.r);
secp256k1_ge_t key;
secp256k1_ge_set_gej(&key, &keyj);
secp256k1_scalar_t msg = sig.s;
CHECK(secp256k1_ecdsa_sig_verify(&sig, &key, &msg) == 0);
}
/* Test r/s equal to zero */
{
/* (1,1) encoded in DER. */
unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01};
unsigned char sigc64[64] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
};
unsigned char pubkeyc[65];
int pubkeyclen = 65;
CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1);
CHECK(secp256k1_ecdsa_verify(msg32, 32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1);
sigcder[4] = 0;
sigc64[31] = 0;
CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0);
CHECK(secp256k1_ecdsa_verify(msg32, 32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0);
sigcder[4] = 1;
sigcder[7] = 0;
sigc64[31] = 1;
sigc64[63] = 0;
CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0);
CHECK(secp256k1_ecdsa_verify(msg32, 32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0);
}
} }
void run_ecdsa_infinity(void) { void run_ecdsa_edge_cases(void) {
test_ecdsa_infinity(); test_ecdsa_edge_cases();
} }
#ifdef ENABLE_OPENSSL_TESTS #ifdef ENABLE_OPENSSL_TESTS
@ -996,11 +1118,12 @@ void test_ecdsa_openssl(void) {
CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key));
secp256k1_ecdsa_sig_t sig; secp256k1_ecdsa_sig_t sig;
CHECK(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize)); CHECK(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize));
secp256k1_num_t msg_num; CHECK(secp256k1_ecdsa_sig_verify(&sig, &q, &msg));
secp256k1_scalar_get_num(&msg_num, &msg); secp256k1_scalar_t one;
CHECK(secp256k1_ecdsa_sig_verify(&sig, &q, &msg_num)); secp256k1_scalar_set_int(&one, 1);
secp256k1_num_inc(&sig.r); secp256k1_scalar_t msg2;
CHECK(!secp256k1_ecdsa_sig_verify(&sig, &q, &msg_num)); secp256k1_scalar_add(&msg2, &msg, &one);
CHECK(!secp256k1_ecdsa_sig_verify(&sig, &q, &msg2));
random_sign(&sig, &key, &msg, NULL); random_sign(&sig, &key, &msg, NULL);
int secp_sigsize = 80; int secp_sigsize = 80;
@ -1042,8 +1165,19 @@ int main(int argc, char **argv) {
/* initialize */ /* initialize */
secp256k1_start(SECP256K1_START_SIGN | SECP256K1_START_VERIFY); secp256k1_start(SECP256K1_START_SIGN | SECP256K1_START_VERIFY);
/* initializing a second time shouldn't cause any harm or memory leaks. */
secp256k1_start(SECP256K1_START_SIGN | SECP256K1_START_VERIFY);
/* Likewise, re-running the internal init functions should be harmless. */
secp256k1_fe_start();
secp256k1_ge_start();
secp256k1_scalar_start();
secp256k1_ecdsa_start();
#ifndef USE_NUM_NONE
/* num tests */ /* num tests */
run_num_smalltests(); run_num_smalltests();
#endif
/* scalar tests */ /* scalar tests */
run_scalar_tests(); run_scalar_tests();
@ -1067,7 +1201,7 @@ int main(int argc, char **argv) {
/* ecdsa tests */ /* ecdsa tests */
run_ecdsa_sign_verify(); run_ecdsa_sign_verify();
run_ecdsa_end_to_end(); run_ecdsa_end_to_end();
run_ecdsa_infinity(); run_ecdsa_edge_cases();
#ifdef ENABLE_OPENSSL_TESTS #ifdef ENABLE_OPENSSL_TESTS
run_ecdsa_openssl(); run_ecdsa_openssl();
#endif #endif
@ -1076,5 +1210,14 @@ int main(int argc, char **argv) {
/* shutdown */ /* shutdown */
secp256k1_stop(); secp256k1_stop();
/* shutting down twice shouldn't cause any double frees. */
secp256k1_stop();
/* Same for the internal shutdown functions. */
secp256k1_fe_stop();
secp256k1_ge_stop();
secp256k1_scalar_stop();
secp256k1_ecdsa_stop();
return 0; return 0;
} }

17
src/util.h

@ -61,4 +61,21 @@
#define VERIFY_CHECK(cond) do { (void)(cond); } while(0) #define VERIFY_CHECK(cond) do { (void)(cond); } while(0)
#endif #endif
/* Macro for restrict, when available and not in a VERIFY build. */
#if defined(SECP256K1_BUILD) && defined(VERIFY)
# define SECP256K1_RESTRICT
#else
# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
# if SECP256K1_GNUC_PREREQ(3,0)
# define SECP256K1_RESTRICT __restrict__
# elif (defined(_MSC_VER) && _MSC_VER >= 1400)
# define SECP256K1_RESTRICT __restrict
# else
# define SECP256K1_RESTRICT
# endif
# else
# define SECP256K1_RESTRICT restrict
# endif
#endif
#endif #endif

Loading…
Cancel
Save