Commit 3ddc1097 authored by obscuren's avatar obscuren

Merge branch 'Gustav-Simonsson-update_bitcoin_secp256k1_lib2' into develop

parents 0196a973 50bbdfe5
package secp256k1 package secp256k1
// TODO: set USE_SCALAR_4X64 depending on platform?
/* /*
#cgo CFLAGS: -std=gnu99 -Wno-error #cgo CFLAGS: -I./secp256k1
#cgo darwin CFLAGS: -I/usr/local/include #cgo darwin CFLAGS: -I/usr/local/include
#cgo LDFLAGS: -lgmp #cgo LDFLAGS: -lgmp
#cgo darwin LDFLAGS: -L/usr/local/lib #cgo darwin LDFLAGS: -L/usr/local/lib
#define USE_FIELD_10X26
#define USE_NUM_GMP #define USE_NUM_GMP
#define USE_FIELD_10X26
#define USE_FIELD_INV_BUILTIN #define USE_FIELD_INV_BUILTIN
#define USE_SCALAR_8X32
#define USE_SCALAR_INV_BUILTIN
#include "./secp256k1/src/secp256k1.c" #include "./secp256k1/src/secp256k1.c"
*/ */
import "C" import "C"
...@@ -38,32 +42,14 @@ import ( ...@@ -38,32 +42,14 @@ import (
*/ */
func init() { func init() {
C.secp256k1_start() //takes 10ms to 100ms //takes 10ms to 100ms
C.secp256k1_start(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY
} }
func Stop() { func Stop() {
C.secp256k1_stop() C.secp256k1_stop()
} }
/*
int secp256k1_ecdsa_pubkey_create(
unsigned char *pubkey, int *pubkeylen,
const unsigned char *seckey, int compressed);
*/
/** Compute the public key for a secret key.
* In: compressed: whether the computed public key should be compressed
* seckey: pointer to a 32-byte private key.
* Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
* area to store the public key.
* pubkeylen: pointer to int that will be updated to contains the pubkey's
* length.
* Returns: 1: secret was valid, public key stores
* 0: secret was invalid, try again.
*/
//pubkey, seckey
func GenerateKeyPair() ([]byte, []byte) { func GenerateKeyPair() ([]byte, []byte) {
pubkey_len := C.int(65) pubkey_len := C.int(65)
...@@ -75,7 +61,7 @@ func GenerateKeyPair() ([]byte, []byte) { ...@@ -75,7 +61,7 @@ func GenerateKeyPair() ([]byte, []byte) {
var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0])) var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
ret := C.secp256k1_ecdsa_pubkey_create( ret := C.secp256k1_ec_pubkey_create(
pubkey_ptr, &pubkey_len, pubkey_ptr, &pubkey_len,
seckey_ptr, 0) seckey_ptr, 0)
...@@ -98,7 +84,7 @@ func GeneratePubKey(seckey []byte) ([]byte, error) { ...@@ -98,7 +84,7 @@ func GeneratePubKey(seckey []byte) ([]byte, error) {
var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0])) var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
ret := C.secp256k1_ecdsa_pubkey_create( ret := C.secp256k1_ec_pubkey_create(
pubkey_ptr, &pubkey_len, pubkey_ptr, &pubkey_len,
seckey_ptr, 0) seckey_ptr, 0)
...@@ -109,26 +95,6 @@ func GeneratePubKey(seckey []byte) ([]byte, error) { ...@@ -109,26 +95,6 @@ func GeneratePubKey(seckey []byte) ([]byte, error) {
return pubkey, nil return pubkey, nil
} }
/*
* Create a compact ECDSA signature (64 byte + recovery id).
* Returns: 1: signature created
* 0: nonce invalid, try another one
* In: msg: the message being signed
* msglen: the length of the message being signed
* seckey: pointer to a 32-byte secret key (assumed to be valid)
* nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG)
* Out: sig: pointer to a 64-byte array where the signature will be placed.
* recid: pointer to an int, which will be updated to contain the recovery id.
*/
/*
int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen,
unsigned char *sig64,
const unsigned char *seckey,
const unsigned char *nonce,
int *recid);
*/
func Sign(msg []byte, seckey []byte) ([]byte, error) { func Sign(msg []byte, seckey []byte) ([]byte, error) {
nonce := randentropy.GetEntropyMixed(32) nonce := randentropy.GetEntropyMixed(32)
...@@ -136,19 +102,22 @@ func Sign(msg []byte, seckey []byte) ([]byte, error) { ...@@ -136,19 +102,22 @@ func Sign(msg []byte, seckey []byte) ([]byte, error) {
var recid C.int var recid C.int
var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0])) var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0]))
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
var nonce_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&nonce[0]))
var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0])) var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0]))
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
var noncefp_ptr = &(*C.secp256k1_nonce_function_default)
var ndata_ptr = unsafe.Pointer(&nonce[0])
if C.secp256k1_ecdsa_seckey_verify(seckey_ptr) != C.int(1) { if C.secp256k1_ec_seckey_verify(seckey_ptr) != C.int(1) {
return nil, errors.New("Invalid secret key") return nil, errors.New("Invalid secret key")
} }
ret := C.secp256k1_ecdsa_sign_compact( ret := C.secp256k1_ecdsa_sign_compact(
msg_ptr, C.int(len(msg)), msg_ptr,
sig_ptr, sig_ptr,
seckey_ptr, seckey_ptr,
nonce_ptr, noncefp_ptr,
ndata_ptr,
&recid) &recid)
sig[64] = byte(int(recid)) sig[64] = byte(int(recid))
...@@ -162,37 +131,24 @@ func Sign(msg []byte, seckey []byte) ([]byte, error) { ...@@ -162,37 +131,24 @@ func Sign(msg []byte, seckey []byte) ([]byte, error) {
} }
/*
* Verify an ECDSA secret key.
* Returns: 1: secret key is valid
* 0: secret key is invalid
* In: seckey: pointer to a 32-byte secret key
*/
func VerifySeckeyValidity(seckey []byte) error { func VerifySeckeyValidity(seckey []byte) error {
if len(seckey) != 32 { if len(seckey) != 32 {
return errors.New("priv key is not 32 bytes") return errors.New("priv key is not 32 bytes")
} }
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
ret := C.secp256k1_ecdsa_seckey_verify(seckey_ptr) ret := C.secp256k1_ec_seckey_verify(seckey_ptr)
if int(ret) != 1 { if int(ret) != 1 {
return errors.New("invalid seckey") return errors.New("invalid seckey")
} }
return nil return nil
} }
/*
* Validate a public key.
* Returns: 1: valid public key
* 0: invalid public key
*/
func VerifyPubkeyValidity(pubkey []byte) error { func VerifyPubkeyValidity(pubkey []byte) error {
if len(pubkey) != 65 { if len(pubkey) != 65 {
return errors.New("pub key is not 65 bytes") return errors.New("pub key is not 65 bytes")
} }
var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0])) var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
ret := C.secp256k1_ecdsa_pubkey_verify(pubkey_ptr, 65) ret := C.secp256k1_ec_pubkey_verify(pubkey_ptr, 65)
if int(ret) != 1 { if int(ret) != 1 {
return errors.New("invalid pubkey") return errors.New("invalid pubkey")
} }
...@@ -254,25 +210,6 @@ func VerifySignature(msg []byte, sig []byte, pubkey1 []byte) error { ...@@ -254,25 +210,6 @@ func VerifySignature(msg []byte, sig []byte, pubkey1 []byte) error {
return nil return nil
} }
/*
int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen,
const unsigned char *sig64,
unsigned char *pubkey, int *pubkeylen,
int compressed, int recid);
*/
/*
* Recover an ECDSA public key from a compact signature.
* Returns: 1: public key succesfully recovered (which guarantees a correct signature).
* 0: otherwise.
* In: msg: the message assumed to be signed
* msglen: the length of the message
* compressed: whether to recover a compressed or uncompressed pubkey
* recid: the recovery id (as returned by ecdsa_sign_compact)
* Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey.
* pubkeylen: pointer to an int that will contain the pubkey length.
*/
//recovers the public key from the signature //recovers the public key from the signature
//recovery of pubkey means correct signature //recovery of pubkey means correct signature
func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) { func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
...@@ -289,10 +226,12 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) { ...@@ -289,10 +226,12 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
var pubkeylen C.int var pubkeylen C.int
ret := C.secp256k1_ecdsa_recover_compact( ret := C.secp256k1_ecdsa_recover_compact(
msg_ptr, C.int(len(msg)), msg_ptr,
sig_ptr, sig_ptr,
pubkey_ptr, &pubkeylen, pubkey_ptr,
C.int(0), C.int(sig[64]), &pubkeylen,
C.int(0),
C.int(sig[64]),
) )
if ret == C.int(0) { if ret == C.int(0) {
......
language: c
compiler:
- clang
- gcc
install:
- sudo apt-get install -qq libssl-dev
- if [ "$BIGNUM" = "gmp" -o "$BIGNUM" = "auto" ]; then sudo apt-get install --no-install-recommends --no-upgrade -qq libgmp-dev; fi
- if [ -n "$EXTRAPACKAGES" ]; then sudo apt-get update && sudo apt-get install --no-install-recommends --no-upgrade $EXTRAPACKAGES; fi
env:
global:
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no ASM=no BUILD=check EXTRAFLAGS= HOST= EXTRAPACKAGES=
matrix:
- SCALAR=32bit
- SCALAR=64bit
- FIELD=64bit
- FIELD=64bit ENDOMORPHISM=yes
- FIELD=64bit ASM=x86_64
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
- FIELD=32bit
- FIELD=32bit ENDOMORPHISM=yes
- BIGNUM=no
- BIGNUM=no ENDOMORPHISM=yes
- BUILD=distcheck
- EXTRAFLAGS=CFLAGS=-DDETERMINISTIC
- HOST=i686-linux-gnu EXTRAPACKAGES="gcc-multilib"
- HOST=i686-linux-gnu EXTRAPACKAGES="gcc-multilib" ENDOMORPHISM=yes
before_script: ./autogen.sh
script:
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
- ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
os: linux
$(shell CC=$(CC) YASM=$(YASM) ./configure)
include config.mk
FILES := src/*.h src/impl/*.h
JAVA_FILES := src/java/org_bitcoin_NativeSecp256k1.h src/java/org_bitcoin_NativeSecp256k1.c
OBJS :=
ifeq ($(USE_ASM), 1)
OBJS := $(OBJS) obj/field_5x$(HAVE_LIMB)_asm.o
endif
STD="gnu99"
default: tests libsecp256k1.a libsecp256k1.so
clean:
rm -rf obj/*.o bench tests *.a *.so config.mk
obj/field_5x52_asm.o: src/field_5x52_asm.asm
$(YASM) -f elf64 -o obj/field_5x52_asm.o src/field_5x52_asm.asm
obj/field_5x64_asm.o: src/field_5x64_asm.asm
$(YASM) -f elf64 -o obj/field_5x64_asm.o src/field_5x64_asm.asm
obj/secp256k1.o: $(FILES) src/secp256k1.c include/secp256k1.h
$(CC) -fPIC -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) -DNDEBUG -$(OPTLEVEL) src/secp256k1.c -c -o obj/secp256k1.o
bench: $(FILES) src/bench.c $(OBJS)
$(CC) -fPIC -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DNDEBUG -$(OPTLEVEL) src/bench.c $(OBJS) $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o bench
tests: $(FILES) src/tests.c $(OBJS)
$(CC) -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DVERIFY -fstack-protector-all -$(OPTLEVEL) -ggdb3 src/tests.c $(OBJS) $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o tests
tests_fuzzer: $(FILES) src/tests_fuzzer.c obj/secp256k1.o $(OBJS)
$(CC) -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DVERIFY -fstack-protector-all -$(OPTLEVEL) -ggdb3 src/tests_fuzzer.c $(OBJS) obj/secp256k1.o $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o tests_fuzzer
coverage: $(FILES) src/tests.c $(OBJS)
rm -rf tests.gcno tests.gcda tests_cov
$(CC) -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) $(CFLAGS_TEST_EXTRA) -DVERIFY --coverage -$(OPTLEVEL) -g src/tests.c $(OBJS) $(LDFLAGS_EXTRA) $(LDFLAGS_TEST_EXTRA) -o tests_cov
rm -rf lcov
mkdir -p lcov
cd lcov; lcov --directory ../ --zerocounters
cd lcov; ../tests_cov
cd lcov; lcov --directory ../ --capture --output-file secp256k1.info
cd lcov; genhtml -o . secp256k1.info
libsecp256k1.a: obj/secp256k1.o $(OBJS)
$(AR) -rs $@ $(OBJS) obj/secp256k1.o
libsecp256k1.so: obj/secp256k1.o $(OBJS)
$(CC) -std=$(STD) $(LDFLAGS_EXTRA) $(OBJS) obj/secp256k1.o -shared -o libsecp256k1.so
libjavasecp256k1.so: $(OBJS) obj/secp256k1.o $(JAVA_FILES)
$(CC) -fPIC -std=$(STD) $(CFLAGS) $(CFLAGS_EXTRA) -DNDEBUG -$(OPTLEVEL) -I. src/java/org_bitcoin_NativeSecp256k1.c $(LDFLAGS_EXTRA) $(OBJS) obj/secp256k1.o -shared -o libjavasecp256k1.so
ACLOCAL_AMFLAGS = -I build-aux/m4
lib_LTLIBRARIES = libsecp256k1.la
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
noinst_HEADERS += src/num_gmp_impl.h
noinst_HEADERS += src/ecdsa.h
noinst_HEADERS += src/ecdsa_impl.h
noinst_HEADERS += src/eckey.h
noinst_HEADERS += src/eckey_impl.h
noinst_HEADERS += src/ecmult.h
noinst_HEADERS += src/ecmult_impl.h
noinst_HEADERS += src/ecmult_gen.h
noinst_HEADERS += src/ecmult_gen_impl.h
noinst_HEADERS += src/num.h
noinst_HEADERS += src/num_impl.h
noinst_HEADERS += src/field_10x26.h
noinst_HEADERS += src/field_10x26_impl.h
noinst_HEADERS += src/field_5x52.h
noinst_HEADERS += src/field_5x52_impl.h
noinst_HEADERS += src/field_5x52_int128_impl.h
noinst_HEADERS += src/field_5x52_asm_impl.h
noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h
noinst_HEADERS += src/util.h
noinst_HEADERS += src/testrand.h
noinst_HEADERS += src/testrand_impl.h
noinst_HEADERS += src/hash.h
noinst_HEADERS += src/hash_impl.h
noinst_HEADERS += src/field.h
noinst_HEADERS += src/field_impl.h
noinst_HEADERS += src/bench.h
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libsecp256k1.pc
libsecp256k1_la_SOURCES = src/secp256k1.c
libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include $(SECP_INCLUDES)
libsecp256k1_la_LIBADD = $(SECP_LIBS)
noinst_PROGRAMS =
if USE_BENCHMARK
noinst_PROGRAMS += bench_verify bench_recover bench_sign bench_internal
bench_verify_SOURCES = src/bench_verify.c
bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
bench_verify_LDFLAGS = -static
bench_recover_SOURCES = src/bench_recover.c
bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS)
bench_recover_LDFLAGS = -static
bench_sign_SOURCES = src/bench_sign.c
bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS)
bench_sign_LDFLAGS = -static
bench_internal_SOURCES = src/bench_internal.c
bench_internal_LDADD = $(SECP_LIBS)
bench_internal_LDFLAGS = -static
bench_internal_CPPFLAGS = $(SECP_INCLUDES)
endif
if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
tests_CPPFLAGS = -DVERIFY $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS)
tests_LDFLAGS = -static
TESTS = tests
endif
EXTRA_DIST = autogen.sh
libsecp256k1
============
[![Build Status](https://travis-ci.org/bitcoin/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin/secp256k1)
Optimized C library for EC operations on curve secp256k1.
This library is a work in progress and is being used to research best practices. Use at your own risk.
Features:
* secp256k1 ECDSA signing/verification and key generation.
* Adding/multiplying private/public keys.
* Serialization/parsing of private keys, public keys, signatures.
* Constant time, constant memory access signing and pubkey generation.
* Derandomized DSA (via RFC6979 or with a caller provided function.)
* Very efficient implementation.
Implementation details
----------------------
* General
* No runtime heap allocation.
* Extensive testing infrastructure.
* Structured to facilitate review and analysis.
* Intended to be portable to any system with a C89 compiler and uint64_t support.
* Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.")
* Field operations
* Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
* Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys).
* Using 10 26-bit limbs.
* Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman).
* Scalar operations
* Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
* Using 4 64-bit limbs (relying on __int128 support in the compiler).
* Using 8 32-bit limbs.
* Group operations
* Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7).
* Use addition between points in Jacobian and affine coordinates where possible.
* Use a unified addition/doubling formula where necessary to avoid data-dependent branches.
* Point/x comparison without a field inversion by comparison in the Jacobian coordinate space.
* Point multiplication for verification (a*P + b*G).
* Use wNAF notation for point multiplicands.
* Use a much larger window for multiples of G, using precomputed multiples.
* Use Shamir's trick to do the multiplication with the public key and the generator simultaneously.
* Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.
* Point multiplication for signing
* Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions.
* Access the table with branch-free conditional moves so memory access is uniform.
* No data-dependent branches
* The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally.
Build steps
-----------
libsecp256k1 is built using autotools:
$ ./autogen.sh
$ ./configure
$ make
$ ./tests
$ sudo make install # optional
#!/bin/sh
set -e
autoreconf -if --warnings=all
dnl libsecp25k1 helper checks
AC_DEFUN([SECP_INT128_CHECK],[
has_int128=$ac_cv_type___int128
])
dnl
AC_DEFUN([SECP_64BIT_ASM_CHECK],[
AC_MSG_CHECKING(for x86_64 assembly availability)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <stdint.h>]],[[
uint64_t a = 11, tmp;
__asm__ __volatile__("movq $0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
]])],[has_64bit_asm=yes],[has_64bit_asm=no])
AC_MSG_RESULT([$has_64bit_asm])
])
dnl
AC_DEFUN([SECP_OPENSSL_CHECK],[
if test x"$use_pkgconfig" = x"yes"; then
: #NOP
m4_ifdef([PKG_CHECK_MODULES],[
PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no])
if test x"$has_libcrypto" = x"yes"; then
TEMP_LIBS="$LIBS"
LIBS="$LIBS $CRYPTO_LIBS"
AC_CHECK_LIB(crypto, main,[AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])],[has_libcrypto=no])
LIBS="$TEMP_LIBS"
fi
])
else
AC_CHECK_HEADER(openssl/crypto.h,[AC_CHECK_LIB(crypto, main,[has_libcrypto=yes; CRYPTO_LIBS=-lcrypto; AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])]
)])
LIBS=
fi
if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
AC_MSG_CHECKING(for EC functions in libcrypto)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>]],[[
EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
ECDSA_sign(0, NULL, 0, NULL, NULL, eckey);
ECDSA_verify(0, NULL, 0, NULL, 0, eckey);
EC_KEY_free(eckey);
]])],[has_openssl_ec=yes],[has_openssl_ec=no])
AC_MSG_RESULT([$has_openssl_ec])
fi
])
dnl
AC_DEFUN([SECP_GMP_CHECK],[
if test x"$has_gmp" != x"yes"; then
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
])
CC=cc
YASM=yasm
CFLAGS_EXTRA=-DUSE_FIELD_5X52 -DUSE_FIELD_5X52_ASM -DUSE_NUM_GMP -DUSE_FIELD_INV_NUM
CFLAGS_TEST_EXTRA=-DENABLE_OPENSSL_TESTS
LDFLAGS_EXTRA=-lgmp
LDFLAGS_TEST_EXTRA=-lcrypto
USE_ASM=1
HAVE_LIMB=52
OPTLEVEL=O2
#!/bin/sh
if test -f config.mk; then
exit 0
fi
if test -z "$CC"; then
CC=cc
fi
if test -z "$YASM"; then
YASM=yasm
fi
# test yasm
$YASM -f elf64 -o /tmp/secp256k1-$$.o - <<EOF
BITS 64
GLOBAL testyasm
ALIGN 32
testyasm:
xor r9,r9
EOF
if [ "$?" = 0 ]; then
$CC $CFLAGS -std=c99 -x c -c - -o /tmp/secp256k1-$$-2.o 2>/dev/null <<EOF
void __attribute__ ((sysv_abi)) testyasm(void);
int main() {
testyasm();
return 0;
}
EOF
$CC $CFLAGS -std=c99 /tmp/secp256k1-$$-2.o /tmp/secp256k1-$$.o -o /dev/null 2>/dev/null
if [ "$?" = 0 ]; then
HAVE_YASM=1
fi
rm -rf /tmp/secp256k1-$$-2.o /tmp/secp256k1-$$.o
fi
# test openssl
HAVE_OPENSSL=0
$CC $CFLAGS -std=c99 -x c - -o /dev/null -lcrypto 2>/dev/null <<EOF
#include <openssl/bn.h>
int main() {
BN_CTX *ctx = BN_CTX_new();
BN_CTX_free(ctx);
return 0;
}
EOF
if [ "$?" = 0 ]; then
HAVE_OPENSSL=1
fi
# test openssl/EC
HAVE_OPENSSL_EC=0
if [ "$HAVE_OPENSSL" = "1" ]; then
$CC $CFLAGS -std=c99 -x c - -o /dev/null -lcrypto 2>/dev/null <<EOF
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
int main() {
EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
ECDSA_sign(0, NULL, 0, NULL, NULL, eckey);
ECDSA_verify(0, NULL, 0, NULL, 0, eckey);
EC_KEY_free(eckey);
return 0;
}
EOF
if [ "$?" = 0 ]; then
HAVE_OPENSSL_EC=1
fi
fi
# test gmp
HAVE_GMP=0
$CC $CFLAGS -std=c99 -x c - -o /dev/null -lgmp 2>/dev/null <<EOF
#include <gmp.h>
int main() {
mpz_t n;
mpz_init(n);
mpz_clear(n);
return 0;
}
EOF
if [ "$?" = 0 ]; then
HAVE_GMP=1
fi
# test __int128
HAVE_INT128=0
$CC $CFLAGS -std=c99 -x c - -o /dev/null 2>/dev/null <<EOF
#include <stdint.h>
int main() {
__int128 x = 0;
return 0;
}
EOF
if [ "$?" = 0 ]; then
HAVE_INT128=1
fi
#default limb size
HAVE_LIMB=52
for arg in "$@"; do
case "$arg" in
--no-yasm)
HAVE_YASM=0
;;
--no-gmp)
HAVE_GMP=0
;;
--no-openssl)
HAVE_OPENSSL=0
;;
--use-5x64)
HAVE_LIMB=64
;;
esac
done
LINK_OPENSSL=0
LINK_GMP=0
USE_ASM=0
# select field implementation
if [ "$HAVE_YASM" = "1" ]; then
CFLAGS_FIELD="-DUSE_FIELD_5X$HAVE_LIMB -DUSE_FIELD_5X${HAVE_LIMB}_ASM"
USE_ASM=1
elif [ "$HAVE_INT128" = "1" ]; then
CFLAGS_FIELD="-DUSE_FIELD_5X$HAVE_LIMB -DUSE_FIELD_5X${HAVE_LIMB}_INT128"
elif [ "$HAVE_GMP" = "1" ]; then
CFLAGS_FIELD="-DUSE_FIELD_GMP"
LINK_GMP=1
else
CFLAGS_FIELD="-DUSE_FIELD_10X26"
fi
# select num implementation
if [ "$HAVE_GMP" = "1" ]; then
CFLAGS_NUM="-DUSE_NUM_GMP -DUSE_FIELD_INV_NUM"
LINK_GMP=1
elif [ "$HAVE_OPENSSL" = "1" ]; then
CFLAGS_NUM="-DUSE_NUM_OPENSSL -DUSE_FIELD_INV_BUILTIN"
LINK_OPENSSL=1
else
echo "No usable num implementation found" >&2
exit 1
fi
CFLAGS_EXTRA="$CFLAGS_FIELD $CFLAGS_NUM"
LDFLAGS_EXTRA=""
if [ "$LINK_GMP" = "1" ]; then
LDFLAGS_EXTRA="-lgmp"
fi
if [ "$LINK_OPENSSL" = "1" ]; then
LDFLAGS_EXTRA="-lcrypto"
else
if [ "$HAVE_OPENSSL_EC" = "1" ]; then
LDFLAGS_TEST_EXTRA="-lcrypto"
fi
fi
CFLAGS_TEST_EXTRA=""
if [ "$HAVE_OPENSSL_EC" = "1" ]; then
CFLAGS_TEST_EXTRA="-DENABLE_OPENSSL_TESTS"
fi
echo "CC=$CC" > config.mk
echo "YASM=$YASM" >>config.mk
echo "CFLAGS_EXTRA=$CFLAGS_EXTRA" >> config.mk
echo "CFLAGS_TEST_EXTRA=$CFLAGS_TEST_EXTRA" >> config.mk
echo "LDFLAGS_EXTRA=$LDFLAGS_EXTRA" >> config.mk
echo "LDFLAGS_TEST_EXTRA=$LDFLAGS_TEST_EXTRA" >> config.mk
echo "USE_ASM=$USE_ASM" >>config.mk
echo "HAVE_LIMB=$HAVE_LIMB" >>config.mk
echo "OPTLEVEL=O2" >>config.mk
AC_PREREQ([2.60])
AC_INIT([libsecp256k1],[0.1])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4])
AC_CANONICAL_HOST
AH_TOP([#ifndef LIBSECP256K1_CONFIG_H])
AH_TOP([#define LIBSECP256K1_CONFIG_H])
AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
AM_INIT_AUTOMAKE([foreign subdir-objects])
LT_INIT
dnl make the compilation flags quiet unless V=1 is used
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
PKG_PROG_PKG_CONFIG
AC_PATH_TOOL(AR, ar)
AC_PATH_TOOL(RANLIB, ranlib)
AC_PATH_TOOL(STRIP, strip)
if test "x$CFLAGS" = "x"; then
CFLAGS="-O3 -g"
fi
AC_PROG_CC_C89
if test x"$ac_cv_prog_cc_c89" = x"no"; then
AC_MSG_ERROR([c89 compiler support required])
fi
case $host in
*mingw*)
use_pkgconfig=no
;;
*)
use_pkgconfig=yes
;;
esac
case $host_os in
*darwin*)
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"
fi
fi
fi
;;
esac
CFLAGS="$CFLAGS -W"
warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings"
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $warn_CFLAGS"
AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
CFLAGS="$saved_CFLAGS"
])
AC_ARG_ENABLE(benchmark,
AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]),
[use_benchmark=$enableval],
[use_benchmark=no])
AC_ARG_ENABLE(tests,
AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]),
[use_tests=$enableval],
[use_tests=yes])
AC_ARG_ENABLE(endomorphism,
AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]),
[use_endomorphism=$enableval],
[use_endomorphism=no])
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|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_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|no|auto]
[Specify assembly optimizations to use. Default is auto])],[req_asm=$withval], [req_asm=auto])
AC_CHECK_TYPES([__int128])
AC_MSG_CHECKING([for __builtin_expect])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
[ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ],
[ AC_MSG_RESULT([no])
])
if test x"$req_asm" = x"auto"; then
SECP_64BIT_ASM_CHECK
if test x"$has_64bit_asm" = x"yes"; then
set_asm=x86_64
fi
if test x"$set_asm" = x; then
set_asm=no
fi
else
set_asm=$req_asm
case $set_asm in
x86_64)
SECP_64BIT_ASM_CHECK
if test x"$has_64bit_asm" != x"yes"; then
AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
fi
;;
no)
;;
*)
AC_MSG_ERROR([invalid assembly optimization selection])
;;
esac
fi
if test x"$req_field" = x"auto"; then
if test x"set_asm" = x"x86_64"; then
set_field=64bit
fi
if test x"$set_field" = x; then
SECP_INT128_CHECK
if test x"$has_int128" = x"yes"; then
set_field=64bit
fi
fi
if test x"$set_field" = x; then
set_field=32bit
fi
else
set_field=$req_field
case $set_field in
64bit)
if test x"$set_asm" != x"x86_64"; then
SECP_INT128_CHECK
if test x"$has_int128" != x"yes"; then
AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available])
fi
fi
;;
32bit)
;;
*)
AC_MSG_ERROR([invalid field implementation selection])
;;
esac
fi
if test x"$req_scalar" = x"auto"; then
SECP_INT128_CHECK
if test x"$has_int128" = x"yes"; then
set_scalar=64bit
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
if test x"$has_int128" != x"yes"; then
AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available])
fi
;;
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
set_bignum=gmp
fi
if test x"$set_bignum" = x; then
set_bignum=no
fi
else
set_bignum=$req_bignum
case $set_bignum in
gmp)
SECP_GMP_CHECK
if test x"$has_gmp" != x"yes"; then
AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available])
fi
;;
no)
;;
*)
AC_MSG_ERROR([invalid bignum implementation selection])
;;
esac
fi
# select assembly optimization
case $set_asm in
x86_64)
AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations])
;;
no)
;;
*)
AC_MSG_ERROR([invalid assembly optimizations])
;;
esac
# select field implementation
case $set_field in
64bit)
AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation])
;;
32bit)
AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation])
;;
*)
AC_MSG_ERROR([invalid field implementation])
;;
esac
# select bignum implementation
case $set_bignum in
gmp)
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 for num])
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])
;;
no)
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])
;;
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
AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
SECP_TEST_LIBS="$CRYPTO_LIBS"
case $host in
*mingw*)
SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32"
;;
esac
fi
fi
if test x"$set_bignum" = x"gmp"; then
SECP_LIBS="$SECP_LIBS $GMP_LIBS"
SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS"
fi
if test x"$use_endomorphism" = x"yes"; then
AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization])
fi
AC_C_BIGENDIAN()
AC_MSG_NOTICE([Using assembly optimizations: $set_asm])
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_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
AC_SUBST(SECP_INCLUDES)
AC_SUBST(SECP_LIBS)
AC_SUBST(SECP_TEST_LIBS)
AC_SUBST(SECP_TEST_INCLUDES)
AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
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
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libsecp256k1
Description: Optimized C library for EC operations on curve secp256k1
URL: https://github.com/bitcoin/secp256k1
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
Libs.private: @SECP_LIBS@
Libs: -L${libdir} -lsecp256k1
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <stdio.h>
#include "impl/num.h"
#include "impl/field.h"
#include "impl/group.h"
#include "impl/ecmult.h"
#include "impl/ecdsa.h"
#include "impl/util.h"
void random_num_order(secp256k1_num_t *num) {
do {
unsigned char b32[32];
secp256k1_rand256(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);
}
int main() {
secp256k1_fe_start();
secp256k1_ge_start();
secp256k1_ecmult_start();
secp256k1_fe_t x;
const secp256k1_num_t *order = &secp256k1_ge_consts->order;
secp256k1_num_t r, s, m;
secp256k1_num_init(&r);
secp256k1_num_init(&s);
secp256k1_num_init(&m);
secp256k1_ecdsa_sig_t sig;
secp256k1_ecdsa_sig_init(&sig);
secp256k1_fe_set_hex(&x, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64);
int cnt = 0;
int good = 0;
for (int i=0; i<1000000; i++) {
random_num_order(&r);
random_num_order(&s);
random_num_order(&m);
secp256k1_ecdsa_sig_set_rs(&sig, &r, &s);
secp256k1_ge_t pubkey; secp256k1_ge_set_xo(&pubkey, &x, 1);
if (secp256k1_ge_is_valid(&pubkey)) {
cnt++;
good += secp256k1_ecdsa_sig_verify(&sig, &pubkey, &m);
}
}
printf("%i/%i\n", good, cnt);
secp256k1_num_free(&r);
secp256k1_num_free(&s);
secp256k1_num_free(&m);
secp256k1_ecdsa_sig_free(&sig);
secp256k1_ecmult_stop();
secp256k1_ge_stop();
secp256k1_fe_stop();
return 0;
}
/**********************************************************************
* 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_BENCH_H_
#define _SECP256K1_BENCH_H_
#include <stdio.h>
#include <math.h>
#include "sys/time.h"
static double gettimedouble(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_usec * 0.000001 + tv.tv_sec;
}
void print_number(double x) {
double y = x;
int c = 0;
if (y < 0.0) y = -y;
while (y < 100.0) {
y *= 10.0;
c++;
}
printf("%.*f", c, x);
}
void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) {
int i;
double min = HUGE_VAL;
double sum = 0.0;
double max = 0.0;
for (i = 0; i < count; i++) {
double begin, total;
if (setup) setup(data);
begin = gettimedouble();
benchmark(data);
total = gettimedouble() - begin;
if (teardown) teardown(data);
if (total < min) min = total;
if (total > max) max = total;
sum += total;
}
printf("%s: min ", name);
print_number(min * 1000000.0 / iter);
printf("us / avg ");
print_number((sum / count) * 1000000.0 / iter);
printf("us / avg ");
print_number(max * 1000000.0 / iter);
printf("us\n");
}
#endif
This diff is collapsed.
/**********************************************************************
* 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.*
**********************************************************************/
#include "include/secp256k1.h"
#include "util.h"
#include "bench.h"
typedef struct {
unsigned char msg[32];
unsigned char sig[64];
} bench_recover_t;
void bench_recover(void* arg) {
int i;
bench_recover_t *data = (bench_recover_t*)arg;
unsigned char pubkey[33];
for (i = 0; i < 20000; i++) {
int j;
int pubkeylen = 33;
CHECK(secp256k1_ecdsa_recover_compact(data->msg, data->sig, pubkey, &pubkeylen, 1, i % 2));
for (j = 0; j < 32; j++) {
data->sig[j + 32] = data->msg[j]; /* Move former message to S. */
data->msg[j] = data->sig[j]; /* Move former R to message. */
data->sig[j] = pubkey[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */
}
}
}
void bench_recover_setup(void* arg) {
int i;
bench_recover_t *data = (bench_recover_t*)arg;
for (i = 0; i < 32; i++) data->msg[i] = 1 + i;
for (i = 0; i < 64; i++) data->sig[i] = 65 + i;
}
int main(void) {
bench_recover_t data;
secp256k1_start(SECP256K1_START_VERIFY);
run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, 20000);
secp256k1_stop();
return 0;
}
/**********************************************************************
* 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.*
**********************************************************************/
#include "include/secp256k1.h"
#include "util.h"
#include "bench.h"
typedef struct {
unsigned char msg[32];
unsigned char key[32];
} bench_sign_t;
static void bench_sign_setup(void* arg) {
int i;
bench_sign_t *data = (bench_sign_t*)arg;
for (i = 0; i < 32; i++) data->msg[i] = i + 1;
for (i = 0; i < 32; i++) data->key[i] = i + 65;
}
static void bench_sign(void* arg) {
int i;
bench_sign_t *data = (bench_sign_t*)arg;
unsigned char sig[64];
for (i = 0; i < 20000; i++) {
int j;
int recid = 0;
CHECK(secp256k1_ecdsa_sign_compact(data->msg, sig, data->key, NULL, NULL, &recid));
for (j = 0; j < 32; j++) {
data->msg[j] = sig[j]; /* Move former R to message. */
data->key[j] = sig[j + 32]; /* Move former S to key. */
}
}
}
int main(void) {
bench_sign_t data;
secp256k1_start(SECP256K1_START_SIGN);
run_benchmark("ecdsa_sign", bench_sign, bench_sign_setup, NULL, &data, 10, 20000);
secp256k1_stop();
return 0;
}
/**********************************************************************
* 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.*
**********************************************************************/
#include <stdio.h>
#include <string.h>
#include "include/secp256k1.h"
#include "util.h"
#include "bench.h"
typedef struct {
unsigned char msg[32];
unsigned char key[32];
unsigned char sig[72];
int siglen;
unsigned char pubkey[33];
int pubkeylen;
} benchmark_verify_t;
static void benchmark_verify(void* arg) {
int i;
benchmark_verify_t* data = (benchmark_verify_t*)arg;
for (i = 0; i < 20000; i++) {
data->sig[data->siglen - 1] ^= (i & 0xFF);
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
CHECK(secp256k1_ecdsa_verify(data->msg, data->sig, data->siglen, data->pubkey, data->pubkeylen) == (i == 0));
data->sig[data->siglen - 1] ^= (i & 0xFF);
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
}
}
int main(void) {
int i;
benchmark_verify_t data;
secp256k1_start(SECP256K1_START_VERIFY | SECP256K1_START_SIGN);
for (i = 0; i < 32; i++) data.msg[i] = 1 + i;
for (i = 0; i < 32; i++) data.key[i] = 33 + i;
data.siglen = 72;
secp256k1_ecdsa_sign(data.msg, data.sig, &data.siglen, data.key, NULL, NULL);
data.pubkeylen = 33;
CHECK(secp256k1_ec_pubkey_create(data.pubkey, &data.pubkeylen, data.key, 1));
run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000);
secp256k1_stop();
return 0;
}
// Copyright (c) 2013 Pieter Wuille /**********************************************************************
// Distributed under the MIT/X11 software license, see the accompanying * Copyright (c) 2013, 2014 Pieter Wuille *
// file COPYING or http://www.opensource.org/licenses/mit-license.php. * Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_ECDSA_ #ifndef _SECP256K1_ECDSA_
#define _SECP256K1_ECDSA_ #define _SECP256K1_ECDSA_
#include "num.h" #include "scalar.h"
#include "group.h"
typedef struct { typedef struct {
secp256k1_num_t r, s; secp256k1_scalar_t r, s;
} secp256k1_ecdsa_sig_t; } secp256k1_ecdsa_sig_t;
void static secp256k1_ecdsa_sig_init(secp256k1_ecdsa_sig_t *r); static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size);
void static secp256k1_ecdsa_sig_free(secp256k1_ecdsa_sig_t *r); 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_scalar_t *message);
int static secp256k1_ecdsa_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size); 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);
void static secp256k1_ecdsa_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed); static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid);
int static secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size);
int static secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a);
int static secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_num_t *message);
int static secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *seckey, const secp256k1_num_t *message, const secp256k1_num_t *nonce, int *recid);
int static secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_num_t *message, int recid);
void static secp256k1_ecdsa_sig_set_rs(secp256k1_ecdsa_sig_t *sig, const secp256k1_num_t *r, const secp256k1_num_t *s);
int static secp256k1_ecdsa_privkey_parse(secp256k1_num_t *key, const unsigned char *privkey, int privkeylen);
int static secp256k1_ecdsa_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_num_t *key, int compressed);
#endif #endif
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_ECDSA_IMPL_H_
#define _SECP256K1_ECDSA_IMPL_H_
#include "scalar.h"
#include "field.h"
#include "group.h"
#include "ecmult.h"
#include "ecmult_gen.h"
#include "ecdsa.h"
/** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1
* sage: for t in xrange(1023, -1, -1):
* .. p = 2**256 - 2**32 - t
* .. if p.is_prime():
* .. print '%x'%p
* .. break
* 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'
* sage: a = 0
* sage: b = 7
* sage: F = FiniteField (p)
* sage: '%x' % (EllipticCurve ([F (a), F (b)]).order())
* 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141'
*/
static const secp256k1_fe_t secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST(
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL,
0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL
);
/** Difference between field and order, values 'p' and 'n' values defined in
* "Standards for Efficient Cryptography" (SEC2) 2.7.1.
* sage: p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
* sage: a = 0
* sage: b = 7
* sage: F = FiniteField (p)
* sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order())
* '14551231950b75fc4402da1722fc9baee'
*/
static const secp256k1_fe_t secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST(
0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL
);
static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) {
unsigned char ra[32] = {0}, sa[32] = {0};
const unsigned char *rp;
const unsigned char *sp;
int lenr;
int lens;
int overflow;
if (sig[0] != 0x30) {
return 0;
}
lenr = sig[3];
if (5+lenr >= size) {
return 0;
}
lens = sig[lenr+5];
if (sig[1] != lenr+lens+4) {
return 0;
}
if (lenr+lens+6 > size) {
return 0;
}
if (sig[2] != 0x02) {
return 0;
}
if (lenr == 0) {
return 0;
}
if (sig[lenr+4] != 0x02) {
return 0;
}
if (lens == 0) {
return 0;
}
sp = sig + 6 + lenr;
while (lens > 0 && sp[0] == 0) {
lens--;
sp++;
}
if (lens > 32) {
return 0;
}
rp = sig + 4;
while (lenr > 0 && rp[0] == 0) {
lenr--;
rp++;
}
if (lenr > 32) {
return 0;
}
memcpy(ra + 32 - lenr, rp, lenr);
memcpy(sa + 32 - lens, sp, lens);
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;
}
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) {
unsigned char r[33] = {0}, s[33] = {0};
unsigned char *rp = r, *sp = s;
int lenR = 33, lenS = 33;
secp256k1_scalar_get_b32(&r[1], &a->r);
secp256k1_scalar_get_b32(&s[1], &a->s);
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) {
return 0;
}
*size = 6 + lenS + lenR;
sig[0] = 0x30;
sig[1] = 4 + lenS + lenR;
sig[2] = 0x02;
sig[3] = lenR;
memcpy(sig+4, rp, lenR);
sig[4+lenR] = 0x02;
sig[5+lenR] = lenS;
memcpy(sig+lenR+6, sp, lenS);
return 1;
}
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) {
unsigned char c[32];
secp256k1_scalar_t sn, u1, u2;
secp256k1_fe_t xr;
secp256k1_gej_t pubkeyj;
secp256k1_gej_t pr;
if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) {
return 0;
}
secp256k1_scalar_inverse_var(&sn, &sig->s);
secp256k1_scalar_mul(&u1, &sn, message);
secp256k1_scalar_mul(&u2, &sn, &sig->r);
secp256k1_gej_set_ge(&pubkeyj, pubkey);
secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1);
if (secp256k1_gej_is_infinity(&pr)) {
return 0;
}
secp256k1_scalar_get_b32(c, &sig->r);
secp256k1_fe_set_b32(&xr, c);
/** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
* in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p),
* compute the remainder modulo n, and compare it to xr. However:
*
* xr == X(pr) mod n
* <=> exists h. (xr + h * n < p && xr + h * n == X(pr))
* [Since 2 * n > p, h can only be 0 or 1]
* <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr))
* [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p]
* <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p)
* [Multiplying both sides of the equations by pr.z^2 mod p]
* <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x)
*
* Thus, we can avoid the inversion, but we have to check both cases separately.
* secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test.
*/
if (secp256k1_gej_eq_x_var(&xr, &pr)) {
/* xr.x == xr * xr.z^2 mod p, so the signature is valid. */
return 1;
}
if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
/* xr + p >= n, so we can skip testing the second case. */
return 0;
}
secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe);
if (secp256k1_gej_eq_x_var(&xr, &pr)) {
/* (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. */
return 1;
}
return 0;
}
static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) {
unsigned char brx[32];
secp256k1_fe_t fx;
secp256k1_ge_t x;
secp256k1_gej_t xj;
secp256k1_scalar_t rn, u1, u2;
secp256k1_gej_t qj;
if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) {
return 0;
}
secp256k1_scalar_get_b32(brx, &sig->r);
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 (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
return 0;
}
secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe);
}
if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) {
return 0;
}
secp256k1_gej_set_ge(&xj, &x);
secp256k1_scalar_inverse_var(&rn, &sig->r);
secp256k1_scalar_mul(&u1, &rn, message);
secp256k1_scalar_negate(&u1, &u1);
secp256k1_scalar_mul(&u2, &rn, &sig->s);
secp256k1_ecmult(&qj, &xj, &u2, &u1);
secp256k1_ge_set_gej_var(pubkey, &qj);
return !secp256k1_gej_is_infinity(&qj);
}
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) {
unsigned char b[32];
secp256k1_gej_t rp;
secp256k1_ge_t r;
secp256k1_scalar_t n;
int overflow = 0;
secp256k1_ecmult_gen(&rp, nonce);
secp256k1_ge_set_gej(&r, &rp);
secp256k1_fe_normalize(&r.x);
secp256k1_fe_normalize(&r.y);
secp256k1_fe_get_b32(b, &r.x);
secp256k1_scalar_set_b32(&sig->r, b, &overflow);
if (secp256k1_scalar_is_zero(&sig->r)) {
/* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. */
secp256k1_gej_clear(&rp);
secp256k1_ge_clear(&r);
return 0;
}
if (recid) {
*recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
}
secp256k1_scalar_mul(&n, &sig->r, seckey);
secp256k1_scalar_add(&n, &n, message);
secp256k1_scalar_inverse(&sig->s, nonce);
secp256k1_scalar_mul(&sig->s, &sig->s, &n);
secp256k1_scalar_clear(&n);
secp256k1_gej_clear(&rp);
secp256k1_ge_clear(&r);
if (secp256k1_scalar_is_zero(&sig->s)) {
return 0;
}
if (secp256k1_scalar_is_high(&sig->s)) {
secp256k1_scalar_negate(&sig->s, &sig->s);
if (recid) {
*recid ^= 1;
}
}
return 1;
}
#endif
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_ECKEY_
#define _SECP256K1_ECKEY_
#include "group.h"
#include "scalar.h"
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_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen);
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_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_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak);
#endif
// Copyright (c) 2013 Pieter Wuille /**********************************************************************
// Distributed under the MIT/X11 software license, see the accompanying * Copyright (c) 2013, 2014 Pieter Wuille *
// file COPYING or http://www.opensource.org/licenses/mit-license.php. * Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_ECMULT_ #ifndef _SECP256K1_ECMULT_
#define _SECP256K1_ECMULT_ #define _SECP256K1_ECMULT_
...@@ -11,9 +13,7 @@ ...@@ -11,9 +13,7 @@
static void secp256k1_ecmult_start(void); static void secp256k1_ecmult_start(void);
static void secp256k1_ecmult_stop(void); static void secp256k1_ecmult_stop(void);
/** Multiply with the generator: R = a*G */
static void secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_num_t *a);
/** 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
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_ECMULT_GEN_
#define _SECP256K1_ECMULT_GEN_
#include "scalar.h"
#include "group.h"
static void secp256k1_ecmult_gen_start(void);
static void secp256k1_ecmult_gen_stop(void);
/** Multiply with the generator: R = a*G */
static void secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_scalar_t *a);
#endif
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_ECMULT_GEN_IMPL_H_
#define _SECP256K1_ECMULT_GEN_IMPL_H_
#include "scalar.h"
#include "group.h"
#include "ecmult_gen.h"
typedef struct {
/* For accelerating the computation of a*G:
* To harden against timing attacks, use the following mechanism:
* * Break up the multiplicand into groups of 4 bits, called n_0, n_1, n_2, ..., n_63.
* * Compute sum(n_i * 16^i * G + U_i, i=0..63), where:
* * U_i = U * 2^i (for i=0..62)
* * U_i = U * (1-2^63) (for i=63)
* where U is a point with no known corresponding scalar. Note that sum(U_i, i=0..63) = 0.
* For each i, and each of the 16 possible values of n_i, (n_i * 16^i * G + U_i) is
* 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
* the intermediate sums while computing a*G.
*/
secp256k1_ge_storage_t prec[64][16]; /* prec[j][i] = 16^j * i * G + U_i */
} secp256k1_ecmult_gen_consts_t;
static const secp256k1_ecmult_gen_consts_t *secp256k1_ecmult_gen_consts = NULL;
static void secp256k1_ecmult_gen_start(void) {
secp256k1_ge_t prec[1024];
secp256k1_gej_t gj;
secp256k1_gej_t nums_gej;
secp256k1_ecmult_gen_consts_t *ret;
int i, j;
if (secp256k1_ecmult_gen_consts != NULL) {
return;
}
/* Allocate the precomputation table. */
ret = (secp256k1_ecmult_gen_consts_t*)checked_malloc(sizeof(secp256k1_ecmult_gen_consts_t));
/* get the generator */
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
/* Construct a group element with no known corresponding scalar (nothing up my sleeve). */
{
static const unsigned char nums_b32[33] = "The scalar for this x is unknown";
secp256k1_fe_t nums_x;
secp256k1_ge_t nums_ge;
VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32));
VERIFY_CHECK(secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0));
secp256k1_gej_set_ge(&nums_gej, &nums_ge);
/* Add G to make the bits in x uniformly distributed. */
secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g);
}
/* compute prec. */
{
secp256k1_gej_t precj[1024]; /* Jacobian versions of prec. */
secp256k1_gej_t gbase;
secp256k1_gej_t numsbase;
gbase = gj; /* 16^j * G */
numsbase = nums_gej; /* 2^j * nums. */
for (j = 0; j < 64; j++) {
/* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */
precj[j*16] = numsbase;
for (i = 1; i < 16; i++) {
secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase);
}
/* Multiply gbase by 16. */
for (i = 0; i < 4; i++) {
secp256k1_gej_double_var(&gbase, &gbase);
}
/* Multiply numbase by 2. */
secp256k1_gej_double_var(&numsbase, &numsbase);
if (j == 62) {
/* In the last iteration, numsbase is (1 - 2^j) * nums instead. */
secp256k1_gej_neg(&numsbase, &numsbase);
secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej);
}
}
secp256k1_ge_set_all_gej_var(1024, prec, precj);
}
for (j = 0; j < 64; j++) {
for (i = 0; i < 16; i++) {
secp256k1_ge_to_storage(&ret->prec[j][i], &prec[j*16 + i]);
}
}
/* Set the global pointer to the precomputation table. */
secp256k1_ecmult_gen_consts = ret;
}
static void secp256k1_ecmult_gen_stop(void) {
secp256k1_ecmult_gen_consts_t *c;
if (secp256k1_ecmult_gen_consts == NULL) {
return;
}
c = (secp256k1_ecmult_gen_consts_t*)secp256k1_ecmult_gen_consts;
secp256k1_ecmult_gen_consts = NULL;
free(c);
}
static void secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_scalar_t *gn) {
const secp256k1_ecmult_gen_consts_t *c = secp256k1_ecmult_gen_consts;
secp256k1_ge_t add;
secp256k1_ge_storage_t adds;
int bits;
int i, j;
secp256k1_gej_set_infinity(r);
add.infinity = 0;
for (j = 0; j < 64; j++) {
bits = secp256k1_scalar_get_bits(gn, j * 4, 4);
for (i = 0; i < 16; i++) {
secp256k1_ge_storage_cmov(&adds, &c->prec[j][i], i == bits);
}
secp256k1_ge_from_storage(&add, &adds);
secp256k1_gej_add_ge(r, r, &add);
}
bits = 0;
secp256k1_ge_clear(&add);
}
#endif
This diff is collapsed.
// Copyright (c) 2013 Pieter Wuille /**********************************************************************
// Distributed under the MIT/X11 software license, see the accompanying * Copyright (c) 2013, 2014 Pieter Wuille *
// file COPYING or http://www.opensource.org/licenses/mit-license.php. * Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_FIELD_ #ifndef _SECP256K1_FIELD_
#define _SECP256K1_FIELD_ #define _SECP256K1_FIELD_
...@@ -16,86 +18,99 @@ ...@@ -16,86 +18,99 @@
* normality. * normality.
*/ */
#if defined(USE_FIELD_GMP) #if defined HAVE_CONFIG_H
#include "field_gmp.h" #include "libsecp256k1-config.h"
#elif defined(USE_FIELD_10X26) #endif
#if defined(USE_FIELD_10X26)
#include "field_10x26.h" #include "field_10x26.h"
#elif defined(USE_FIELD_5X52) #elif defined(USE_FIELD_5X52)
#include "field_5x52.h" #include "field_5x52.h"
#elif defined(USE_FIELD_5X64)
#include "field_5x64.h"
#else #else
#error "Please select field implementation" #error "Please select field implementation"
#endif #endif
typedef struct { /** Normalize a field element. */
secp256k1_num_t p; static void secp256k1_fe_normalize(secp256k1_fe_t *r);
} secp256k1_fe_consts_t;
static const secp256k1_fe_consts_t *secp256k1_fe_consts = NULL; /** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */
static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r);
/** Initialize field element precomputation data. */ /** Normalize a field element, without constant-time guarantee. */
void static secp256k1_fe_start(void); static void secp256k1_fe_normalize_var(secp256k1_fe_t *r);
/** Unload field element precomputation data. */ /** Verify whether a field element represents zero i.e. would normalize to a zero value. The field
void static secp256k1_fe_stop(void); * implementation may optionally normalize the input, but this should not be relied upon. */
static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r);
/** Normalize a field element. */ /** Verify whether a field element represents zero i.e. would normalize to a zero value. The field
void static secp256k1_fe_normalize(secp256k1_fe_t *r); * implementation may optionally normalize the input, but this should not be relied upon. */
static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r);
/** Set a field element equal to a small integer. Resulting field element is normalized. */ /** Set a field element equal to a small integer. Resulting field element is normalized. */
void static secp256k1_fe_set_int(secp256k1_fe_t *r, int a); static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a);
/** Verify whether a field element is zero. Requires the input to be normalized. */ /** Verify whether a field element is zero. Requires the input to be normalized. */
int static secp256k1_fe_is_zero(const secp256k1_fe_t *a); static int secp256k1_fe_is_zero(const secp256k1_fe_t *a);
/** Check the "oddness" of a field element. Requires the input to be normalized. */ /** Check the "oddness" of a field element. Requires the input to be normalized. */
int static secp256k1_fe_is_odd(const secp256k1_fe_t *a); static int secp256k1_fe_is_odd(const secp256k1_fe_t *a);
/** Compare two field elements. Requires magnitude-1 inputs. */
static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b);
/** Compare two field elements. Requires both inputs to be normalized */ /** Compare two field elements. Requires both inputs to be normalized */
int static secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b); 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. Resulting field element is normalized. */ /** Set a field element equal to 32-byte big endian value. If succesful, the resulting field element is normalized. */
void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a); 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 */
void static 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);
/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input /** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input
* as an argument. The magnitude of the output is one higher. */ * as an argument. The magnitude of the output is one higher. */
void static secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m); static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m);
/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that /** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that
* small integer. */ * small integer. */
void static secp256k1_fe_mul_int(secp256k1_fe_t *r, int a); static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a);
/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ /** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */
void static secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a); 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). */
void static 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). */
void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a); static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Sets a field element to be the (modular) square root of another. Requires the inputs' magnitude to /** Sets a field element to be the (modular) square root (if any exist) of another. Requires the
* be at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ * input's magnitude to be at most 8. The output magnitude is 1 (but not guaranteed to be
void static secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a); * normalized). Return value indicates whether a square root was found. */
static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be /** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
* at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
void static secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a); static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ /** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */
void static 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);
/** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be
* at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and
* outputs must not overlap in memory. */
static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a);
/** Convert a field element to the storage type. */
static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t*);
/** Convert a field element to a hexadecimal string. */ /** Convert a field element back from the storage type. */
void static secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a); static void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t*);
/** Convert a hexadecimal string to a field element. */ /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
void static secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen); static void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag);
#endif #endif
// Copyright (c) 2013 Pieter Wuille /**********************************************************************
// Distributed under the MIT/X11 software license, see the accompanying * Copyright (c) 2013, 2014 Pieter Wuille *
// file COPYING or http://www.opensource.org/licenses/mit-license.php. * Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_FIELD_REPR_ #ifndef _SECP256K1_FIELD_REPR_
#define _SECP256K1_FIELD_REPR_ #define _SECP256K1_FIELD_REPR_
...@@ -8,7 +10,7 @@ ...@@ -8,7 +10,7 @@
#include <stdint.h> #include <stdint.h>
typedef struct { typedef struct {
// X = sum(i=0..9, elem[i]*2^26) mod n /* X = sum(i=0..9, elem[i]*2^26) mod n */
uint32_t n[10]; uint32_t n[10];
#ifdef VERIFY #ifdef VERIFY
int magnitude; int magnitude;
...@@ -16,4 +18,30 @@ typedef struct { ...@@ -16,4 +18,30 @@ typedef struct {
#endif #endif
} secp256k1_fe_t; } secp256k1_fe_t;
/* Unpacks a constant into a overlapping multi-limbed FE element. */
#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \
(d0) & 0x3FFFFFFUL, \
((d0) >> 26) | ((d1) & 0xFFFFFUL) << 6, \
((d1) >> 20) | ((d2) & 0x3FFFUL) << 12, \
((d2) >> 14) | ((d3) & 0xFFUL) << 18, \
((d3) >> 8) | ((d4) & 0x3) << 24, \
((d4) >> 2) & 0x3FFFFFFUL, \
((d4) >> 28) | ((d5) & 0x3FFFFFUL) << 4, \
((d5) >> 22) | ((d6) & 0xFFFF) << 10, \
((d6) >> 16) | ((d7) & 0x3FF) << 16, \
((d7) >> 10) \
}
#ifdef VERIFY
#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}
#else
#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}
#endif
typedef struct {
uint32_t n[8];
} secp256k1_fe_storage_t;
#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}
#endif #endif
This diff is collapsed.
// Copyright (c) 2013 Pieter Wuille /**********************************************************************
// Distributed under the MIT/X11 software license, see the accompanying * Copyright (c) 2013, 2014 Pieter Wuille *
// file COPYING or http://www.opensource.org/licenses/mit-license.php. * Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_FIELD_REPR_ #ifndef _SECP256K1_FIELD_REPR_
#define _SECP256K1_FIELD_REPR_ #define _SECP256K1_FIELD_REPR_
...@@ -8,7 +10,7 @@ ...@@ -8,7 +10,7 @@
#include <stdint.h> #include <stdint.h>
typedef struct { typedef struct {
// X = sum(i=0..4, elem[i]*2^52) mod n /* X = sum(i=0..4, elem[i]*2^52) mod n */
uint64_t n[5]; uint64_t n[5];
#ifdef VERIFY #ifdef VERIFY
int magnitude; int magnitude;
...@@ -16,4 +18,30 @@ typedef struct { ...@@ -16,4 +18,30 @@ typedef struct {
#endif #endif
} secp256k1_fe_t; } secp256k1_fe_t;
/* Unpacks a constant into a overlapping multi-limbed FE element. */
#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \
(d0) | ((uint64_t)(d1) & 0xFFFFFUL) << 32, \
((d1) >> 20) | ((uint64_t)(d2)) << 12 | ((uint64_t)(d3) & 0xFFUL) << 44, \
((d3) >> 8) | ((uint64_t)(d4) & 0xFFFFFFFUL) << 24, \
((d4) >> 28) | ((uint64_t)(d5)) << 4 | ((uint64_t)(d6) & 0xFFFFUL) << 36, \
((d6) >> 16) | ((uint64_t)(d7)) << 16 \
}
#ifdef VERIFY
#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}
#else
#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}
#endif
typedef struct {
uint64_t n[4];
} secp256k1_fe_storage_t;
#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \
(d0) | ((uint64_t)(d1)) << 32, \
(d2) | ((uint64_t)(d3)) << 32, \
(d4) | ((uint64_t)(d5)) << 32, \
(d6) | ((uint64_t)(d7)) << 32 \
}}
#endif #endif
;; Added by Diederik Huys, March 2013
;;
;; Provided public procedures:
;; secp256k1_fe_mul_inner
;; secp256k1_fe_sqr_inner
;;
;; Needed tools: YASM (http://yasm.tortall.net)
;;
;;
BITS 64
;; Procedure ExSetMult
;; Register Layout:
;; INPUT: rdi = a->n
;; rsi = b->n
;; rdx = r->a
;;
;; INTERNAL: rdx:rax = multiplication accumulator
;; r9:r8 = c
;; r10-r13 = t0-t3
;; r14 = b.n[0] / t4
;; r15 = b.n[1] / t5
;; rbx = b.n[2] / t6
;; rcx = b.n[3] / t7
;; rbp = Constant 0FFFFFFFFFFFFFh / t8
;; rsi = b.n / b.n[4] / t9
GLOBAL secp256k1_fe_mul_inner
ALIGN 32
secp256k1_fe_mul_inner:
push rbp
push rbx
push r12
push r13
push r14
push r15
push rdx
mov r14,[rsi+8*0] ; preload b.n[0]. This will be the case until
; b.n[0] is no longer needed, then we reassign
; r14 to t4
;; c=a.n[0] * b.n[0]
mov rax,[rdi+0*8] ; load a.n[0]
mov rbp,0FFFFFFFFFFFFFh
mul r14 ; rdx:rax=a.n[0]*b.n[0]
mov r15,[rsi+1*8]
mov r10,rbp ; load modulus into target register for t0
mov r8,rax
and r10,rax ; only need lower qword of c
shrd r8,rdx,52
xor r9,r9 ; c < 2^64, so we ditch the HO part
;; c+=a.n[0] * b.n[1] + a.n[1] * b.n[0]
mov rax,[rdi+0*8]
mul r15
add r8,rax
adc r9,rdx
mov rax,[rdi+1*8]
mul r14
mov r11,rbp
mov rbx,[rsi+2*8]
add r8,rax
adc r9,rdx
and r11,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[0 1 2] * b.n[2 1 0]
mov rax,[rdi+0*8]
mul rbx
add r8,rax
adc r9,rdx
mov rax,[rdi+1*8]
mul r15
add r8,rax
adc r9,rdx
mov rax,[rdi+2*8]
mul r14
mov r12,rbp
mov rcx,[rsi+3*8]
add r8,rax
adc r9,rdx
and r12,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[0 1 2 3] * b.n[3 2 1 0]
mov rax,[rdi+0*8]
mul rcx
add r8,rax
adc r9,rdx
mov rax,[rdi+1*8]
mul rbx
add r8,rax
adc r9,rdx
mov rax,[rdi+2*8]
mul r15
add r8,rax
adc r9,rdx
mov rax,[rdi+3*8]
mul r14
mov r13,rbp
mov rsi,[rsi+4*8] ; load b.n[4] and destroy pointer
add r8,rax
adc r9,rdx
and r13,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[0 1 2 3 4] * b.n[4 3 2 1 0]
mov rax,[rdi+0*8]
mul rsi
add r8,rax
adc r9,rdx
mov rax,[rdi+1*8]
mul rcx
add r8,rax
adc r9,rdx
mov rax,[rdi+2*8]
mul rbx
add r8,rax
adc r9,rdx
mov rax,[rdi+3*8]
mul r15
add r8,rax
adc r9,rdx
mov rax,[rdi+4*8]
mul r14
mov r14,rbp ; load modulus into t4 and destroy a.n[0]
add r8,rax
adc r9,rdx
and r14,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[1 2 3 4] * b.n[4 3 2 1]
mov rax,[rdi+1*8]
mul rsi
add r8,rax
adc r9,rdx
mov rax,[rdi+2*8]
mul rcx
add r8,rax
adc r9,rdx
mov rax,[rdi+3*8]
mul rbx
add r8,rax
adc r9,rdx
mov rax,[rdi+4*8]
mul r15
mov r15,rbp
add r8,rax
adc r9,rdx
and r15,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[2 3 4] * b.n[4 3 2]
mov rax,[rdi+2*8]
mul rsi
add r8,rax
adc r9,rdx
mov rax,[rdi+3*8]
mul rcx
add r8,rax
adc r9,rdx
mov rax,[rdi+4*8]
mul rbx
mov rbx,rbp
add r8,rax
adc r9,rdx
and rbx,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[3 4] * b.n[4 3]
mov rax,[rdi+3*8]
mul rsi
add r8,rax
adc r9,rdx
mov rax,[rdi+4*8]
mul rcx
mov rcx,rbp
add r8,rax
adc r9,rdx
and rcx,r8
shrd r8,r9,52
xor r9,r9
;; c+=a.n[4] * b.n[4]
mov rax,[rdi+4*8]
mul rsi
;; mov rbp,rbp ; modulus already there!
add r8,rax
adc r9,rdx
and rbp,r8
shrd r8,r9,52
xor r9,r9
mov rsi,r8 ; load c into t9 and destroy b.n[4]
;; *******************************************************
common_exit_norm:
mov rdi,01000003D10h ; load constant
mov rax,r15 ; get t5
mul rdi
add rax,r10 ; +t0
adc rdx,0
mov r10,0FFFFFFFFFFFFFh ; modulus. Sadly, we ran out of registers!
mov r8,rax ; +c
and r10,rax
shrd r8,rdx,52
xor r9,r9
mov rax,rbx ; get t6
mul rdi
add rax,r11 ; +t1
adc rdx,0
mov r11,0FFFFFFFFFFFFFh ; modulus
add r8,rax ; +c
adc r9,rdx
and r11,r8
shrd r8,r9,52
xor r9,r9
mov rax,rcx ; get t7
mul rdi
add rax,r12 ; +t2
adc rdx,0
pop rbx ; retrieve pointer to this.n
mov r12,0FFFFFFFFFFFFFh ; modulus
add r8,rax ; +c
adc r9,rdx
and r12,r8
mov [rbx+2*8],r12 ; mov into this.n[2]
shrd r8,r9,52
xor r9,r9
mov rax,rbp ; get t8
mul rdi
add rax,r13 ; +t3
adc rdx,0
mov r13,0FFFFFFFFFFFFFh ; modulus
add r8,rax ; +c
adc r9,rdx
and r13,r8
mov [rbx+3*8],r13 ; -> this.n[3]
shrd r8,r9,52
xor r9,r9
mov rax,rsi ; get t9
mul rdi
add rax,r14 ; +t4
adc rdx,0
mov r14,0FFFFFFFFFFFFh ; !!!
add r8,rax ; +c
adc r9,rdx
and r14,r8
mov [rbx+4*8],r14 ; -> this.n[4]
shrd r8,r9,48 ; !!!
xor r9,r9
mov rax,01000003D1h
mul r8
add rax,r10
adc rdx,0
mov r10,0FFFFFFFFFFFFFh ; modulus
mov r8,rax
and rax,r10
shrd r8,rdx,52
mov [rbx+0*8],rax ; -> this.n[0]
add r8,r11
mov [rbx+1*8],r8 ; -> this.n[1]
pop r15
pop r14
pop r13
pop r12
pop rbx
pop rbp
ret
;; PROC ExSetSquare
;; Register Layout:
;; INPUT: rdi = a.n
;; rsi = this.a
;; INTERNAL: rdx:rax = multiplication accumulator
;; r9:r8 = c
;; r10-r13 = t0-t3
;; r14 = a.n[0] / t4
;; r15 = a.n[1] / t5
;; rbx = a.n[2] / t6
;; rcx = a.n[3] / t7
;; rbp = 0FFFFFFFFFFFFFh / t8
;; rsi = a.n[4] / t9
GLOBAL secp256k1_fe_sqr_inner
ALIGN 32
secp256k1_fe_sqr_inner:
push rbp
push rbx
push r12
push r13
push r14
push r15
push rsi
mov rbp,0FFFFFFFFFFFFFh
;; c=a.n[0] * a.n[0]
mov r14,[rdi+0*8] ; r14=a.n[0]
mov r10,rbp ; modulus
mov rax,r14
mul rax
mov r15,[rdi+1*8] ; a.n[1]
add r14,r14 ; r14=2*a.n[0]
mov r8,rax
and r10,rax ; only need lower qword
shrd r8,rdx,52
xor r9,r9
;; c+=2*a.n[0] * a.n[1]
mov rax,r14 ; r14=2*a.n[0]
mul r15
mov rbx,[rdi+2*8] ; rbx=a.n[2]
mov r11,rbp ; modulus
add r8,rax
adc r9,rdx
and r11,r8
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[0]*a.n[2]+a.n[1]*a.n[1]
mov rax,r14
mul rbx
add r8,rax
adc r9,rdx
mov rax,r15
mov r12,rbp ; modulus
mul rax
mov rcx,[rdi+3*8] ; rcx=a.n[3]
add r15,r15 ; r15=a.n[1]*2
add r8,rax
adc r9,rdx
and r12,r8 ; only need lower dword
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[0]*a.n[3]+2*a.n[1]*a.n[2]
mov rax,r14
mul rcx
add r8,rax
adc r9,rdx
mov rax,r15 ; rax=2*a.n[1]
mov r13,rbp ; modulus
mul rbx
mov rsi,[rdi+4*8] ; rsi=a.n[4]
add r8,rax
adc r9,rdx
and r13,r8
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[0]*a.n[4]+2*a.n[1]*a.n[3]+a.n[2]*a.n[2]
mov rax,r14 ; last time we need 2*a.n[0]
mul rsi
add r8,rax
adc r9,rdx
mov rax,r15
mul rcx
mov r14,rbp ; modulus
add r8,rax
adc r9,rdx
mov rax,rbx
mul rax
add rbx,rbx ; rcx=2*a.n[2]
add r8,rax
adc r9,rdx
and r14,r8
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[1]*a.n[4]+2*a.n[2]*a.n[3]
mov rax,r15 ; last time we need 2*a.n[1]
mul rsi
add r8,rax
adc r9,rdx
mov rax,rbx
mul rcx
mov r15,rbp ; modulus
add r8,rax
adc r9,rdx
and r15,r8
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[2]*a.n[4]+a.n[3]*a.n[3]
mov rax,rbx ; last time we need 2*a.n[2]
mul rsi
add r8,rax
adc r9,rdx
mov rax,rcx ; a.n[3]
mul rax
mov rbx,rbp ; modulus
add r8,rax
adc r9,rdx
and rbx,r8 ; only need lower dword
lea rax,[2*rcx]
shrd r8,r9,52
xor r9,r9
;; c+=2*a.n[3]*a.n[4]
mul rsi
mov rcx,rbp ; modulus
add r8,rax
adc r9,rdx
and rcx,r8 ; only need lower dword
shrd r8,r9,52
xor r9,r9
;; c+=a.n[4]*a.n[4]
mov rax,rsi
mul rax
;; mov rbp,rbp ; modulus is already there!
add r8,rax
adc r9,rdx
and rbp,r8
shrd r8,r9,52
xor r9,r9
mov rsi,r8
;; *******************************************************
jmp common_exit_norm
end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_REPR_
#define _SECP256K1_FIELD_REPR_
#include <stdint.h>
typedef struct {
// X = sum(i=0..4, elem[i]*2^64) mod n
uint64_t n[5];
#ifdef VERIFY
int reduced; // n[4] == 0
int normalized; // reduced and X < 2^256 - 0x100003D1
#endif
} secp256k1_fe_t;
#endif
This diff is collapsed.
// Copyright (c) 2013 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _SECP256K1_FIELD_REPR_
#define _SECP256K1_FIELD_REPR_
#include <gmp.h>
#define FIELD_LIMBS ((256 + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS)
typedef struct {
mp_limb_t n[FIELD_LIMBS+1];
} secp256k1_fe_t;
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment