Implementations for scalar without data-dependent branches.

This commit is contained in:
Pieter Wuille 2014-10-29 00:35:49 -07:00
parent 0ce80ef47e
commit 1d52a8b155
10 changed files with 1194 additions and 57 deletions

View File

@ -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

View File

@ -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

View File

@ -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])

View File

@ -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);

15
src/scalar_4x64.h Normal file
View File

@ -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 <stdint.h>
/** A scalar modulo the group order of the secp256k1 curve. */
typedef struct {
uint64_t d[4];
} secp256k1_scalar_t;
#endif

357
src/scalar_4x64_impl.h Normal file
View File

@ -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

15
src/scalar_8x32.h Normal file
View File

@ -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 <stdint.h>
/** A scalar modulo the group order of the secp256k1 curve. */
typedef struct {
uint32_t d[8];
} secp256k1_scalar_t;
#endif

570
src/scalar_8x32_impl.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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) {