diff --git a/.travis.yml b/.travis.yml index 44563d1b18..cbafed7a58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,10 @@ install: - if [ "$FIELD" = "64bit_asm" ]; then sudo apt-get install -qq yasm; fi env: global: - - FIELD=auto BIGNUM=auto ENDOMORPHISM=no BUILD=check + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no BUILD=check matrix: + - SCALAR=32bit + - SCALAR=64bit - FIELD=gmp - FIELD=gmp ENDOMORPHISM=yes - FIELD=64bit_asm @@ -18,5 +20,5 @@ env: - FIELD=32bit ENDOMORPHISM=yes - BUILD=distcheck before_script: ./autogen.sh -script: ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM && make -j2 $BUILD +script: ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR && make -j2 $BUILD os: linux diff --git a/Makefile.am b/Makefile.am index 7fa4ceeb48..7f16ef40b0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,7 +10,11 @@ noinst_LTLIBRARIES = $(COMMON_LIB) include_HEADERS = include/secp256k1.h noinst_HEADERS = noinst_HEADERS += src/scalar.h +noinst_HEADERS += src/scalar_4x64.h +noinst_HEADERS += src/scalar_8x32.h noinst_HEADERS += src/scalar_impl.h +noinst_HEADERS += src/scalar_4x64_impl.h +noinst_HEADERS += src/scalar_8x32_impl.h noinst_HEADERS += src/group.h noinst_HEADERS += src/group_impl.h noinst_HEADERS += src/num_gmp.h diff --git a/configure.ac b/configure.ac index 8f9b2cc81b..c22669002c 100644 --- a/configure.ac +++ b/configure.ac @@ -64,6 +64,9 @@ AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=gmp|64bit|64bit_asm|32bit|aut AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|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], +[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto]) + AC_CHECK_TYPES([__int128]) AC_DEFUN([SECP_INT128_CHECK],[ @@ -71,6 +74,9 @@ has_int128=$ac_cv_type___int128 if test x"$has_int128" != x"yes" && test x"$set_field" = x"64bit"; then AC_MSG_ERROR([$set_field field support explicitly requested but is not compatible with this host]) fi +if test x"$has_int128" != x"yes" && test x"$set_scalar" = x"64bit"; then + AC_MSG_ERROR([$set_scalar scalar support explicitly requested but is not compatible with this host]) +fi ]) AC_DEFUN([SECP_64BIT_ASM_CHECK],[ @@ -194,6 +200,30 @@ else esac fi +if test x"$req_scalar" = x"auto"; then + if test x"$set_scalar" = x; then + SECP_INT128_CHECK + if test x"$has_int128" = x"yes"; then + set_scalar=64bit + fi + fi + if test x"$set_scalar" = x; then + set_scalar=32bit + fi +else + set_scalar=$req_scalar + case $set_scalar in + 64bit) + SECP_INT128_CHECK + ;; + 32bit) + ;; + *) + AC_MSG_ERROR([invalid scalar implementation selected]) + ;; + esac +fi + if test x"$req_bignum" = x"auto"; then SECP_GMP_CHECK if test x"$has_gmp" = x"yes"; then @@ -252,6 +282,19 @@ gmp) ;; esac +#select scalar implementation +case $set_scalar in +64bit) + AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation]) + ;; +32bit) + AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation]) + ;; +*) + AC_MSG_ERROR([invalid scalar implementation]) + ;; +esac + if test x"$use_tests" = x"yes"; then SECP_OPENSSL_CHECK if test x"$has_openssl_ec" == x"yes"; then @@ -278,6 +321,7 @@ fi AC_MSG_NOTICE([Using field implementation: $set_field]) AC_MSG_NOTICE([Using bignum implementation: $set_bignum]) +AC_MSG_NOTICE([Using scalar implementation: $set_scalar]) AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) AC_CONFIG_FILES([Makefile libsecp256k1.pc]) diff --git a/src/scalar.h b/src/scalar.h index fdc0500121..2579db12b2 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -7,10 +7,17 @@ #include "num.h" -/** A scalar modulo the group order of the secp256k1 curve. */ -typedef struct { - secp256k1_num_t n; -} secp256k1_scalar_t; +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#if defined(USE_SCALAR_4X64) +#include "scalar_4x64.h" +#elif defined(USE_SCALAR_8X32) +#include "scalar_8x32.h" +#else +#error "Please select scalar implementation" +#endif /** Clear a scalar to prevent the leak of sensitive data. */ void static secp256k1_scalar_clear(secp256k1_scalar_t *r); @@ -30,6 +37,9 @@ void static secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t /** Multiply two scalars (modulo the group order). */ void static secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); +/** Compute the square of a scalar (modulo the group order). */ +void static secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); + /** Compute the inverse of a scalar (modulo the group order). */ void static secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); diff --git a/src/scalar_4x64.h b/src/scalar_4x64.h new file mode 100644 index 0000000000..22ebe4fbba --- /dev/null +++ b/src/scalar_4x64.h @@ -0,0 +1,15 @@ +// Copyright (c) 2014 Pieter Wuille +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef _SECP256K1_SCALAR_REPR_ +#define _SECP256K1_SCALAR_REPR_ + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef struct { + uint64_t d[4]; +} secp256k1_scalar_t; + +#endif diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h new file mode 100644 index 0000000000..66f17a2e23 --- /dev/null +++ b/src/scalar_4x64_impl.h @@ -0,0 +1,357 @@ +// Copyright (c) 2014 Pieter Wuille +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ +#define _SECP256K1_SCALAR_REPR_IMPL_H_ + +typedef unsigned __int128 uint128_t; + +// Limbs of the secp256k1 order. +#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) +#define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL) +#define SECP256K1_N_2 ((uint64_t)0xFFFFFFFFFFFFFFFEULL) +#define SECP256K1_N_3 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) + +// Limbs of 2^256 minus the secp256k1 order. +#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) +#define SECP256K1_N_C_1 (~SECP256K1_N_1) +#define SECP256K1_N_C_2 (1) + +// Limbs of half the secp256k1 order. +#define SECP256K1_N_H_0 ((uint64_t)0xDFE92F46681B20A0ULL) +#define SECP256K1_N_H_1 ((uint64_t)0x5D576E7357A4501DULL) +#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) +#define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL) + +void static inline secp256k1_scalar_clear(secp256k1_scalar_t *r) { + r->d[0] = 0; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; +} + +int static inline secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, int offset, int count) { + VERIFY_CHECK((offset + count - 1) / 64 == offset / 64); + return (a->d[offset / 64] >> (offset % 64)) & ((((uint64_t)1) << count) - 1); +} + +int static inline secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) { + int yes = 0; + int no = 0; + no |= (a->d[3] < SECP256K1_N_3); // No need for a > check. + no |= (a->d[2] < SECP256K1_N_2); + yes |= (a->d[2] > SECP256K1_N_2) & ~no; + no |= (a->d[1] < SECP256K1_N_1); + yes |= (a->d[1] > SECP256K1_N_1) & ~no; + yes |= (a->d[0] >= SECP256K1_N_0) & ~no; + return yes; +} + +int static inline secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsigned int overflow) { + VERIFY_CHECK(overflow <= 1); + uint128_t t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; + r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1; + r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[2] + overflow * SECP256K1_N_C_2; + r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint64_t)r->d[3]; + r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; + return overflow; +} + +void static 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]; + r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)a->d[1] + b->d[1]; + r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)a->d[2] + b->d[2]; + r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)a->d[3] + b->d[3]; + r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + secp256k1_scalar_reduce(r, t + secp256k1_scalar_check_overflow(r)); +} + +void static secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) { + r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56; + r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56; + r->d[2] = (uint64_t)b32[15] | (uint64_t)b32[14] << 8 | (uint64_t)b32[13] << 16 | (uint64_t)b32[12] << 24 | (uint64_t)b32[11] << 32 | (uint64_t)b32[10] << 40 | (uint64_t)b32[9] << 48 | (uint64_t)b32[8] << 56; + r->d[3] = (uint64_t)b32[7] | (uint64_t)b32[6] << 8 | (uint64_t)b32[5] << 16 | (uint64_t)b32[4] << 24 | (uint64_t)b32[3] << 32 | (uint64_t)b32[2] << 40 | (uint64_t)b32[1] << 48 | (uint64_t)b32[0] << 56; + int over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); + if (overflow) { + *overflow = over; + } +} + +void static secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) { + bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3]; + bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2]; + bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1]; + bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; +} + +int static inline secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) { + return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; +} + +void static secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { + uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0); + uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1; + r->d[0] = t & nonzero; t >>= 64; + t += (uint128_t)(~a->d[1]) + SECP256K1_N_1; + r->d[1] = t & nonzero; t >>= 64; + t += (uint128_t)(~a->d[2]) + SECP256K1_N_2; + r->d[2] = t & nonzero; t >>= 64; + t += (uint128_t)(~a->d[3]) + SECP256K1_N_3; + r->d[3] = t & nonzero; +} + +int static inline secp256k1_scalar_is_one(const secp256k1_scalar_t *a) { + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; +} + +int static secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { + int yes = 0; + int no = 0; + no |= (a->d[3] < SECP256K1_N_H_3); + yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; + no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; // No need for a > check. + no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; + yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; + return yes; +} + +// Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. + +/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd(a,b) { \ + uint64_t tl, th; \ + { \ + uint128_t t = (uint128_t)a * b; \ + th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + c1 += th; /* overflow is handled on the next line */ \ + c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ +} + +/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ +#define muladd_fast(a,b) { \ + uint64_t tl, th; \ + { \ + uint128_t t = (uint128_t)a * b; \ + th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + c1 += th; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK(c1 >= th); \ +} + +/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd2(a,b) { \ + uint64_t tl, th; \ + { \ + uint128_t t = (uint128_t)a * b; \ + th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = t; \ + } \ + uint64_t th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \ + c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ + uint64_t tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \ + th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + c0 += tl2; /* overflow is handled on the next line */ \ + th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ + c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ + c1 += th2; /* overflow is handled on the next line */ \ + c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ +} + +/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define sumadd(a) { \ + c0 += (a); /* overflow is handled on the next line */ \ + int over = (c0 < (a)) ? 1 : 0; \ + c1 += over; /* overflow is handled on the next line */ \ + c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ +} + +/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ +#define sumadd_fast(a) { \ + c0 += (a); /* overflow is handled on the next line */ \ + c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ + VERIFY_CHECK(c2 == 0); \ +} + +/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. */ +#define extract(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = c2; \ + c2 = 0; \ +} + +/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. c2 is required to be zero. */ +#define extract_fast(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = 0; \ + VERIFY_CHECK(c2 == 0); \ +} + +void static secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l) { + uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7]; + + // 160 bit accumulator. + uint64_t c0, c1; + uint32_t c2; + + // Reduce 512 bits into 385. + // m[0..6] = l[0..3] + n[0..3] * SECP256K1_N_C. + c0 = l[0]; c1 = 0; c2 = 0; + muladd_fast(n0, SECP256K1_N_C_0); + uint64_t m0; extract_fast(m0); + sumadd_fast(l[1]); + muladd(n1, SECP256K1_N_C_0); + muladd(n0, SECP256K1_N_C_1); + uint64_t m1; extract(m1); + sumadd(l[2]); + muladd(n2, SECP256K1_N_C_0); + muladd(n1, SECP256K1_N_C_1); + sumadd(n0); + uint64_t m2; extract(m2); + sumadd(l[3]); + muladd(n3, SECP256K1_N_C_0); + muladd(n2, SECP256K1_N_C_1); + sumadd(n1); + uint64_t m3; extract(m3); + muladd(n3, SECP256K1_N_C_1); + sumadd(n2); + uint64_t m4; extract(m4); + sumadd_fast(n3); + uint64_t m5; extract_fast(m5); + VERIFY_CHECK(c0 <= 1); + uint32_t m6 = c0; + + // Reduce 385 bits into 258. + // p[0..4] = m[0..3] + m[4..6] * SECP256K1_N_C. + c0 = m0; c1 = 0; c2 = 0; + muladd_fast(m4, SECP256K1_N_C_0); + uint64_t p0; extract_fast(p0); + sumadd_fast(m1); + muladd(m5, SECP256K1_N_C_0); + muladd(m4, SECP256K1_N_C_1); + uint64_t p1; extract(p1); + sumadd(m2); + muladd(m6, SECP256K1_N_C_0); + muladd(m5, SECP256K1_N_C_1); + sumadd(m4); + uint64_t p2; extract(p2); + sumadd_fast(m3); + muladd_fast(m6, SECP256K1_N_C_1); + sumadd_fast(m5); + uint64_t p3; extract_fast(p3); + uint32_t p4 = c0 + m6; + VERIFY_CHECK(p4 <= 2); + + // Reduce 258 bits into 256. + // r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. + uint128_t c = p0 + (uint128_t)SECP256K1_N_C_0 * p4; + r->d[0] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + c += p1 + (uint128_t)SECP256K1_N_C_1 * p4; + r->d[1] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + c += p2 + (uint128_t)p4; + r->d[2] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + c += p3; + r->d[3] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + + // Final reduction of r. + secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); +} + +void static secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { + // 160 bit accumulator. + uint64_t c0 = 0, c1 = 0; + uint32_t c2 = 0; + + uint64_t l[8]; + + // l[0..7] = a[0..3] * b[0..3]. + muladd_fast(a->d[0], b->d[0]); + extract_fast(l[0]); + muladd(a->d[0], b->d[1]); + muladd(a->d[1], b->d[0]); + extract(l[1]); + muladd(a->d[0], b->d[2]); + muladd(a->d[1], b->d[1]); + muladd(a->d[2], b->d[0]); + extract(l[2]); + muladd(a->d[0], b->d[3]); + muladd(a->d[1], b->d[2]); + muladd(a->d[2], b->d[1]); + muladd(a->d[3], b->d[0]); + extract(l[3]); + muladd(a->d[1], b->d[3]); + muladd(a->d[2], b->d[2]); + muladd(a->d[3], b->d[1]); + extract(l[4]); + muladd(a->d[2], b->d[3]); + muladd(a->d[3], b->d[2]); + extract(l[5]); + muladd_fast(a->d[3], b->d[3]); + extract_fast(l[6]); + VERIFY_CHECK(c1 <= 0); + l[7] = c0; + + secp256k1_scalar_reduce_512(r, l); +} + +void static secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { + // 160 bit accumulator. + uint64_t c0 = 0, c1 = 0; + uint32_t c2 = 0; + + uint64_t l[8]; + + // l[0..7] = a[0..3] * b[0..3]. + muladd_fast(a->d[0], a->d[0]); + extract_fast(l[0]); + muladd2(a->d[0], a->d[1]); + extract(l[1]); + muladd2(a->d[0], a->d[2]); + muladd(a->d[1], a->d[1]); + extract(l[2]); + muladd2(a->d[0], a->d[3]); + muladd2(a->d[1], a->d[2]); + extract(l[3]); + muladd2(a->d[1], a->d[3]); + muladd(a->d[2], a->d[2]); + extract(l[4]); + muladd2(a->d[2], a->d[3]); + extract(l[5]); + muladd_fast(a->d[3], a->d[3]); + extract_fast(l[6]); + VERIFY_CHECK(c1 == 0); + l[7] = c0; + + secp256k1_scalar_reduce_512(r, l); +} + +#undef sumadd +#undef sumadd_fast +#undef muladd +#undef muladd_fast +#undef muladd2 +#undef extract +#undef extract_fast + +#endif diff --git a/src/scalar_8x32.h b/src/scalar_8x32.h new file mode 100644 index 0000000000..da7c63c788 --- /dev/null +++ b/src/scalar_8x32.h @@ -0,0 +1,15 @@ +// Copyright (c) 2014 Pieter Wuille +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef _SECP256K1_SCALAR_REPR_ +#define _SECP256K1_SCALAR_REPR_ + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef struct { + uint32_t d[8]; +} secp256k1_scalar_t; + +#endif diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h new file mode 100644 index 0000000000..3983edd27e --- /dev/null +++ b/src/scalar_8x32_impl.h @@ -0,0 +1,570 @@ +// Copyright (c) 2014 Pieter Wuille +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ +#define _SECP256K1_SCALAR_REPR_IMPL_H_ + +// Limbs of the secp256k1 order. +#define SECP256K1_N_0 ((uint32_t)0xD0364141UL) +#define SECP256K1_N_1 ((uint32_t)0xBFD25E8CUL) +#define SECP256K1_N_2 ((uint32_t)0xAF48A03BUL) +#define SECP256K1_N_3 ((uint32_t)0xBAAEDCE6UL) +#define SECP256K1_N_4 ((uint32_t)0xFFFFFFFEUL) +#define SECP256K1_N_5 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_6 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_7 ((uint32_t)0xFFFFFFFFUL) + +// Limbs of 2^256 minus the secp256k1 order. +#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) +#define SECP256K1_N_C_1 (~SECP256K1_N_1) +#define SECP256K1_N_C_2 (~SECP256K1_N_2) +#define SECP256K1_N_C_3 (~SECP256K1_N_3) +#define SECP256K1_N_C_4 (1) + +// Limbs of half the secp256k1 order. +#define SECP256K1_N_H_0 ((uint32_t)0x681B20A0UL) +#define SECP256K1_N_H_1 ((uint32_t)0xDFE92F46UL) +#define SECP256K1_N_H_2 ((uint32_t)0x57A4501DUL) +#define SECP256K1_N_H_3 ((uint32_t)0x5D576E73UL) +#define SECP256K1_N_H_4 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_5 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL) + +void static inline secp256k1_scalar_clear(secp256k1_scalar_t *r) { + r->d[0] = 0; + 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; +} + +int static inline secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, int offset, int count) { + VERIFY_CHECK((offset + count - 1) / 32 == offset / 32); + return (a->d[offset / 32] >> (offset % 32)) & ((1 << count) - 1); +} + +int static inline secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) { + int yes = 0; + int no = 0; + no |= (a->d[7] < SECP256K1_N_7); // No need for a > check. + no |= (a->d[6] < SECP256K1_N_6); // No need for a > check. + no |= (a->d[5] < SECP256K1_N_5); // No need for a > check. + no |= (a->d[4] < SECP256K1_N_4); + yes |= (a->d[4] > SECP256K1_N_4) & ~no; + no |= (a->d[3] < SECP256K1_N_3) & ~yes; + yes |= (a->d[3] > SECP256K1_N_3) & ~no; + no |= (a->d[2] < SECP256K1_N_2) & ~yes; + yes |= (a->d[2] > SECP256K1_N_2) & ~no; + no |= (a->d[1] < SECP256K1_N_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_1) & ~no; + yes |= (a->d[0] >= SECP256K1_N_0) & ~no; + return yes; +} + +int static inline secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint32_t overflow) { + VERIFY_CHECK(overflow <= 1); + uint64_t t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; + r->d[0] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1; + r->d[1] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[2] + overflow * SECP256K1_N_C_2; + r->d[2] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[3] + overflow * SECP256K1_N_C_3; + r->d[3] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[4] + overflow * SECP256K1_N_C_4; + r->d[4] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[5]; + r->d[5] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[6]; + r->d[6] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[7]; + r->d[7] = t & 0xFFFFFFFFUL; + return overflow; +} + +void static 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]; + r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[1] + b->d[1]; + r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[2] + b->d[2]; + r->d[2] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[3] + b->d[3]; + r->d[3] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[4] + b->d[4]; + r->d[4] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[5] + b->d[5]; + r->d[5] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[6] + b->d[6]; + r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[7] + b->d[7]; + r->d[7] = t & 0xFFFFFFFFULL; t >>= 32; + secp256k1_scalar_reduce(r, t + secp256k1_scalar_check_overflow(r)); +} + +void static secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) { + r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24; + r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24; + r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24; + r->d[3] = (uint32_t)b32[19] | (uint32_t)b32[18] << 8 | (uint32_t)b32[17] << 16 | (uint32_t)b32[16] << 24; + r->d[4] = (uint32_t)b32[15] | (uint32_t)b32[14] << 8 | (uint32_t)b32[13] << 16 | (uint32_t)b32[12] << 24; + r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24; + r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24; + r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24; + int over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); + if (overflow) { + *overflow = over; + } +} + +void static secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) { + bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7]; + bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6]; + bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5]; + bin[12] = a->d[4] >> 24; bin[13] = a->d[4] >> 16; bin[14] = a->d[4] >> 8; bin[15] = a->d[4]; + bin[16] = a->d[3] >> 24; bin[17] = a->d[3] >> 16; bin[18] = a->d[3] >> 8; bin[19] = a->d[3]; + bin[20] = a->d[2] >> 24; bin[21] = a->d[2] >> 16; bin[22] = a->d[2] >> 8; bin[23] = a->d[2]; + bin[24] = a->d[1] >> 24; bin[25] = a->d[1] >> 16; bin[26] = a->d[1] >> 8; bin[27] = a->d[1]; + bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; +} + +int static inline secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) { + return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; +} + +void static secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { + uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0); + uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1; + r->d[0] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[1]) + SECP256K1_N_1; + r->d[1] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[2]) + SECP256K1_N_2; + r->d[2] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[3]) + SECP256K1_N_3; + r->d[3] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[4]) + SECP256K1_N_4; + r->d[4] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[5]) + SECP256K1_N_5; + r->d[5] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[6]) + SECP256K1_N_6; + r->d[6] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[7]) + SECP256K1_N_7; + r->d[7] = t & nonzero; +} + +int static inline secp256k1_scalar_is_one(const secp256k1_scalar_t *a) { + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; +} + +int static secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { + int yes = 0; + int no = 0; + no |= (a->d[7] < SECP256K1_N_H_7); + yes |= (a->d[7] > SECP256K1_N_H_7) & ~no; + no |= (a->d[6] < SECP256K1_N_H_6) & ~yes; // No need for a > check. + no |= (a->d[5] < SECP256K1_N_H_5) & ~yes; // No need for a > check. + no |= (a->d[4] < SECP256K1_N_H_4) & ~yes; // No need for a > check. + no |= (a->d[3] < SECP256K1_N_H_3) & ~yes; + yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; + no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; + yes |= (a->d[2] > SECP256K1_N_H_2) & ~no; + no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; + yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; + return yes; +} + +// Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. + +/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd(a,b) { \ + uint32_t tl, th; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + c1 += th; /* overflow is handled on the next line */ \ + c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ +} + +/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ +#define muladd_fast(a,b) { \ + uint32_t tl, th; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + c1 += th; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK(c1 >= th); \ +} + +/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd2(a,b) { \ + uint32_t tl, th; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + uint32_t th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \ + c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ + uint32_t tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \ + th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + c0 += tl2; /* overflow is handled on the next line */ \ + th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ + c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ + c1 += th2; /* overflow is handled on the next line */ \ + c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ +} + +/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define sumadd(a) { \ + c0 += (a); /* overflow is handled on the next line */ \ + int over = (c0 < (a)) ? 1 : 0; \ + c1 += over; /* overflow is handled on the next line */ \ + c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ +} + +/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ +#define sumadd_fast(a) { \ + c0 += (a); /* overflow is handled on the next line */ \ + c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ + VERIFY_CHECK(c2 == 0); \ +} + +/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. */ +#define extract(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = c2; \ + c2 = 0; \ +} + +/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. c2 is required to be zero. */ +#define extract_fast(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = 0; \ + VERIFY_CHECK(c2 == 0); \ +} + +void static secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l) { + uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15]; + + // 96 bit accumulator. + uint32_t c0, c1, c2; + + // Reduce 512 bits into 385. + // m[0..12] = l[0..7] + n[0..7] * SECP256K1_N_C. + c0 = l[0]; c1 = 0; c2 = 0; + muladd_fast(n0, SECP256K1_N_C_0); + uint32_t m0; extract_fast(m0); + sumadd_fast(l[1]); + muladd(n1, SECP256K1_N_C_0); + muladd(n0, SECP256K1_N_C_1); + uint32_t m1; extract(m1); + sumadd(l[2]); + muladd(n2, SECP256K1_N_C_0); + muladd(n1, SECP256K1_N_C_1); + muladd(n0, SECP256K1_N_C_2); + uint32_t m2; extract(m2); + sumadd(l[3]); + muladd(n3, SECP256K1_N_C_0); + muladd(n2, SECP256K1_N_C_1); + muladd(n1, SECP256K1_N_C_2); + muladd(n0, SECP256K1_N_C_3); + uint32_t m3; extract(m3); + sumadd(l[4]); + muladd(n4, SECP256K1_N_C_0); + muladd(n3, SECP256K1_N_C_1); + muladd(n2, SECP256K1_N_C_2); + muladd(n1, SECP256K1_N_C_3); + sumadd(n0); + uint32_t m4; extract(m4); + sumadd(l[5]); + muladd(n5, SECP256K1_N_C_0); + muladd(n4, SECP256K1_N_C_1); + muladd(n3, SECP256K1_N_C_2); + muladd(n2, SECP256K1_N_C_3); + sumadd(n1); + uint32_t m5; extract(m5); + sumadd(l[6]); + muladd(n6, SECP256K1_N_C_0); + muladd(n5, SECP256K1_N_C_1); + muladd(n4, SECP256K1_N_C_2); + muladd(n3, SECP256K1_N_C_3); + sumadd(n2); + uint32_t m6; extract(m6); + sumadd(l[7]); + muladd(n7, SECP256K1_N_C_0); + muladd(n6, SECP256K1_N_C_1); + muladd(n5, SECP256K1_N_C_2); + muladd(n4, SECP256K1_N_C_3); + sumadd(n3); + uint32_t m7; extract(m7); + muladd(n7, SECP256K1_N_C_1); + muladd(n6, SECP256K1_N_C_2); + muladd(n5, SECP256K1_N_C_3); + sumadd(n4); + uint32_t m8; extract(m8); + muladd(n7, SECP256K1_N_C_2); + muladd(n6, SECP256K1_N_C_3); + sumadd(n5); + uint32_t m9; extract(m9); + muladd(n7, SECP256K1_N_C_3); + sumadd(n6); + uint32_t m10; extract(m10); + sumadd_fast(n7); + uint32_t m11; extract_fast(m11); + VERIFY_CHECK(c0 <= 1); + uint32_t m12 = c0; + + // Reduce 385 bits into 258. + // p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. + c0 = m0; c1 = 0; c2 = 0; + muladd_fast(m8, SECP256K1_N_C_0); + uint32_t p0; extract_fast(p0); + sumadd_fast(m1); + muladd(m9, SECP256K1_N_C_0); + muladd(m8, SECP256K1_N_C_1); + uint32_t p1; extract(p1); + sumadd(m2); + muladd(m10, SECP256K1_N_C_0); + muladd(m9, SECP256K1_N_C_1); + muladd(m8, SECP256K1_N_C_2); + uint32_t p2; extract(p2); + sumadd(m3); + muladd(m11, SECP256K1_N_C_0); + muladd(m10, SECP256K1_N_C_1); + muladd(m9, SECP256K1_N_C_2); + muladd(m8, SECP256K1_N_C_3); + uint32_t p3; extract(p3); + sumadd(m4); + muladd(m12, SECP256K1_N_C_0); + muladd(m11, SECP256K1_N_C_1); + muladd(m10, SECP256K1_N_C_2); + muladd(m9, SECP256K1_N_C_3); + sumadd(m8); + uint32_t p4; extract(p4); + sumadd(m5); + muladd(m12, SECP256K1_N_C_1); + muladd(m11, SECP256K1_N_C_2); + muladd(m10, SECP256K1_N_C_3); + sumadd(m9); + uint32_t p5; extract(p5); + sumadd(m6); + muladd(m12, SECP256K1_N_C_2); + muladd(m11, SECP256K1_N_C_3); + sumadd(m10); + uint32_t p6; extract(p6); + sumadd_fast(m7); + muladd_fast(m12, SECP256K1_N_C_3); + sumadd_fast(m11); + uint32_t p7; extract_fast(p7); + uint32_t p8 = c0 + m12; + VERIFY_CHECK(p8 <= 2); + + // Reduce 258 bits into 256. + // r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. + uint64_t c = p0 + (uint64_t)SECP256K1_N_C_0 * p8; + r->d[0] = c & 0xFFFFFFFFUL; c >>= 32; + c += p1 + (uint64_t)SECP256K1_N_C_1 * p8; + r->d[1] = c & 0xFFFFFFFFUL; c >>= 32; + c += p2 + (uint64_t)SECP256K1_N_C_2 * p8; + r->d[2] = c & 0xFFFFFFFFUL; c >>= 32; + c += p3 + (uint64_t)SECP256K1_N_C_3 * p8; + r->d[3] = c & 0xFFFFFFFFUL; c >>= 32; + c += p4 + (uint64_t)p8; + r->d[4] = c & 0xFFFFFFFFUL; c >>= 32; + c += p5; + r->d[5] = c & 0xFFFFFFFFUL; c >>= 32; + c += p6; + r->d[6] = c & 0xFFFFFFFFUL; c >>= 32; + c += p7; + r->d[7] = c & 0xFFFFFFFFUL; c >>= 32; + + // Final reduction of r. + secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); +} + +void static secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { + // 96 bit accumulator. + uint32_t c0 = 0, c1 = 0, c2 = 0; + + uint32_t l[16]; + + // l[0..15] = a[0..7] * b[0..7]. + muladd_fast(a->d[0], b->d[0]); + extract_fast(l[0]); + muladd(a->d[0], b->d[1]); + muladd(a->d[1], b->d[0]); + extract(l[1]); + muladd(a->d[0], b->d[2]); + muladd(a->d[1], b->d[1]); + muladd(a->d[2], b->d[0]); + extract(l[2]); + muladd(a->d[0], b->d[3]); + muladd(a->d[1], b->d[2]); + muladd(a->d[2], b->d[1]); + muladd(a->d[3], b->d[0]); + extract(l[3]); + muladd(a->d[0], b->d[4]); + muladd(a->d[1], b->d[3]); + muladd(a->d[2], b->d[2]); + muladd(a->d[3], b->d[1]); + muladd(a->d[4], b->d[0]); + extract(l[4]); + muladd(a->d[0], b->d[5]); + muladd(a->d[1], b->d[4]); + muladd(a->d[2], b->d[3]); + muladd(a->d[3], b->d[2]); + muladd(a->d[4], b->d[1]); + muladd(a->d[5], b->d[0]); + extract(l[5]); + muladd(a->d[0], b->d[6]); + muladd(a->d[1], b->d[5]); + muladd(a->d[2], b->d[4]); + muladd(a->d[3], b->d[3]); + muladd(a->d[4], b->d[2]); + muladd(a->d[5], b->d[1]); + muladd(a->d[6], b->d[0]); + extract(l[6]); + muladd(a->d[0], b->d[7]); + muladd(a->d[1], b->d[6]); + muladd(a->d[2], b->d[5]); + muladd(a->d[3], b->d[4]); + muladd(a->d[4], b->d[3]); + muladd(a->d[5], b->d[2]); + muladd(a->d[6], b->d[1]); + muladd(a->d[7], b->d[0]); + extract(l[7]); + muladd(a->d[1], b->d[7]); + muladd(a->d[2], b->d[6]); + muladd(a->d[3], b->d[5]); + muladd(a->d[4], b->d[4]); + muladd(a->d[5], b->d[3]); + muladd(a->d[6], b->d[2]); + muladd(a->d[7], b->d[1]); + extract(l[8]); + muladd(a->d[2], b->d[7]); + muladd(a->d[3], b->d[6]); + muladd(a->d[4], b->d[5]); + muladd(a->d[5], b->d[4]); + muladd(a->d[6], b->d[3]); + muladd(a->d[7], b->d[2]); + extract(l[9]); + muladd(a->d[3], b->d[7]); + muladd(a->d[4], b->d[6]); + muladd(a->d[5], b->d[5]); + muladd(a->d[6], b->d[4]); + muladd(a->d[7], b->d[3]); + extract(l[10]); + muladd(a->d[4], b->d[7]); + muladd(a->d[5], b->d[6]); + muladd(a->d[6], b->d[5]); + muladd(a->d[7], b->d[4]); + extract(l[11]); + muladd(a->d[5], b->d[7]); + muladd(a->d[6], b->d[6]); + muladd(a->d[7], b->d[5]); + extract(l[12]); + muladd(a->d[6], b->d[7]); + muladd(a->d[7], b->d[6]); + extract(l[13]); + muladd_fast(a->d[7], b->d[7]); + extract_fast(l[14]); + VERIFY_CHECK(c1 == 0); + l[15] = c0; + + secp256k1_scalar_reduce_512(r, l); +} + +void static secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { + // 96 bit accumulator. + uint32_t c0 = 0, c1 = 0, c2 = 0; + + uint32_t l[16]; + + // l[0..15] = a[0..7]^2. + muladd_fast(a->d[0], a->d[0]); + extract_fast(l[0]); + muladd2(a->d[0], a->d[1]); + extract(l[1]); + muladd2(a->d[0], a->d[2]); + muladd(a->d[1], a->d[1]); + extract(l[2]); + muladd2(a->d[0], a->d[3]); + muladd2(a->d[1], a->d[2]); + extract(l[3]); + muladd2(a->d[0], a->d[4]); + muladd2(a->d[1], a->d[3]); + muladd(a->d[2], a->d[2]); + extract(l[4]); + muladd2(a->d[0], a->d[5]); + muladd2(a->d[1], a->d[4]); + muladd2(a->d[2], a->d[3]); + extract(l[5]); + muladd2(a->d[0], a->d[6]); + muladd2(a->d[1], a->d[5]); + muladd2(a->d[2], a->d[4]); + muladd(a->d[3], a->d[3]); + extract(l[6]); + muladd2(a->d[0], a->d[7]); + muladd2(a->d[1], a->d[6]); + muladd2(a->d[2], a->d[5]); + muladd2(a->d[3], a->d[4]); + extract(l[7]); + muladd2(a->d[1], a->d[7]); + muladd2(a->d[2], a->d[6]); + muladd2(a->d[3], a->d[5]); + muladd(a->d[4], a->d[4]); + extract(l[8]); + muladd2(a->d[2], a->d[7]); + muladd2(a->d[3], a->d[6]); + muladd2(a->d[4], a->d[5]); + extract(l[9]); + muladd2(a->d[3], a->d[7]); + muladd2(a->d[4], a->d[6]); + muladd(a->d[5], a->d[5]); + extract(l[10]); + muladd2(a->d[4], a->d[7]); + muladd2(a->d[5], a->d[6]); + extract(l[11]); + muladd2(a->d[5], a->d[7]); + muladd(a->d[6], a->d[6]); + extract(l[12]); + muladd2(a->d[6], a->d[7]); + extract(l[13]); + muladd_fast(a->d[7], a->d[7]); + extract_fast(l[14]); + VERIFY_CHECK(c1 == 0); + l[15] = c0; + + secp256k1_scalar_reduce_512(r, l); +} + +#undef sumadd +#undef sumadd_fast +#undef muladd +#undef muladd_fast +#undef muladd2 +#undef extract +#undef extract_fast + +#endif diff --git a/src/scalar_impl.h b/src/scalar_impl.h index 6e6e8db7f1..c52328e42c 100644 --- a/src/scalar_impl.h +++ b/src/scalar_impl.h @@ -9,62 +9,174 @@ #include "scalar.h" -#include "group.h" +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif -void static secp256k1_scalar_clear(secp256k1_scalar_t *r) { - secp256k1_num_clear(&r->n); -} - -int static secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, int offset, int count) { - return secp256k1_num_get_bits(&a->n, offset, count); -} - -void static secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *bin, int *overflow) { - secp256k1_num_set_bin(&r->n, bin, 32); - if (overflow) { - *overflow = secp256k1_num_cmp(&r->n, &secp256k1_ge_consts->order) >= 0; - } - secp256k1_num_mod(&r->n, &secp256k1_ge_consts->order); -} - -void static secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) { - secp256k1_num_get_bin(bin, 32, &a->n); -} - -void static secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { - secp256k1_num_add(&r->n, &a->n, &b->n); - secp256k1_num_mod(&r->n, &secp256k1_ge_consts->order); -} - -void static secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { - secp256k1_num_mod_mul(&r->n, &a->n, &b->n, &secp256k1_ge_consts->order); -} - -void static secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { - secp256k1_num_mod_inverse(&r->n, &a->n, &secp256k1_ge_consts->order); -} - -void static secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { - secp256k1_num_sub(&r->n, &secp256k1_ge_consts->order, &a->n); - secp256k1_num_mod(&r->n, &secp256k1_ge_consts->order); -} - -int static secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) { - return secp256k1_num_is_zero(&a->n); -} - -int static secp256k1_scalar_is_one(const secp256k1_scalar_t *a) { - return secp256k1_num_bits(&a->n) == 1; -} - -int static secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { - return secp256k1_num_cmp(&a->n, &secp256k1_ge_consts->half_order) > 0; -} +#if defined(USE_SCALAR_4X64) +#include "scalar_4x64_impl.h" +#elif defined(USE_SCALAR_8X32) +#include "scalar_8x32_impl.h" +#else +#error "Please select scalar implementation" +#endif void static secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a) { unsigned char c[32]; - secp256k1_num_get_bin(c, 32, &a->n); + secp256k1_scalar_get_b32(c, a); secp256k1_num_set_bin(r, c, 32); } + +void static secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) { + // First compute x ^ (2^N - 1) for some values of N. + secp256k1_scalar_t x2, x3, x4, x6, x7, x8, x15, x30, x60, x120, x127; + + secp256k1_scalar_sqr(&x2, x); + secp256k1_scalar_mul(&x2, &x2, x); + + secp256k1_scalar_sqr(&x3, &x2); + secp256k1_scalar_mul(&x3, &x3, x); + + secp256k1_scalar_sqr(&x4, &x3); + secp256k1_scalar_mul(&x4, &x4, x); + + secp256k1_scalar_sqr(&x6, &x4); + secp256k1_scalar_sqr(&x6, &x6); + secp256k1_scalar_mul(&x6, &x6, &x2); + + secp256k1_scalar_sqr(&x7, &x6); + secp256k1_scalar_mul(&x7, &x7, x); + + secp256k1_scalar_sqr(&x8, &x7); + secp256k1_scalar_mul(&x8, &x8, x); + + secp256k1_scalar_sqr(&x15, &x8); + for (int i=0; i<6; i++) + secp256k1_scalar_sqr(&x15, &x15); + secp256k1_scalar_mul(&x15, &x15, &x7); + + secp256k1_scalar_sqr(&x30, &x15); + for (int i=0; i<14; i++) + secp256k1_scalar_sqr(&x30, &x30); + secp256k1_scalar_mul(&x30, &x30, &x15); + + secp256k1_scalar_sqr(&x60, &x30); + for (int i=0; i<29; i++) + secp256k1_scalar_sqr(&x60, &x60); + secp256k1_scalar_mul(&x60, &x60, &x30); + + secp256k1_scalar_sqr(&x120, &x60); + for (int i=0; i<59; i++) + secp256k1_scalar_sqr(&x120, &x120); + secp256k1_scalar_mul(&x120, &x120, &x60); + + secp256k1_scalar_sqr(&x127, &x120); + for (int i=0; i<6; i++) + secp256k1_scalar_sqr(&x127, &x127); + secp256k1_scalar_mul(&x127, &x127, &x7); + + // Then accumulate the final result (t starts at x127). + secp256k1_scalar_t *t = &x127; + for (int i=0; i<2; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<4; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x3); // 111 + for (int i=0; i<2; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<2; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<2; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<4; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x3); // 111 + for (int i=0; i<3; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x2); // 11 + for (int i=0; i<4; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x3); // 111 + for (int i=0; i<5; i++) // 00 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x3); // 111 + for (int i=0; i<4; i++) // 00 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x2); // 11 + for (int i=0; i<2; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<2; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<5; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x4); // 1111 + for (int i=0; i<2; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<3; i++) // 00 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<4; i++) // 000 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<2; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<10; i++) // 0000000 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x3); // 111 + for (int i=0; i<4; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x3); // 111 + for (int i=0; i<9; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x8); // 11111111 + for (int i=0; i<2; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<3; i++) // 00 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<3; i++) // 00 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<5; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x4); // 1111 + for (int i=0; i<2; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<5; i++) // 000 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x2); // 11 + for (int i=0; i<4; i++) // 00 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x2); // 11 + for (int i=0; i<2; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<8; i++) // 000000 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x2); // 11 + for (int i=0; i<3; i++) // 0 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, &x2); // 11 + for (int i=0; i<3; i++) // 00 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<6; i++) // 00000 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(t, t, x); // 1 + for (int i=0; i<8; i++) // 00 + secp256k1_scalar_sqr(t, t); + secp256k1_scalar_mul(r, t, &x6); // 111111 +} + #endif diff --git a/src/tests.c b/src/tests.c index 4b1c98f1c4..22168e0be6 100644 --- a/src/tests.c +++ b/src/tests.c @@ -373,6 +373,14 @@ void scalar_test(void) { secp256k1_scalar_add(&r2, &r2, &t); CHECK(secp256k1_scalar_eq(&r1, &r2)); } + + { + // Test square. + secp256k1_scalar_t r1, r2; + secp256k1_scalar_sqr(&r1, &s1); + secp256k1_scalar_mul(&r2, &s1, &s1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } } void run_scalar_tests(void) {