tags/v0.15.17a49cac
Merge #410: Add string.h include to ecmult_impl0bbd5d4
Add string.h include to ecmult_implc5b32e1
Merge #405: Make secp256k1_fe_sqrt constant time926836a
Make secp256k1_fe_sqrt constant timee2a8e92
Merge #404: Replace 3M + 4S doubling formula with 2M + 5S one8ec49d8
Add note about 2M + 5S doubling formula5a91bd7
Merge #400: A couple minor cleanupsac01378
build: add -DSECP256K1_BUILD to benchmark_internal build flagsa6c6f99
Remove a bunch of unused stdlib #includes65285a6
Merge #403: configure: add flag to disable OpenSSL testsa9b2a5d
configure: add flag to disable OpenSSL testsb340123
Merge #402: Add support for testing quadratic residuese6e9805
Add function for testing quadratic residue field/group elements.efd953a
Add Jacobi symbol test via GMPfa36a0d
Merge #401: ecmult_const: unify endomorphism and non-endomorphism skew casesc6191fd
ecmult_const: unify endomorphism and non-endomorphism skew cases0b3e618
Merge #378: .gitignore build-aux cleanup6042217
Merge #384: JNI: align shared files copyright/comments to bitcoinj's24ad20f
Merge #399: build: verify that the native compiler works for static precompb3be852
Merge #398: Test whether ECDH and Schnorr are enabled for JNIaa0b1fd
build: verify that the native compiler works for static precompeee808d
Test whether ECDH and Schnorr are enabled for JNI7b0fb18
Merge #366: ARM assembly implementation of field_10x26 inner (rebase of #173)001f176
ARM assembly implementation of field_10x26 inner0172be9
Merge #397: Small fixes for sha2563f8b78e
Fix undefs in hash_impl.h2ab4695
Fix state size in sha256 struct6875b01
Merge #386: Add some missing `VERIFY_CHECK(ctx != NULL)`2c52b5d
Merge #389: Cast pointers through uintptr_t under JNI43097a4
Merge #390: Update bitcoin-core GitHub links31c9c12
Merge #391: JNI: Only call ecdsa_verify if its inputs parsed correctly1cb2302
Merge #392: Add testcase which hits additional branch in secp256k1_scalar_sqrd2ee340
Merge #388: bench_ecdh: fix call to secp256k1_context_create093a497
Add testcase which hits additional branch in secp256k1_scalar_sqra40c701
JNI: Only call ecdsa_verify if its inputs parsed correctlyfaa2a11
Update bitcoin-core GitHub links47b9e78
Cast pointers through uintptr_t under JNIf36f9c6
bench_ecdh: fix call to secp256k1_context_createbcc4881
Add some missing `VERIFY_CHECK(ctx != NULL)` for functions that use `ARG_CHECK`6ceea2c
align shared files copyright/comments to bitcoinj's70141a8
Update .gitignore7b549b1
Merge #373: build: fix x86_64 asm detection for some compilersbc7c93c
Merge #374: Add note about y=0 being possible on one of the sextic twistse457018
Merge #364: JNI rebased86e2d07
JNI library: cleanup, removed unimplemented code3093576a
JNI librarybd2895f
Merge pull request #371e72e93a
Add note about y=0 being possible on one of the sextic twists3f8fdfb
build: fix x86_64 asm detection for some compilerse5a9047
[Trivial] Remove double semicolonsc18b869
Merge pull request #3603026daa
Merge pull request #30203d4611
Add sage verification script for the group lawsa965937
Merge pull request #36183221ec
Add experimental features to configure5d4c5a3
Prevent damage_array in the signature test from going out of bounds.419bf7f
Merge pull request #35603d84a4
Benchmark against OpenSSL verification git-subtree-dir: src/secp256k1 git-subtree-split:7a49cacd39
@@ -25,17 +25,24 @@ config.status | |||
libtool | |||
.deps/ | |||
.dirstamp | |||
build-aux/ | |||
*.lo | |||
*.o | |||
*~ | |||
src/libsecp256k1-config.h | |||
src/libsecp256k1-config.h.in | |||
src/ecmult_static_context.h | |||
m4/libtool.m4 | |||
m4/ltoptions.m4 | |||
m4/ltsugar.m4 | |||
m4/ltversion.m4 | |||
m4/lt~obsolete.m4 | |||
build-aux/config.guess | |||
build-aux/config.sub | |||
build-aux/depcomp | |||
build-aux/install-sh | |||
build-aux/ltmain.sh | |||
build-aux/m4/libtool.m4 | |||
build-aux/m4/lt~obsolete.m4 | |||
build-aux/m4/ltoptions.m4 | |||
build-aux/m4/ltsugar.m4 | |||
build-aux/m4/ltversion.m4 | |||
build-aux/missing | |||
build-aux/compile | |||
build-aux/test-driver | |||
src/stamp-h1 | |||
libsecp256k1.pc |
@@ -6,26 +6,31 @@ addons: | |||
compiler: | |||
- clang | |||
- gcc | |||
cache: | |||
directories: | |||
- src/java/guava/ | |||
env: | |||
global: | |||
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no | |||
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no EXPERIMENTAL=no | |||
- GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar | |||
matrix: | |||
- SCALAR=32bit RECOVERY=yes | |||
- SCALAR=32bit FIELD=32bit ECDH=yes | |||
- SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes | |||
- SCALAR=64bit | |||
- FIELD=64bit RECOVERY=yes | |||
- FIELD=64bit ENDOMORPHISM=yes | |||
- FIELD=64bit ENDOMORPHISM=yes ECDH=yes | |||
- FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes | |||
- FIELD=64bit ASM=x86_64 | |||
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 | |||
- FIELD=32bit SCHNORR=yes | |||
- FIELD=32bit SCHNORR=yes EXPERIMENTAL=yes | |||
- FIELD=32bit ENDOMORPHISM=yes | |||
- BIGNUM=no | |||
- BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes | |||
- BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes EXPERIMENTAL=yes | |||
- BIGNUM=no STATICPRECOMPUTATION=no | |||
- BUILD=distcheck | |||
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC | |||
- EXTRAFLAGS=CFLAGS=-O0 | |||
- BUILD=check-java ECDH=yes SCHNORR=yes EXPERIMENTAL=yes | |||
matrix: | |||
fast_finish: true | |||
include: | |||
@@ -55,9 +60,11 @@ matrix: | |||
packages: | |||
- gcc-multilib | |||
- libgmp-dev:i386 | |||
before_install: mkdir -p `dirname $GUAVA_JAR` | |||
install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi | |||
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 --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD | |||
- ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD | |||
os: linux |
@@ -1,6 +1,12 @@ | |||
ACLOCAL_AMFLAGS = -I build-aux/m4 | |||
lib_LTLIBRARIES = libsecp256k1.la | |||
if USE_JNI | |||
JNI_LIB = libsecp256k1_jni.la | |||
noinst_LTLIBRARIES = $(JNI_LIB) | |||
else | |||
JNI_LIB = | |||
endif | |||
include_HEADERS = include/secp256k1.h | |||
noinst_HEADERS = | |||
noinst_HEADERS += src/scalar.h | |||
@@ -32,6 +38,7 @@ 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/java/org_bitcoin_Secp256k1Context.h | |||
noinst_HEADERS += src/util.h | |||
noinst_HEADERS += src/testrand.h | |||
noinst_HEADERS += src/testrand_impl.h | |||
@@ -45,35 +52,80 @@ noinst_HEADERS += contrib/lax_der_parsing.c | |||
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h | |||
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c | |||
if USE_EXTERNAL_ASM | |||
COMMON_LIB = libsecp256k1_common.la | |||
noinst_LTLIBRARIES = $(COMMON_LIB) | |||
else | |||
COMMON_LIB = | |||
endif | |||
pkgconfigdir = $(libdir)/pkgconfig | |||
pkgconfig_DATA = libsecp256k1.pc | |||
if USE_EXTERNAL_ASM | |||
if USE_ASM_ARM | |||
libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s | |||
endif | |||
endif | |||
libsecp256k1_la_SOURCES = src/secp256k1.c | |||
libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) | |||
libsecp256k1_la_LIBADD = $(SECP_LIBS) | |||
libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) | |||
libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB) | |||
libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c | |||
libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES) | |||
noinst_PROGRAMS = | |||
if USE_BENCHMARK | |||
noinst_PROGRAMS += bench_verify bench_sign bench_internal | |||
bench_verify_SOURCES = src/bench_verify.c | |||
bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) | |||
bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) | |||
bench_sign_SOURCES = src/bench_sign.c | |||
bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) | |||
bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) | |||
bench_internal_SOURCES = src/bench_internal.c | |||
bench_internal_LDADD = $(SECP_LIBS) | |||
bench_internal_CPPFLAGS = $(SECP_INCLUDES) | |||
bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) | |||
bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES) | |||
endif | |||
if USE_TESTS | |||
noinst_PROGRAMS += tests | |||
tests_SOURCES = src/tests.c | |||
tests_CPPFLAGS = -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) | |||
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) | |||
tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) | |||
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) | |||
tests_LDFLAGS = -static | |||
TESTS = tests | |||
endif | |||
JAVAROOT=src/java | |||
JAVAORG=org/bitcoin | |||
JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar | |||
CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA) | |||
JAVA_FILES= \ | |||
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \ | |||
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \ | |||
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \ | |||
$(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java | |||
if USE_JNI | |||
$(JAVA_GUAVA): | |||
@echo Guava is missing. Fetch it via: \ | |||
wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@) | |||
@false | |||
.stamp-java: $(JAVA_FILES) | |||
@echo Compiling $^ | |||
$(AM_V_at)$(CLASSPATH_ENV) javac $^ | |||
@touch $@ | |||
if USE_TESTS | |||
check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java | |||
$(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test | |||
endif | |||
endif | |||
if USE_ECMULT_STATIC_PRECOMPUTATION | |||
CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) | |||
CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function | |||
@@ -93,10 +145,10 @@ $(bench_internal_OBJECTS): src/ecmult_static_context.h | |||
src/ecmult_static_context.h: $(gen_context_BIN) | |||
./$(gen_context_BIN) | |||
CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h | |||
CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java | |||
endif | |||
EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h | |||
EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES) | |||
if ENABLE_MODULE_ECDH | |||
include src/modules/ecdh/Makefile.am.include |
@@ -1,7 +1,7 @@ | |||
libsecp256k1 | |||
============ | |||
[](https://travis-ci.org/bitcoin/secp256k1) | |||
[](https://travis-ci.org/bitcoin-core/secp256k1) | |||
Optimized C library for EC operations on curve secp256k1. | |||
@@ -0,0 +1,140 @@ | |||
# =========================================================================== | |||
# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html | |||
# =========================================================================== | |||
# | |||
# SYNOPSIS | |||
# | |||
# AX_JNI_INCLUDE_DIR | |||
# | |||
# DESCRIPTION | |||
# | |||
# AX_JNI_INCLUDE_DIR finds include directories needed for compiling | |||
# programs using the JNI interface. | |||
# | |||
# JNI include directories are usually in the Java distribution. This is | |||
# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in | |||
# that order. When this macro completes, a list of directories is left in | |||
# the variable JNI_INCLUDE_DIRS. | |||
# | |||
# Example usage follows: | |||
# | |||
# AX_JNI_INCLUDE_DIR | |||
# | |||
# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS | |||
# do | |||
# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR" | |||
# done | |||
# | |||
# If you want to force a specific compiler: | |||
# | |||
# - at the configure.in level, set JAVAC=yourcompiler before calling | |||
# AX_JNI_INCLUDE_DIR | |||
# | |||
# - at the configure level, setenv JAVAC | |||
# | |||
# Note: This macro can work with the autoconf M4 macros for Java programs. | |||
# This particular macro is not part of the original set of macros. | |||
# | |||
# LICENSE | |||
# | |||
# Copyright (c) 2008 Don Anderson <dda@sleepycat.com> | |||
# | |||
# Copying and distribution of this file, with or without modification, are | |||
# permitted in any medium without royalty provided the copyright notice | |||
# and this notice are preserved. This file is offered as-is, without any | |||
# warranty. | |||
#serial 10 | |||
AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR]) | |||
AC_DEFUN([AX_JNI_INCLUDE_DIR],[ | |||
JNI_INCLUDE_DIRS="" | |||
if test "x$JAVA_HOME" != x; then | |||
_JTOPDIR="$JAVA_HOME" | |||
else | |||
if test "x$JAVAC" = x; then | |||
JAVAC=javac | |||
fi | |||
AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no]) | |||
if test "x$_ACJNI_JAVAC" = xno; then | |||
AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME]) | |||
fi | |||
_ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC") | |||
_JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'` | |||
fi | |||
case "$host_os" in | |||
darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` | |||
_JINC="$_JTOPDIR/Headers";; | |||
*) _JINC="$_JTOPDIR/include";; | |||
esac | |||
_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR]) | |||
_AS_ECHO_LOG([_JINC=$_JINC]) | |||
# On Mac OS X 10.6.4, jni.h is a symlink: | |||
# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h | |||
# -> ../../CurrentJDK/Headers/jni.h. | |||
AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path, | |||
[ | |||
if test -f "$_JINC/jni.h"; then | |||
ac_cv_jni_header_path="$_JINC" | |||
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" | |||
else | |||
_JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` | |||
if test -f "$_JTOPDIR/include/jni.h"; then | |||
ac_cv_jni_header_path="$_JTOPDIR/include" | |||
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" | |||
else | |||
ac_cv_jni_header_path=none | |||
fi | |||
fi | |||
]) | |||
# get the likely subdirectories for system specific java includes | |||
case "$host_os" in | |||
bsdi*) _JNI_INC_SUBDIRS="bsdos";; | |||
darwin*) _JNI_INC_SUBDIRS="darwin";; | |||
freebsd*) _JNI_INC_SUBDIRS="freebsd";; | |||
linux*) _JNI_INC_SUBDIRS="linux genunix";; | |||
osf*) _JNI_INC_SUBDIRS="alpha";; | |||
solaris*) _JNI_INC_SUBDIRS="solaris";; | |||
mingw*) _JNI_INC_SUBDIRS="win32";; | |||
cygwin*) _JNI_INC_SUBDIRS="win32";; | |||
*) _JNI_INC_SUBDIRS="genunix";; | |||
esac | |||
if test "x$ac_cv_jni_header_path" != "xnone"; then | |||
# add any subdirectories that are present | |||
for JINCSUBDIR in $_JNI_INC_SUBDIRS | |||
do | |||
if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then | |||
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR" | |||
fi | |||
done | |||
fi | |||
]) | |||
# _ACJNI_FOLLOW_SYMLINKS <path> | |||
# Follows symbolic links on <path>, | |||
# finally setting variable _ACJNI_FOLLOWED | |||
# ---------------------------------------- | |||
AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[ | |||
# find the include directory relative to the javac executable | |||
_cur="$1" | |||
while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do | |||
AC_MSG_CHECKING([symlink for $_cur]) | |||
_slink=`ls -ld "$_cur" | sed 's/.* -> //'` | |||
case "$_slink" in | |||
/*) _cur="$_slink";; | |||
# 'X' avoids triggering unwanted echo options. | |||
*) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";; | |||
esac | |||
AC_MSG_RESULT([$_cur]) | |||
done | |||
_ACJNI_FOLLOWED="$_cur" | |||
])# _ACJNI |
@@ -3,13 +3,13 @@ AC_DEFUN([SECP_INT128_CHECK],[ | |||
has_int128=$ac_cv_type___int128 | |||
]) | |||
dnl | |||
dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell. | |||
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"); | |||
__asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); | |||
]])],[has_64bit_asm=yes],[has_64bit_asm=no]) | |||
AC_MSG_RESULT([$has_64bit_asm]) | |||
]) |
@@ -29,6 +29,7 @@ AC_PROG_CC_C89 | |||
if test x"$ac_cv_prog_cc_c89" = x"no"; then | |||
AC_MSG_ERROR([c89 compiler support required]) | |||
fi | |||
AM_PROG_AS | |||
case $host_os in | |||
*darwin*) | |||
@@ -93,23 +94,33 @@ AC_ARG_ENABLE(tests, | |||
[use_tests=$enableval], | |||
[use_tests=yes]) | |||
AC_ARG_ENABLE(openssl_tests, | |||
AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]), | |||
[enable_openssl_tests=$enableval], | |||
[enable_openssl_tests=auto]) | |||
AC_ARG_ENABLE(experimental, | |||
AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]), | |||
[use_experimental=$enableval], | |||
[use_experimental=no]) | |||
AC_ARG_ENABLE(endomorphism, | |||
AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]), | |||
[use_endomorphism=$enableval], | |||
[use_endomorphism=no]) | |||
AC_ARG_ENABLE(ecmult_static_precomputation, | |||
AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]), | |||
[use_ecmult_static_precomputation=$enableval], | |||
[use_ecmult_static_precomputation=yes]) | |||
[use_ecmult_static_precomputation=auto]) | |||
AC_ARG_ENABLE(module_ecdh, | |||
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (default is no)]), | |||
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]), | |||
[enable_module_ecdh=$enableval], | |||
[enable_module_ecdh=no]) | |||
AC_ARG_ENABLE(module_schnorr, | |||
AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (default is no)]), | |||
AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (experimental)]), | |||
[enable_module_schnorr=$enableval], | |||
[enable_module_schnorr=no]) | |||
@@ -118,6 +129,11 @@ AC_ARG_ENABLE(module_recovery, | |||
[enable_module_recovery=$enableval], | |||
[enable_module_recovery=no]) | |||
AC_ARG_ENABLE(jni, | |||
AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]), | |||
[use_jni=$enableval], | |||
[use_jni=auto]) | |||
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], | |||
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) | |||
@@ -127,8 +143,8 @@ AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|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_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto] | |||
[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto]) | |||
AC_CHECK_TYPES([__int128]) | |||
@@ -138,6 +154,34 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])], | |||
[ AC_MSG_RESULT([no]) | |||
]) | |||
if test x"$use_ecmult_static_precomputation" != x"no"; then | |||
save_cross_compiling=$cross_compiling | |||
cross_compiling=no | |||
TEMP_CC="$CC" | |||
CC="$CC_FOR_BUILD" | |||
AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}]) | |||
AC_RUN_IFELSE( | |||
[AC_LANG_PROGRAM([], [return 0])], | |||
[working_native_cc=yes], | |||
[working_native_cc=no],[dnl]) | |||
CC="$TEMP_CC" | |||
cross_compiling=$save_cross_compiling | |||
if test x"$working_native_cc" = x"no"; then | |||
set_precomp=no | |||
if test x"$use_ecmult_static_precomputation" = x"yes"; then | |||
AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) | |||
else | |||
AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) | |||
fi | |||
else | |||
AC_MSG_RESULT([ok]) | |||
set_precomp=yes | |||
fi | |||
else | |||
set_precomp=no | |||
fi | |||
if test x"$req_asm" = x"auto"; then | |||
SECP_64BIT_ASM_CHECK | |||
if test x"$has_64bit_asm" = x"yes"; then | |||
@@ -155,6 +199,8 @@ else | |||
AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) | |||
fi | |||
;; | |||
arm) | |||
;; | |||
no) | |||
;; | |||
*) | |||
@@ -247,10 +293,15 @@ else | |||
fi | |||
# select assembly optimization | |||
use_external_asm=no | |||
case $set_asm in | |||
x86_64) | |||
AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations]) | |||
;; | |||
arm) | |||
use_external_asm=yes | |||
;; | |||
no) | |||
;; | |||
*) | |||
@@ -305,16 +356,51 @@ 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 | |||
if test x"$enable_openssl_tests" != x"no"; 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 | |||
else | |||
if test x"$enable_openssl_tests" = x"yes"; then | |||
AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available]) | |||
fi | |||
fi | |||
else | |||
if test x"$enable_openssl_tests" = x"yes"; then | |||
AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled]) | |||
fi | |||
fi | |||
if test x"$use_jni" != x"no"; then | |||
AX_JNI_INCLUDE_DIR | |||
have_jni_dependencies=yes | |||
if test x"$enable_module_schnorr" = x"no"; then | |||
have_jni_dependencies=no | |||
fi | |||
if test x"$enable_module_ecdh" = x"no"; then | |||
have_jni_dependencies=no | |||
fi | |||
if test "x$JNI_INCLUDE_DIRS" = "x"; then | |||
have_jni_dependencies=no | |||
fi | |||
if test "x$have_jni_dependencies" = "xno"; then | |||
if test x"$use_jni" = x"yes"; then | |||
AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and Schnorr and try again.]) | |||
fi | |||
AC_MSG_WARN([jni headers/dependencies not found. jni support disabled]) | |||
use_jni=no | |||
else | |||
use_jni=yes | |||
for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do | |||
JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR" | |||
done | |||
fi | |||
fi | |||
@@ -345,18 +431,43 @@ fi | |||
AC_C_BIGENDIAN() | |||
if test x"$use_external_asm" = x"yes"; then | |||
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used]) | |||
fi | |||
AC_MSG_NOTICE([Using static precomputation: $set_precomp]) | |||
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_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) | |||
AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr]) | |||
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery]) | |||
AC_MSG_NOTICE([Using jni: $use_jni]) | |||
if test x"$enable_experimental" = x"yes"; then | |||
AC_MSG_NOTICE([******]) | |||
AC_MSG_NOTICE([WARNING: experimental build]) | |||
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) | |||
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) | |||
AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr]) | |||
AC_MSG_NOTICE([******]) | |||
else | |||
if test x"$enable_module_schnorr" = x"yes"; then | |||
AC_MSG_ERROR([Schnorr signature module is experimental. Use --enable-experimental to allow.]) | |||
fi | |||
if test x"$enable_module_ecdh" = x"yes"; then | |||
AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.]) | |||
fi | |||
if test x"$set_asm" = x"arm"; then | |||
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.]) | |||
fi | |||
fi | |||
AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) | |||
AC_CONFIG_FILES([Makefile libsecp256k1.pc]) | |||
AC_SUBST(JNI_INCLUDES) | |||
AC_SUBST(SECP_INCLUDES) | |||
AC_SUBST(SECP_LIBS) | |||
AC_SUBST(SECP_TEST_LIBS) | |||
@@ -367,6 +478,9 @@ AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_pr | |||
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) | |||
AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"]) | |||
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) | |||
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"]) | |||
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"]) | |||
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"]) | |||
dnl make sure nothing new is exported so that we don't break the cache | |||
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" |
@@ -5,7 +5,7 @@ includedir=@includedir@ | |||
Name: libsecp256k1 | |||
Description: Optimized C library for EC operations on curve secp256k1 | |||
URL: https://github.com/bitcoin/secp256k1 | |||
URL: https://github.com/bitcoin-core/secp256k1 | |||
Version: @PACKAGE_VERSION@ | |||
Cflags: -I${includedir} | |||
Libs.private: @SECP_LIBS@ |
@@ -0,0 +1,322 @@ | |||
# This code supports verifying group implementations which have branches | |||
# or conditional statements (like cmovs), by allowing each execution path | |||
# to independently set assumptions on input or intermediary variables. | |||
# | |||
# The general approach is: | |||
# * A constraint is a tuple of two sets of of symbolic expressions: | |||
# the first of which are required to evaluate to zero, the second of which | |||
# are required to evaluate to nonzero. | |||
# - A constraint is said to be conflicting if any of its nonzero expressions | |||
# is in the ideal with basis the zero expressions (in other words: when the | |||
# zero expressions imply that one of the nonzero expressions are zero). | |||
# * There is a list of laws that describe the intended behaviour, including | |||
# laws for addition and doubling. Each law is called with the symbolic point | |||
# coordinates as arguments, and returns: | |||
# - A constraint describing the assumptions under which it is applicable, | |||
# called "assumeLaw" | |||
# - A constraint describing the requirements of the law, called "require" | |||
# * Implementations are transliterated into functions that operate as well on | |||
# algebraic input points, and are called once per combination of branches | |||
# exectured. Each execution returns: | |||
# - A constraint describing the assumptions this implementation requires | |||
# (such as Z1=1), called "assumeFormula" | |||
# - A constraint describing the assumptions this specific branch requires, | |||
# but which is by construction guaranteed to cover the entire space by | |||
# merging the results from all branches, called "assumeBranch" | |||
# - The result of the computation | |||
# * All combinations of laws with implementation branches are tried, and: | |||
# - If the combination of assumeLaw, assumeFormula, and assumeBranch results | |||
# in a conflict, it means this law does not apply to this branch, and it is | |||
# skipped. | |||
# - For others, we try to prove the require constraints hold, assuming the | |||
# information in assumeLaw + assumeFormula + assumeBranch, and if this does | |||
# not succeed, we fail. | |||
# + To prove an expression is zero, we check whether it belongs to the | |||
# ideal with the assumed zero expressions as basis. This test is exact. | |||
# + To prove an expression is nonzero, we check whether each of its | |||
# factors is contained in the set of nonzero assumptions' factors. | |||
# This test is not exact, so various combinations of original and | |||
# reduced expressions' factors are tried. | |||
# - If we succeed, we print out the assumptions from assumeFormula that | |||
# weren't implied by assumeLaw already. Those from assumeBranch are skipped, | |||
# as we assume that all constraints in it are complementary with each other. | |||
# | |||
# Based on the sage verification scripts used in the Explicit-Formulas Database | |||
# by Tanja Lange and others, see http://hyperelliptic.org/EFD | |||
class fastfrac: | |||
"""Fractions over rings.""" | |||
def __init__(self,R,top,bot=1): | |||
"""Construct a fractional, given a ring, a numerator, and denominator.""" | |||
self.R = R | |||
if parent(top) == ZZ or parent(top) == R: | |||
self.top = R(top) | |||
self.bot = R(bot) | |||
elif top.__class__ == fastfrac: | |||
self.top = top.top | |||
self.bot = top.bot * bot | |||
else: | |||
self.top = R(numerator(top)) | |||
self.bot = R(denominator(top)) * bot | |||
def iszero(self,I): | |||
"""Return whether this fraction is zero given an ideal.""" | |||
return self.top in I and self.bot not in I | |||
def reduce(self,assumeZero): | |||
zero = self.R.ideal(map(numerator, assumeZero)) | |||
return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot)) | |||
def __add__(self,other): | |||
"""Add two fractions.""" | |||
if parent(other) == ZZ: | |||
return fastfrac(self.R,self.top + self.bot * other,self.bot) | |||
if other.__class__ == fastfrac: | |||
return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot) | |||
return NotImplemented | |||
def __sub__(self,other): | |||
"""Subtract two fractions.""" | |||
if parent(other) == ZZ: | |||
return fastfrac(self.R,self.top - self.bot * other,self.bot) | |||
if other.__class__ == fastfrac: | |||
return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot) | |||
return NotImplemented | |||
def __neg__(self): | |||
"""Return the negation of a fraction.""" | |||
return fastfrac(self.R,-self.top,self.bot) | |||
def __mul__(self,other): | |||
"""Multiply two fractions.""" | |||
if parent(other) == ZZ: | |||
return fastfrac(self.R,self.top * other,self.bot) | |||
if other.__class__ == fastfrac: | |||
return fastfrac(self.R,self.top * other.top,self.bot * other.bot) | |||
return NotImplemented | |||
def __rmul__(self,other): | |||
"""Multiply something else with a fraction.""" | |||
return self.__mul__(other) | |||
def __div__(self,other): | |||
"""Divide two fractions.""" | |||
if parent(other) == ZZ: | |||
return fastfrac(self.R,self.top,self.bot * other) | |||
if other.__class__ == fastfrac: | |||
return fastfrac(self.R,self.top * other.bot,self.bot * other.top) | |||
return NotImplemented | |||
def __pow__(self,other): | |||
"""Compute a power of a fraction.""" | |||
if parent(other) == ZZ: | |||
if other < 0: | |||
# Negative powers require flipping top and bottom | |||
return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other)) | |||
else: | |||
return fastfrac(self.R,self.top ^ other,self.bot ^ other) | |||
return NotImplemented | |||
def __str__(self): | |||
return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))" | |||
def __repr__(self): | |||
return "%s" % self | |||
def numerator(self): | |||
return self.top | |||
class constraints: | |||
"""A set of constraints, consisting of zero and nonzero expressions. | |||
Constraints can either be used to express knowledge or a requirement. | |||
Both the fields zero and nonzero are maps from expressions to description | |||
strings. The expressions that are the keys in zero are required to be zero, | |||
and the expressions that are the keys in nonzero are required to be nonzero. | |||
Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in | |||
nonzero could be multiplied into a single key. This is often much less | |||
efficient to work with though, so we keep them separate inside the | |||
constraints. This allows higher-level code to do fast checks on the individual | |||
nonzero elements, or combine them if needed for stronger checks. | |||
We can't multiply the different zero elements, as it would suffice for one of | |||
the factors to be zero, instead of all of them. Instead, the zero elements are | |||
typically combined into an ideal first. | |||
""" | |||
def __init__(self, **kwargs): | |||
if 'zero' in kwargs: | |||
self.zero = dict(kwargs['zero']) | |||
else: | |||
self.zero = dict() | |||
if 'nonzero' in kwargs: | |||
self.nonzero = dict(kwargs['nonzero']) | |||
else: | |||
self.nonzero = dict() | |||
def negate(self): | |||
return constraints(zero=self.nonzero, nonzero=self.zero) | |||
def __add__(self, other): | |||
zero = self.zero.copy() | |||
zero.update(other.zero) | |||
nonzero = self.nonzero.copy() | |||
nonzero.update(other.nonzero) | |||
return constraints(zero=zero, nonzero=nonzero) | |||
def __str__(self): | |||
return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero) | |||
def __repr__(self): | |||
return "%s" % self | |||
def conflicts(R, con): | |||
"""Check whether any of the passed non-zero assumptions is implied by the zero assumptions""" | |||
zero = R.ideal(map(numerator, con.zero)) | |||
if 1 in zero: | |||
return True | |||
# First a cheap check whether any of the individual nonzero terms conflict on | |||
# their own. | |||
for nonzero in con.nonzero: | |||
if nonzero.iszero(zero): | |||
return True | |||
# It can be the case that entries in the nonzero set do not individually | |||
# conflict with the zero set, but their combination does. For example, knowing | |||
# that either x or y is zero is equivalent to having x*y in the zero set. | |||
# Having x or y individually in the nonzero set is not a conflict, but both | |||
# simultaneously is, so that is the right thing to check for. | |||
if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero): | |||
return True | |||
return False | |||
def get_nonzero_set(R, assume): | |||
"""Calculate a simple set of nonzero expressions""" | |||
zero = R.ideal(map(numerator, assume.zero)) | |||
nonzero = set() | |||
for nz in map(numerator, assume.nonzero): | |||
for (f,n) in nz.factor(): | |||
nonzero.add(f) | |||
rnz = zero.reduce(nz) | |||
for (f,n) in rnz.factor(): | |||
nonzero.add(f) | |||
return nonzero | |||
def prove_nonzero(R, exprs, assume): | |||
"""Check whether an expression is provably nonzero, given assumptions""" | |||
zero = R.ideal(map(numerator, assume.zero)) | |||
nonzero = get_nonzero_set(R, assume) | |||
expl = set() | |||
ok = True | |||
for expr in exprs: | |||
if numerator(expr) in zero: | |||
return (False, [exprs[expr]]) | |||
allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1) | |||
for (f, n) in allexprs.factor(): | |||
if f not in nonzero: | |||
ok = False | |||
if ok: | |||
return (True, None) | |||
ok = True | |||
for (f, n) in zero.reduce(numerator(allexprs)).factor(): | |||
if f not in nonzero: | |||
ok = False | |||
if ok: | |||
return (True, None) | |||
ok = True | |||
for expr in exprs: | |||
for (f,n) in numerator(expr).factor(): | |||
if f not in nonzero: | |||
ok = False | |||
if ok: | |||
return (True, None) | |||
ok = True | |||
for expr in exprs: | |||
for (f,n) in zero.reduce(numerator(expr)).factor(): | |||
if f not in nonzero: | |||
expl.add(exprs[expr]) | |||
if expl: | |||
return (False, list(expl)) | |||
else: | |||
return (True, None) | |||
def prove_zero(R, exprs, assume): | |||
"""Check whether all of the passed expressions are provably zero, given assumptions""" | |||
r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume) | |||
if not r: | |||
return (False, map(lambda x: "Possibly zero denominator: %s" % x, e)) | |||
zero = R.ideal(map(numerator, assume.zero)) | |||
nonzero = prod(x for x in assume.nonzero) | |||
expl = [] | |||
for expr in exprs: | |||
if not expr.iszero(zero): | |||
expl.append(exprs[expr]) | |||
if not expl: | |||
return (True, None) | |||
return (False, expl) | |||
def describe_extra(R, assume, assumeExtra): | |||
"""Describe what assumptions are added, given existing assumptions""" | |||
zerox = assume.zero.copy() | |||
zerox.update(assumeExtra.zero) | |||
zero = R.ideal(map(numerator, assume.zero)) | |||
zeroextra = R.ideal(map(numerator, zerox)) | |||
nonzero = get_nonzero_set(R, assume) | |||
ret = set() | |||
# Iterate over the extra zero expressions | |||
for base in assumeExtra.zero: | |||
if base not in zero: | |||
add = [] | |||
for (f, n) in numerator(base).factor(): | |||
if f not in nonzero: | |||
add += ["%s" % f] | |||
if add: | |||
ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base]) | |||
# Iterate over the extra nonzero expressions | |||
for nz in assumeExtra.nonzero: | |||
nzr = zeroextra.reduce(numerator(nz)) | |||
if nzr not in zeroextra: | |||
for (f,n) in nzr.factor(): | |||
if zeroextra.reduce(f) not in nonzero: | |||
ret.add("%s != 0" % zeroextra.reduce(f)) | |||
return ", ".join(x for x in ret) | |||
def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require): | |||
"""Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions""" | |||
assume = assumeLaw + assumeAssert + assumeBranch | |||
if conflicts(R, assume): | |||
# This formula does not apply | |||
return None | |||
describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert) | |||
ok, msg = prove_zero(R, require.zero, assume) | |||
if not ok: | |||
return "FAIL, %s fails (assuming %s)" % (str(msg), describe) | |||
res, expl = prove_nonzero(R, require.nonzero, assume) | |||
if not res: | |||
return "FAIL, %s fails (assuming %s)" % (str(expl), describe) | |||
if describe != "": | |||
return "OK (assuming %s)" % describe | |||
else: | |||
return "OK" | |||
def concrete_verify(c): | |||
for k in c.zero: | |||
if k != 0: | |||
return (False, c.zero[k]) | |||
for k in c.nonzero: | |||
if k == 0: | |||
return (False, c.nonzero[k]) | |||
return (True, None) |
@@ -0,0 +1,306 @@ | |||
# Test libsecp256k1' group operation implementations using prover.sage | |||
import sys | |||
load("group_prover.sage") | |||
load("weierstrass_prover.sage") | |||
def formula_secp256k1_gej_double_var(a): | |||
"""libsecp256k1's secp256k1_gej_double_var, used by various addition functions""" | |||
rz = a.Z * a.Y | |||
rz = rz * 2 | |||
t1 = a.X^2 | |||
t1 = t1 * 3 | |||
t2 = t1^2 | |||
t3 = a.Y^2 | |||
t3 = t3 * 2 | |||
t4 = t3^2 | |||
t4 = t4 * 2 | |||
t3 = t3 * a.X | |||
rx = t3 | |||
rx = rx * 4 | |||
rx = -rx | |||
rx = rx + t2 | |||
t2 = -t2 | |||
t3 = t3 * 6 | |||
t3 = t3 + t2 | |||
ry = t1 * t3 | |||
t2 = -t4 | |||
ry = ry + t2 | |||
return jacobianpoint(rx, ry, rz) | |||
def formula_secp256k1_gej_add_var(branch, a, b): | |||
"""libsecp256k1's secp256k1_gej_add_var""" | |||
if branch == 0: | |||
return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b) | |||
if branch == 1: | |||
return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) | |||
z22 = b.Z^2 | |||
z12 = a.Z^2 | |||
u1 = a.X * z22 | |||
u2 = b.X * z12 | |||
s1 = a.Y * z22 | |||
s1 = s1 * b.Z | |||
s2 = b.Y * z12 | |||
s2 = s2 * a.Z | |||
h = -u1 | |||
h = h + u2 | |||
i = -s1 | |||
i = i + s2 | |||
if branch == 2: | |||
r = formula_secp256k1_gej_double_var(a) | |||
return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r) | |||
if branch == 3: | |||
return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity()) | |||
i2 = i^2 | |||
h2 = h^2 | |||
h3 = h2 * h | |||
h = h * b.Z | |||
rz = a.Z * h | |||
t = u1 * h2 | |||
rx = t | |||
rx = rx * 2 | |||
rx = rx + h3 | |||
rx = -rx | |||
rx = rx + i2 | |||
ry = -rx | |||
ry = ry + t | |||
ry = ry * i | |||
h3 = h3 * s1 | |||
h3 = -h3 | |||
ry = ry + h3 | |||
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) | |||
def formula_secp256k1_gej_add_ge_var(branch, a, b): | |||
"""libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1""" | |||
if branch == 0: | |||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b) | |||
if branch == 1: | |||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) | |||
z12 = a.Z^2 | |||
u1 = a.X | |||
u2 = b.X * z12 | |||
s1 = a.Y | |||
s2 = b.Y * z12 | |||
s2 = s2 * a.Z | |||
h = -u1 | |||
h = h + u2 | |||
i = -s1 | |||
i = i + s2 | |||
if (branch == 2): | |||
r = formula_secp256k1_gej_double_var(a) | |||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) | |||
if (branch == 3): | |||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) | |||
i2 = i^2 | |||
h2 = h^2 | |||
h3 = h * h2 | |||
rz = a.Z * h | |||
t = u1 * h2 | |||
rx = t | |||
rx = rx * 2 | |||
rx = rx + h3 | |||
rx = -rx | |||
rx = rx + i2 | |||
ry = -rx | |||
ry = ry + t | |||
ry = ry * i | |||
h3 = h3 * s1 | |||
h3 = -h3 | |||
ry = ry + h3 | |||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) | |||
def formula_secp256k1_gej_add_zinv_var(branch, a, b): | |||
"""libsecp256k1's secp256k1_gej_add_zinv_var""" | |||
bzinv = b.Z^(-1) | |||
if branch == 0: | |||
return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a) | |||
if branch == 1: | |||
bzinv2 = bzinv^2 | |||
bzinv3 = bzinv2 * bzinv | |||
rx = b.X * bzinv2 | |||
ry = b.Y * bzinv3 | |||
rz = 1 | |||
return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz)) | |||
azz = a.Z * bzinv | |||
z12 = azz^2 | |||
u1 = a.X | |||
u2 = b.X * z12 | |||
s1 = a.Y | |||
s2 = b.Y * z12 | |||
s2 = s2 * azz | |||
h = -u1 | |||
h = h + u2 | |||
i = -s1 | |||
i = i + s2 | |||
if branch == 2: | |||
r = formula_secp256k1_gej_double_var(a) | |||
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) | |||
if branch == 3: | |||
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) | |||
i2 = i^2 | |||
h2 = h^2 | |||
h3 = h * h2 | |||
rz = a.Z | |||
rz = rz * h | |||
t = u1 * h2 | |||
rx = t | |||
rx = rx * 2 | |||
rx = rx + h3 | |||
rx = -rx | |||
rx = rx + i2 | |||
ry = -rx | |||
ry = ry + t | |||
ry = ry * i | |||
h3 = h3 * s1 | |||
h3 = -h3 | |||
ry = ry + h3 | |||
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) | |||
def formula_secp256k1_gej_add_ge(branch, a, b): | |||
"""libsecp256k1's secp256k1_gej_add_ge""" | |||
zeroes = {} | |||
nonzeroes = {} | |||
a_infinity = False | |||
if (branch & 4) != 0: | |||
nonzeroes.update({a.Infinity : 'a_infinite'}) | |||
a_infinity = True | |||
else: | |||
zeroes.update({a.Infinity : 'a_finite'}) | |||
zz = a.Z^2 | |||
u1 = a.X | |||
u2 = b.X * zz | |||
s1 = a.Y | |||
s2 = b.Y * zz | |||
s2 = s2 * a.Z | |||
t = u1 | |||
t = t + u2 | |||
m = s1 | |||
m = m + s2 | |||
rr = t^2 | |||
m_alt = -u2 | |||
tt = u1 * m_alt | |||
rr = rr + tt | |||
degenerate = (branch & 3) == 3 | |||
if (branch & 1) != 0: | |||
zeroes.update({m : 'm_zero'}) | |||
else: | |||
nonzeroes.update({m : 'm_nonzero'}) | |||
if (branch & 2) != 0: | |||
zeroes.update({rr : 'rr_zero'}) | |||
else: | |||
nonzeroes.update({rr : 'rr_nonzero'}) | |||
rr_alt = s1 | |||
rr_alt = rr_alt * 2 | |||
m_alt = m_alt + u1 | |||
if not degenerate: | |||
rr_alt = rr | |||
m_alt = m | |||
n = m_alt^2 | |||
q = n * t | |||
n = n^2 | |||
if degenerate: | |||
n = m | |||
t = rr_alt^2 | |||
rz = a.Z * m_alt | |||
infinity = False | |||
if (branch & 8) != 0: | |||
if not a_infinity: | |||
infinity = True | |||
zeroes.update({rz : 'r.z=0'}) | |||
else: | |||
nonzeroes.update({rz : 'r.z!=0'}) | |||
rz = rz * 2 | |||
q = -q | |||
t = t + q | |||
rx = t | |||
t = t * 2 | |||
t = t + q | |||
t = t * rr_alt | |||
t = t + n | |||
ry = -t | |||
rx = rx * 4 | |||
ry = ry * 4 | |||
if a_infinity: | |||
rx = b.X | |||
ry = b.Y | |||
rz = 1 | |||
if infinity: | |||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) | |||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) | |||
def formula_secp256k1_gej_add_ge_old(branch, a, b): | |||
"""libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx""" | |||
a_infinity = (branch & 1) != 0 | |||
zero = {} | |||
nonzero = {} | |||
if a_infinity: | |||
nonzero.update({a.Infinity : 'a_infinite'}) | |||
else: | |||
zero.update({a.Infinity : 'a_finite'}) | |||
zz = a.Z^2 | |||
u1 = a.X | |||
u2 = b.X * zz | |||
s1 = a.Y | |||
s2 = b.Y * zz | |||
s2 = s2 * a.Z | |||
z = a.Z | |||
t = u1 | |||
t = t + u2 | |||
m = s1 | |||
m = m + s2 | |||
n = m^2 | |||
q = n * t | |||
n = n^2 | |||
rr = t^2 | |||
t = u1 * u2 | |||
t = -t | |||
rr = rr + t | |||
t = rr^2 | |||
rz = m * z | |||
infinity = False | |||
if (branch & 2) != 0: | |||
if not a_infinity: | |||
infinity = True | |||
else: | |||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity()) | |||
zero.update({rz : 'r.z=0'}) | |||
else: | |||
nonzero.update({rz : 'r.z!=0'}) | |||
rz = rz * (0 if a_infinity else 2) | |||
rx = t | |||
q = -q | |||
rx = rx + q | |||
q = q * 3 | |||
t = t * 2 | |||
t = t + q | |||
t = t * rr | |||
t = t + n | |||
ry = -t | |||
rx = rx * (0 if a_infinity else 4) | |||
ry = ry * (0 if a_infinity else 4) | |||
t = b.X | |||
t = t * (1 if a_infinity else 0) | |||
rx = rx + t | |||
t = b.Y | |||
t = t * (1 if a_infinity else 0) | |||
ry = ry + t | |||
t = (1 if a_infinity else 0) | |||
rz = rz + t | |||
if infinity: | |||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity()) | |||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz)) | |||
if __name__ == "__main__": | |||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var) | |||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var) | |||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var) | |||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge) | |||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old) | |||
if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": | |||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43) | |||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43) | |||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43) | |||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43) | |||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43) |
@@ -0,0 +1,264 @@ | |||
# Prover implementation for Weierstrass curves of the form | |||
# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws | |||
# operating on affine and Jacobian coordinates, including the point at infinity | |||
# represented by a 4th variable in coordinates. | |||
load("group_prover.sage") | |||
class affinepoint: | |||
def __init__(self, x, y, infinity=0): | |||
self.x = x | |||
self.y = y | |||
self.infinity = infinity | |||
def __str__(self): | |||
return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity) | |||
class jacobianpoint: | |||
def __init__(self, x, y, z, infinity=0): | |||
self.X = x | |||
self.Y = y | |||
self.Z = z | |||
self.Infinity = infinity | |||
def __str__(self): | |||
return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity) | |||
def point_at_infinity(): | |||
return jacobianpoint(1, 1, 1, 1) | |||
def negate(p): | |||
if p.__class__ == affinepoint: | |||
return affinepoint(p.x, -p.y) | |||
if p.__class__ == jacobianpoint: | |||
return jacobianpoint(p.X, -p.Y, p.Z) | |||
assert(False) | |||
def on_weierstrass_curve(A, B, p): | |||
"""Return a set of zero-expressions for an affine point to be on the curve""" | |||
return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'}) | |||
def tangential_to_weierstrass_curve(A, B, p12, p3): | |||
"""Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)""" | |||
return constraints(zero={ | |||
(p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve' | |||
}) | |||
def colinear(p1, p2, p3): | |||
"""Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear""" | |||
return constraints(zero={ | |||
(p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1', | |||
(p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2', | |||
(p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3' | |||
}) | |||
def good_affine_point(p): | |||
return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'}) | |||
def good_jacobian_point(p): | |||
return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'}) | |||
def good_point(p): | |||
return constraints(nonzero={p.Z^6 : 'nonzero_X'}) | |||
def finite(p, *affine_fns): | |||
con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'}) | |||
if p.Z != 0: | |||
return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con) | |||
else: | |||
return con | |||
def infinite(p): | |||
return constraints(nonzero={p.Infinity : 'infinite_point'}) | |||
def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC): | |||
"""Check whether the passed set of coordinates is a valid Jacobian add, given assumptions""" | |||
assumeLaw = (good_affine_point(pa) + | |||
good_affine_point(pb) + | |||
good_jacobian_point(pA) + | |||
good_jacobian_point(pB) + | |||
on_weierstrass_curve(A, B, pa) + | |||
on_weierstrass_curve(A, B, pb) + | |||
finite(pA) + | |||
finite(pB) + | |||
constraints(nonzero={pa.x - pb.x : 'different_x'})) | |||
require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + | |||
colinear(pa, pb, negate(pc)))) | |||
return (assumeLaw, require) | |||
def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC): | |||
"""Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions""" | |||
assumeLaw = (good_affine_point(pa) + | |||
good_affine_point(pb) + | |||
good_jacobian_point(pA) + | |||
good_jacobian_point(pB) + | |||
on_weierstrass_curve(A, B, pa) + | |||
on_weierstrass_curve(A, B, pb) + | |||
finite(pA) + | |||
finite(pB) + | |||
constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'})) | |||
require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + | |||
tangential_to_weierstrass_curve(A, B, pa, negate(pc)))) | |||
return (assumeLaw, require) | |||
def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC): | |||
assumeLaw = (good_affine_point(pa) + | |||
good_affine_point(pb) + | |||
good_jacobian_point(pA) + | |||
good_jacobian_point(pB) + | |||
on_weierstrass_curve(A, B, pa) + | |||
on_weierstrass_curve(A, B, pb) + | |||
finite(pA) + | |||
finite(pB) + | |||
constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'})) | |||
require = infinite(pC) | |||
return (assumeLaw, require) | |||
def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC): | |||
assumeLaw = (good_affine_point(pa) + | |||
good_affine_point(pb) + | |||
good_jacobian_point(pA) + | |||
good_jacobian_point(pB) + | |||
on_weierstrass_curve(A, B, pb) + | |||
infinite(pA) + | |||
finite(pB)) | |||
require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'})) | |||
return (assumeLaw, require) | |||
def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC): | |||
assumeLaw = (good_affine_point(pa) + | |||
good_affine_point(pb) + | |||
good_jacobian_point(pA) + | |||
good_jacobian_point(pB) + | |||
on_weierstrass_curve(A, B, pa) + | |||
infinite(pB) + | |||
finite(pA)) | |||
require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'})) | |||
return (assumeLaw, require) | |||
def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC): | |||
assumeLaw = (good_affine_point(pa) + | |||
good_affine_point(pb) + | |||
good_jacobian_point(pA) + | |||
good_jacobian_point(pB) + | |||
infinite(pA) + | |||
infinite(pB)) | |||
require = infinite(pC) | |||
return (assumeLaw, require) | |||
laws_jacobian_weierstrass = { | |||
'add': law_jacobian_weierstrass_add, | |||
'double': law_jacobian_weierstrass_double, | |||
'add_opposite': law_jacobian_weierstrass_add_opposites, | |||
'add_infinite_a': law_jacobian_weierstrass_add_infinite_a, | |||
'add_infinite_b': law_jacobian_weierstrass_add_infinite_b, | |||
'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab | |||
} | |||
def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p): | |||
"""Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field""" | |||
F = Integers(p) | |||
print "Formula %s on Z%i:" % (name, p) | |||
points = [] | |||
for x in xrange(0, p): | |||
for y in xrange(0, p): | |||
point = affinepoint(F(x), F(y)) | |||
r, e = concrete_verify(on_weierstrass_curve(A, B, point)) | |||
if r: | |||
points.append(point) | |||
for za in xrange(1, p): | |||
for zb in xrange(1, p): | |||
for pa in points: | |||
for pb in points: | |||
for ia in xrange(2): | |||
for ib in xrange(2): | |||
pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia) | |||
pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib) | |||
for branch in xrange(0, branches): | |||
assumeAssert, assumeBranch, pC = formula(branch, pA, pB) | |||
pC.X = F(pC.X) | |||
pC.Y = F(pC.Y) | |||
pC.Z = F(pC.Z) | |||
pC.Infinity = F(pC.Infinity) | |||
r, e = concrete_verify(assumeAssert + assumeBranch) | |||
if r: | |||
match = False | |||
for key in laws_jacobian_weierstrass: | |||
assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC) | |||
r, e = concrete_verify(assumeLaw) | |||
if r: | |||
if match: | |||
print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity) | |||
else: | |||
match = True | |||
r, e = concrete_verify(require) | |||
if not r: | |||
print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e) | |||
def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC): | |||
assumeLaw, require = f(A, B, pa, pb, pA, pB, pC) | |||
return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require) | |||
def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula): | |||
"""Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically""" | |||
R.<ax,bx,ay,by,Az,Bz,Ai,Bi> = PolynomialRing(QQ,8,order='invlex') | |||
lift = lambda x: fastfrac(R,x) | |||
ax = lift(ax) | |||
ay = lift(ay) | |||
Az = lift(Az) | |||
bx = lift(bx) | |||
by = lift(by) | |||
Bz = lift(Bz) | |||
Ai = lift(Ai) | |||
Bi = lift(Bi) | |||
pa = affinepoint(ax, ay, Ai) | |||
pb = affinepoint(bx, by, Bi) | |||
pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai) | |||
pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi) | |||
res = {} | |||
for key in laws_jacobian_weierstrass: | |||
res[key] = [] | |||
print ("Formula " + name + ":") | |||
count = 0 | |||
for branch in xrange(branches): | |||
assumeFormula, assumeBranch, pC = formula(branch, pA, pB) | |||
pC.X = lift(pC.X) | |||
pC.Y = lift(pC.Y) | |||
pC.Z = lift(pC.Z) | |||
pC.Infinity = lift(pC.Infinity) | |||
for key in laws_jacobian_weierstrass: | |||
res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch)) | |||
for key in res: | |||
print " %s:" % key | |||
val = res[key] | |||
for x in val: | |||
if x[0] is not None: | |||
print " branch %i: %s" % (x[1], x[0]) | |||
@@ -0,0 +1,919 @@ | |||
@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm: | |||
/********************************************************************** | |||
* Copyright (c) 2014 Wladimir J. van der Laan * | |||
* Distributed under the MIT software license, see the accompanying * | |||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.* | |||
**********************************************************************/ | |||
/* | |||
ARM implementation of field_10x26 inner loops. | |||
Note: | |||
- To avoid unnecessary loads and make use of available registers, two | |||
'passes' have every time been interleaved, with the odd passes accumulating c' and d' | |||
which will be added to c and d respectively in the the even passes | |||
*/ | |||
.syntax unified | |||
.arch armv7-a | |||
@ eabi attributes - see readelf -A | |||
.eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes | |||
.eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no | |||
.eabi_attribute 10, 0 @ Tag_FP_arch = none | |||
.eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte | |||
.eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP | |||
.eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed | |||
.eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6 | |||
.text | |||
@ Field constants | |||
.set field_R0, 0x3d10 | |||
.set field_R1, 0x400 | |||
.set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff | |||
.align 2 | |||
.global secp256k1_fe_mul_inner | |||
.type secp256k1_fe_mul_inner, %function | |||
@ Arguments: | |||
@ r0 r Restrict: can overlap with a, not with b | |||
@ r1 a | |||
@ r2 b | |||
@ Stack (total 4+10*4 = 44) | |||
@ sp + #0 saved 'r' pointer | |||
@ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 | |||
secp256k1_fe_mul_inner: | |||
stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} | |||
sub sp, sp, #48 @ frame=44 + alignment | |||
str r0, [sp, #0] @ save result address, we need it only at the end | |||
/****************************************** | |||
* Main computation code. | |||
****************************************** | |||
Allocation: | |||
r0,r14,r7,r8 scratch | |||
r1 a (pointer) | |||
r2 b (pointer) | |||
r3:r4 c | |||
r5:r6 d | |||
r11:r12 c' | |||
r9:r10 d' | |||
Note: do not write to r[] here, it may overlap with a[] | |||
*/ | |||
/* A - interleaved with B */ | |||
ldr r7, [r1, #0*4] @ a[0] | |||
ldr r8, [r2, #9*4] @ b[9] | |||
ldr r0, [r1, #1*4] @ a[1] | |||
umull r5, r6, r7, r8 @ d = a[0] * b[9] | |||
ldr r14, [r2, #8*4] @ b[8] | |||
umull r9, r10, r0, r8 @ d' = a[1] * b[9] | |||
ldr r7, [r1, #2*4] @ a[2] | |||
umlal r5, r6, r0, r14 @ d += a[1] * b[8] | |||
ldr r8, [r2, #7*4] @ b[7] | |||
umlal r9, r10, r7, r14 @ d' += a[2] * b[8] | |||
ldr r0, [r1, #3*4] @ a[3] | |||
umlal r5, r6, r7, r8 @ d += a[2] * b[7] | |||
ldr r14, [r2, #6*4] @ b[6] | |||
umlal r9, r10, r0, r8 @ d' += a[3] * b[7] | |||
ldr r7, [r1, #4*4] @ a[4] | |||
umlal r5, r6, r0, r14 @ d += a[3] * b[6] | |||
ldr r8, [r2, #5*4] @ b[5] | |||
umlal r9, r10, r7, r14 @ d' += a[4] * b[6] | |||
ldr r0, [r1, #5*4] @ a[5] | |||
umlal r5, r6, r7, r8 @ d += a[4] * b[5] | |||
ldr r14, [r2, #4*4] @ b[4] | |||
umlal r9, r10, r0, r8 @ d' += a[5] * b[5] | |||
ldr r7, [r1, #6*4] @ a[6] | |||
umlal r5, r6, r0, r14 @ d += a[5] * b[4] | |||
ldr r8, [r2, #3*4] @ b[3] | |||
umlal r9, r10, r7, r14 @ d' += a[6] * b[4] | |||
ldr r0, [r1, #7*4] @ a[7] | |||
umlal r5, r6, r7, r8 @ d += a[6] * b[3] | |||
ldr r14, [r2, #2*4] @ b[2] | |||
umlal r9, r10, r0, r8 @ d' += a[7] * b[3] | |||
ldr r7, [r1, #8*4] @ a[8] | |||
umlal r5, r6, r0, r14 @ d += a[7] * b[2] | |||
ldr r8, [r2, #1*4] @ b[1] | |||
umlal r9, r10, r7, r14 @ d' += a[8] * b[2] | |||
ldr r0, [r1, #9*4] @ a[9] | |||
umlal r5, r6, r7, r8 @ d += a[8] * b[1] | |||
ldr r14, [r2, #0*4] @ b[0] | |||
umlal r9, r10, r0, r8 @ d' += a[9] * b[1] | |||
ldr r7, [r1, #0*4] @ a[0] | |||
umlal r5, r6, r0, r14 @ d += a[9] * b[0] | |||
@ r7,r14 used in B | |||
bic r0, r5, field_not_M @ t9 = d & M | |||
str r0, [sp, #4 + 4*9] | |||
mov r5, r5, lsr #26 @ d >>= 26 | |||
orr r5, r5, r6, asl #6 | |||
mov r6, r6, lsr #26 | |||
/* B */ | |||
umull r3, r4, r7, r14 @ c = a[0] * b[0] | |||
adds r5, r5, r9 @ d += d' | |||
adc r6, r6, r10 | |||
bic r0, r5, field_not_M @ u0 = d & M | |||
mov r5, r5, lsr #26 @ d >>= 26 | |||
orr r5, r5, r6, asl #6 | |||
mov r6, r6, lsr #26 | |||
movw r14, field_R0 @ c += u0 * R0 | |||
umlal r3, r4, r0, r14 | |||
bic r14, r3, field_not_M @ t0 = c & M | |||
str r14, [sp, #4 + 0*4] | |||
mov r3, r3, lsr #26 @ c >>= 26 | |||
orr r3, r3, r4, asl #6 | |||
mov r4, r4, lsr #26 | |||
mov r14, field_R1 @ c += u0 * R1 | |||
umlal r3, r4, r0, r14 | |||
/* C - interleaved with D */ | |||
ldr r7, [r1, #0*4] @ a[0] | |||
ldr r8, [r2, #2*4] @ b[2] | |||
ldr r14, [r2, #1*4] @ b[1] | |||
umull r11, r12, r7, r8 @ c' = a[0] * b[2] | |||
ldr r0, [r1, #1*4] @ a[1] | |||
umlal r3, r4, r7, r14 @ c += a[0] * b[1] | |||
ldr r8, [r2, #0*4] @ b[0] | |||
umlal r11, r12, r0, r14 @ c' += a[1] * b[1] | |||
ldr r7, [r1, #2*4] @ a[2] | |||
umlal r3, r4, r0, r8 @ c += a[1] * b[0] | |||
ldr r14, [r2, #9*4] @ b[9] | |||
umlal r11, r12, r7, r8 @ c' += a[2] * b[0] | |||
ldr r0, [r1, #3*4] @ a[3] | |||
umlal r5, r6, r7, r14 @ d += a[2] * b[9] | |||
ldr r8, [r2, #8*4] @ b[8] | |||
umull r9, r10, r0, r14 @ d' = a[3] * b[9] | |||
ldr r7, [r1, #4*4] @ a[4] | |||
umlal r5, r6, r0, r8 @ d += a[3] * b[8] | |||
ldr r14, [r2, #7*4] @ b[7] | |||
umlal r9, r10, r7, r8 @ d' += a[4] * b[8] | |||
ldr r0, [r1, #5*4] @ a[5] | |||
umlal r5, r6, r7, r14 @ d += a[4] * b[7] | |||
ldr r8, [r2, #6*4] @ b[6] | |||
umlal r9, r10, r0, r14 @ d' += a[5] * b[7] | |||
ldr r7, [r1, #6*4] @ a[6] | |||
umlal r5, r6, r0, r8 @ d += a[5] * b[6] | |||
ldr r14, [r2, #5*4] @ b[5] | |||
umlal r9, r10, r7, r8 @ d' += a[6] * b[6] | |||
ldr r0, [r1, #7*4] @ a[7] | |||
umlal r5, r6, r7, r14 @ d += a[6] * b[5] | |||
ldr r8, [r2, #4*4] @ b[4] | |||
umlal r9, r10, r0, r14 @ d' += a[7] * b[5] | |||
ldr r7, [r1, #8*4] @ a[8] | |||
umlal r5, r6, r0, r8 @ d += a[7] * b[4] | |||
ldr r14, [r2, #3*4] @ b[3] | |||
umlal r9, r10, r7, r8 @ d' += a[8] * b[4] | |||
ldr r0, [r1, #9*4] @ a[9] | |||
umlal r5, r6, r7, r14 @ d += a[8] * b[3] | |||
ldr r8, [r2, #2*4] @ b[2] | |||
umlal r9, r10, r0, r14 @ d' += a[9] * b[3] | |||
umlal r5, r6, r0, r8 @ d += a[9] * b[2] | |||
bic r0, r5, field_not_M @ u1 = d & M | |||
mov r5, r5, lsr #26 @ d >>= 26 | |||
orr r5, r5, r6, asl #6 | |||
mov r6, r6, lsr #26 | |||
movw r14, field_R0 @ c += u1 * R0 | |||
umlal r3, r4, r0, r14 | |||
bic r14, r3, field_not_M @ t1 = c & M | |||
str r14, [sp, #4 + 1*4] | |||
mov r3, r3, lsr #26 @ c >>= 26 | |||
orr r3, r3, r4, asl #6 | |||
mov r4, r4, lsr #26 | |||
mov r14, field_R1 @ c += u1 * R1 | |||
umlal r3, r4, r0, r14 | |||
/* D */ | |||
adds r3, r3, r11 @ c += c' | |||
adc r4, r4, r12 | |||
adds r5, r5, r9 @ d += d' | |||
adc r6, r6, r10 | |||
bic r0, r5, field_not_M @ u2 = d & M | |||
mov r5, r5, lsr #26 @ d >>= 26 | |||
orr r5, r5, r6, asl #6 | |||
mov r6, r6, lsr #26 | |||
movw r14, field_R0 @ c += u2 * R0 | |||
umlal r3, r4, r0, r14 | |||
bic r14, r3, field_not_M @ t2 = c & M | |||
str r14, [sp, #4 + 2*4] | |||
mov r3, r3, lsr #26 @ c >>= 26 | |||
orr r3, r3, r4, asl #6 | |||
mov r4, r4, lsr #26 | |||
mov r14, field_R1 @ c += u2 * R1 | |||
umlal r3, r4, r0, r14 | |||
/* E - interleaved with F */ | |||
ldr r7, [r1, #0*4] @ a[0] | |||
ldr r8, [r2, #4*4] @ b[4] | |||
umull r11, r12, r7, r8 @ c' = a[0] * b[4] | |||
ldr r8, [r2, #3*4] @ b[3] | |||
umlal r3, r4, r7, r8 @ c += a[0] * b[3] | |||
ldr r7, [r1, #1*4] @ a[1] | |||
umlal r11, r12, r7, r8 @ c' += a[1] * b[3] | |||
ldr r8, [r2, #2*4] @ b[2] | |||
umlal r3, r4, r7, r8 @ c += a[1] * b[2] | |||
ldr r7, [r1, #2*4] @ a[2] | |||
umlal r11, r12, r7, r8 @ c' += a[2] * b[2] | |||
ldr r8, [r2, #1*4] @ b[1] | |||
umlal r3, r4, r7, r8 @ c += a[2] * b[1] | |||
ldr r7, [r1, #3*4] @ a[3] | |||
umlal r11, r12, r7, r8 @ c' += a[3] * b[1] | |||
ldr r8, [r2, #0*4] @ b[0] | |||
umlal r3, r4, r7, r8 @ c += a[3] * b[0] | |||
ldr r7, [r1, #4*4] @ a[4] | |||
umlal r11, r12, r7, r8 @ c' += a[4] * b[0] | |||
ldr r8, [r2, #9*4] @ b[9] | |||
umlal r5, r6, r7, r8 @ d += a[4] * b[9] | |||
ldr r7, [r1, #5*4] @ a[5] | |||
umull r9, r10, r7, r8 @ d' = a[5] * b[9] | |||
ldr r8, [r2, #8*4] @ b[8] | |||
umlal r5, r6, r7, r8 @ d += a[5] * b[8] | |||
ldr r7, [r1, #6*4] @ a[6] | |||
umlal r9, r10, r7, r8 @ d' += a[6] * b[8] | |||
ldr r8, [r2, #7*4] @ b[7] | |||
umlal r5, r6, r7, r8 @ d += a[6] * b[7] | |||
ldr r7, [r1, #7*4] @ a[7] | |||
umlal r9, r10, r7, r8 @ d' += a[7] * b[7] | |||
ldr r8, [r2, #6*4] @ b[6] | |||
umlal r5, r6, r7, r8 @ d += a[7] * b[6] | |||
ldr r7, [r1, #8*4] @ a[8] | |||
umlal r9, r10, r7, r8 @ d' += a[8] * b[6] | |||
ldr r8, [r2, #5*4] @ b[5] | |||
umlal r5, r6, r7, r8 @ d += a[8] * b[5] | |||
ldr r7, [r1, #9*4] @ a[9] | |||
umlal r9, r10, r7, r8 @ d' += a[9] * b[5] | |||
ldr r8, [r2, #4*4] @ b[4] | |||
umlal r5, r6, r7, r8 @ d += a[9] * b[4] | |||
bic r0, r5, field_not_M @ u3 = d & M | |||
mov r5, r5, lsr #26 @ d >>= 26 | |||
orr r5, r5, r6, asl #6 | |||
mov r6, r6, lsr #26 | |||
movw r14, field_R0 @ c += u3 * R0 | |||
umlal r3, r4, r0, r14 | |||
bic r14, r3, field_not_M @ t3 = c & M | |||
str r14, [sp, #4 + 3*4] | |||
mov r3, r3, lsr #26 @ c >>= 26 | |||
orr r3, r3, r4, asl #6 | |||
mov r4, r4, lsr #26 | |||
mov r14, field_R1 @ c += u3 * R1 | |||
umlal r3, r4, r0, r14 | |||
/* F */ | |||
adds r3, r3, r11 @ c += c' | |||
adc r4, r4, r12 | |||
adds r5, r5, r9 @ d += d' | |||
adc r6, r6, r10 | |||
bic r0, r5, field_not_M @ u4 = d & M | |||
mov r5, r5, lsr #26 @ d >>= 26 | |||
orr r5, r5, r6, asl #6 | |||
mov r6, r6, lsr #26 | |||
movw r14, field_R0 @ c += u4 * R0 | |||
umlal r3, r4, r0, r14 | |||
bic r14, r3, field_not_M @ t4 = c & M | |||
str r14, [sp, #4 + 4*4] | |||
mov r3, r3, lsr #26 @ c >>= 26 | |||
orr r3, r3, r4, asl #6 | |||
mov r4, r4, lsr #26 | |||
mov r14, field_R1 @ c += u4 * R1 | |||
umlal r3, r4, r0, r14 | |||
/* G - interleaved with H */ | |||
ldr r7, [r1, #0*4] @ a[0] | |||
ldr r8, [r2, #6*4] @ b[6] | |||
ldr r14, [r2, #5*4] @ b[5] | |||
umull r11, r12, r7, r8 @ c' = a[0] * b[6] | |||
ldr r0, [r1, #1*4] @ a[1] | |||
umlal r3, r4, r7, r14 @ c += a[0] * b[5] | |||
ldr r8, [r2, #4*4] @ b[4] | |||
umlal r11, r12, r0, r14 @ c' += a[1] * b[5] | |||
ldr r7, [r1, #2*4] @ a[2] | |||
umlal r3, r4, r0, r8 @ c += a[1] * b[4] | |||
ldr r14, [r2, #3*4] @ b[3] | |||
umlal r11, r12, r7, r8 @ c' += a[2] * b[4] | |||
ldr r0, [r1, #3*4] @ a[3] | |||
umlal r3, r4, r7, r14 @ c += a[2] * b[3] | |||
ldr r8, [r2, #2*4] @ b[2] | |||
umlal r11, r12, r0, r14 @ c' += a[3] * b[3] | |||
ldr r7, [r1, #4*4] @ a[4] | |||
umlal r3, r4, r0, r8 @ c += a[3] * b[2] | |||
ldr r14, [r2, #1*4] @ b[1] | |||
umlal r11, r12, r7, r8 @ c' += a[4] * b[2] | |||
ldr r0, [r1, #5*4] @ a[5] | |||
umlal r3, r4, r7, r14 @ c += a[4] * b[1] | |||
ldr r8, [r2, #0*4] @ b[0] | |||
umlal r11, r12, r0, r14 @ c' += a[5] * b[1] | |||
ldr r7, [r1, #6*4] @ a[6] | |||
umlal r3, r4, r0, r8 @ c += a[5] * b[0] | |||
ldr r14, [r2, #9*4] @ b[9] | |||
umlal r11, r12, r7, r8 @ c' += a[6] * b[0] | |||
ldr r0, [r1, #7*4] @ a[7] | |||
umlal r5, r6, r7, r14 @ d += a[6] * b[9] | |||
ldr r8, [r2, #8*4] @ b[8] | |||
umull r9, r10, r0, r14 @ d' = a[7] * b[9] | |||
ldr r7, [r1, #8*4] @ a[8] | |||
umlal r5, r6, r0, r8 @ d += a[7] * b[8] | |||
ldr r14, [r2, #7*4] @ b[7] | |||
umlal r9, r10, r7, r8 @ d' += a[8] * b[8] | |||
ldr r0, [r1, #9*4] @ a[9] | |||
umlal r5, r6, r7, r14 @ d += a[8] * b[7] | |||
ldr r8, [r2, #6*4] @ b[6] | |||
umlal r9, r10, r0, r14 @ d' += a[9] * b[7] | |||
umlal r5, r6, r0, r8 @ d += a[9] * b[6] | |||
bic r0, r5, field_not_M @ u5 = d & M | |||
mov r5, r5, lsr #26 @ d >>= 26 | |||
orr r5, r5, r6, asl #6 | |||
mov r6, r6, lsr #26 | |||
movw r14, field_R0 @ c += u5 * R0 | |||
umlal r3, r4, r0, r14 | |||
bic r14, r3, field_not_M @ t5 = c & M | |||
str r14, [sp, #4 + 5*4] | |||
mov r3, r3, lsr #26 @ c >>= 26 | |||
orr r3, r3, r4, asl #6 | |||
mov r4, r4, lsr #26 | |||
mov r14, field_R1 @ c += u5 * R1 | |||
umlal r3, r4, r0, r14 | |||
/* H */ | |||
adds r3, r3, r11 @ c += c' | |||
adc r4, r4, r12 | |||
adds r5, r5, r9 @ d += d' | |||
adc r6, r6, r10 | |||
bic r0, r5, field_not_M @ u6 = d & M | |||
mov r5, r5, lsr #26 @ d >>= 26 | |||
orr r5, r5, r6, asl #6 | |||
mov r6, r6, lsr #26 | |||
movw r14, field_R0 @ c += u6 * R0 | |||
umlal r3, r4, r0, r14 | |||
bic r14, r3, field_not_M @ t6 = c & M | |||
str r14, [sp, #4 + 6*4] | |||
mov r3, r3, lsr #26 @ c >>= 26 | |||
orr r3, r3, r4, asl #6 | |||
mov r4, r4, lsr #26 | |||
mov r14, field_R1 @ c += u6 * R1 | |||
umlal r3, r4, r0, r14 | |||
/* I - interleaved with J */ | |||
ldr r8, [r2, #8*4] @ b[8] | |||
ldr r7, [r1, #0*4] @ a[0] | |||
ldr r14, [r2, #7*4] @ b[7] | |||
umull r11, r12, r7, r8 @ c' = a[0] * b[8] | |||
ldr r0, [r1, #1*4] @ a[1] | |||
umlal r3, r4, r7, r14 @ c += a[0] * b[7] | |||
ldr r8, [r2, #6*4] @ b[6] | |||
umlal r11, r12, r0, r14 @ c' += a[1] * b[7] | |||
ldr r7, [r1, #2*4] @ a[2] | |||
umlal r3, r4, r0, r8 @ c += a[1] * b[6] | |||
ldr r14, [r2, #5*4] @ b[5] | |||
umlal r11, r12, r7, r8 @ c' += a[2] * b[6] | |||
ldr r0, [r1, #3*4] @ a[3] | |||
umlal r3, r4, r7, r14 @ c += a[2] * b[5] | |||
ldr r8, [r2, #4*4] @ b[4] | |||
umlal r11, r12, r0, r14 @ c' += a[3] * b[5] | |||
ldr r7, [r1, #4*4] @ a[4] | |||
umlal r3, r4, r0, r8 @ c += a[3] * b[4] | |||
ldr r14, [r2, #3*4] @ b[3] | |||
umlal r11, r12, r7, r8 @ c' += a[4] * b[4] | |||
ldr r0, [r1, #5*4] @ a[5] | |||
umlal r3, r4, r7, r14 @ c += a[4] * b[3] | |||
ldr r8, [r2, #2*4] @ b[2] | |||
umlal r11, r12, r0, r14 @ c' += a[5] * b[3] | |||
ldr r7, [r1, #6*4] @ a[6] | |||
umlal r3, r4, r0, r8 @ c += a[5] * b[2] | |||
ldr r14, [r2, #1*4] @ b[1] | |||
umlal r11, r12, r7, r8 @ c' += a[6] * b[2] | |||
ldr r0, [r1, #7*4] @ a[7] | |||
umlal r3, r4, r7, r14 @ c += a[6] * b[1] | |||
ldr r8, [r2, #0*4] @ b[0] | |||
umlal r11, r12, r0, r14 @ c' += a[7] * b[1] | |||
ldr r7, [r1, #8*4] @ a[8] | |||
umlal r3, r4, r0, r8 @ c += a[7] * b[0] | |||
ldr r14, [r2, #9*4] @ b[9] | |||
umlal r11, r12, r7, r8 @ c' += a[8] * b[0] | |||
ldr r0, [r1, #9*4] @ a[9] | |||
umlal r5, r6, r7, r14 @ d += a[8] * b[9] | |||
ldr r8, [r2, #8*4] @ b[8] | |||
umull r9, r10, r0, r14 @ d' = a[9] * b[9] | |||
umlal r5, r6, r0, r8 @ d += a[9] * b[8] | |||
bic r0, r5, field_not_M @ u7 = d & M | |||
mov r5, r5, lsr #26 @ d >>= 26 | |||
orr r5, r5, r6, asl #6 | |||
mov r6, r6, lsr #26 | |||
movw r14, field_R0 @ c += u7 * R0 | |||
umlal r3, r4, r0, r14 | |||
bic r14, r3, field_not_M @ t7 = c & M | |||
str r14, [sp, #4 + 7*4] | |||
mov r3, r3, lsr #26 @ c >>= 26 | |||
orr r3, r3, r4, asl #6 | |||
mov r4, r4, lsr #26 | |||
mov r14, field_R1 @ c += u7 * R1 | |||
umlal r3, r4, r0, r14 | |||
/* J */ | |||
adds r3, r3, r11 @ c += c' | |||
adc r4, r4, r12 | |||
adds r5, r5, r9 @ d += d' | |||
adc r6, r6, r10 | |||
bic r0, r5, field_not_M @ u8 = d & M | |||
str r0, [sp, #4 + 8*4] | |||
mov r5, r5, lsr #26 @ d >>= 26 | |||
orr r5, r5, r6, asl #6 | |||
mov r6, r6, lsr #26 | |||
movw r14, field_R0 @ c += u8 * R0 | |||
umlal r3, r4, r0, r14 | |||
/****************************************** | |||
* compute and write back result | |||
****************************************** | |||
Allocation: | |||
r0 r | |||
r3:r4 c | |||
r5:r6 d | |||
r7 t0 | |||
r8 t1 | |||
r9 t2 | |||
r11 u8 | |||
r12 t9 | |||
r1,r2,r10,r14 scratch | |||
Note: do not read from a[] after here, it may overlap with r[] | |||
*/ | |||
ldr r0, [sp, #0] | |||
add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 | |||
ldmia r1, {r2,r7,r8,r9,r10,r11,r12} | |||
add r1, r0, #3*4 | |||
stmia r1, {r2,r7,r8,r9,r10} | |||
bic r2, r3, field_not_M @ r[8] = c & M | |||
str r2, [r0, #8*4] | |||
mov r3, r3, lsr #26 @ c >>= 26 | |||
orr r3, r3, r4, asl #6 | |||
mov r4, r4, lsr #26 | |||
mov r14, field_R1 @ c += u8 * R1 | |||
umlal r3, r4, r11, r14 | |||
movw r14, field_R0 @ c += d * R0 | |||
umlal r3, r4, r5, r14 | |||
adds r3, r3, r12 @ c += t9 | |||
adc r4, r4, #0 | |||
add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 | |||
ldmia r1, {r7,r8,r9} | |||
ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) | |||
str r2, [r0, #9*4] | |||
mov r3, r3, lsr #22 @ c >>= 22 | |||
orr r3, r3, r4, asl #10 | |||
mov r4, r4, lsr #22 | |||
movw r14, field_R1 << 4 @ c += d * (R1 << 4) | |||
umlal r3, r4, r5, r14 | |||
movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) | |||
umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) | |||
adds r5, r5, r7 @ d.lo += t0 | |||
mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) | |||
adc r6, r6, 0 @ d.hi += carry | |||
bic r2, r5, field_not_M @ r[0] = d & M | |||
str r2, [r0, #0*4] | |||
mov r5, r5, lsr #26 @ d >>= 26 | |||
orr r5, r5, r6, asl #6 | |||
mov r6, r6, lsr #26 | |||
movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) | |||
umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) | |||
adds r5, r5, r8 @ d.lo += t1 | |||
adc r6, r6, #0 @ d.hi += carry | |||
adds r5, r5, r1 @ d.lo += tmp.lo | |||
mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) | |||
adc r6, r6, r2 @ d.hi += carry + tmp.hi | |||
bic r2, r5, field_not_M @ r[1] = d & M | |||
str r2, [r0, #1*4] | |||
mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) | |||
orr r5, r5, r6, asl #6 | |||
add r5, r5, r9 @ d += t2 | |||
str r5, [r0, #2*4] @ r[2] = d | |||
add sp, sp, #48 | |||
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} | |||
.size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner | |||
.align 2 | |||
.global secp256k1_fe_sqr_inner | |||
.type secp256k1_fe_sqr_inner, %function | |||
@ Arguments: | |||
@ r0 r Can overlap with a | |||
@ r1 a | |||
@ Stack (total 4+10*4 = 44) | |||
@ sp + #0 saved 'r' pointer | |||
@ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 | |||
secp256k1_fe_sqr_inner: | |||
stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} | |||
sub sp, sp, #48 @ frame=44 + alignment | |||
str r0, [sp, #0] @ save result address, we need it only at the end | |||
/****************************************** | |||
* Main computation code. | |||
****************************************** | |||
Allocation: | |||
r0,r14,r2,r7,r8 scratch | |||
r1 a (pointer) | |||
r3:r4 c | |||
r5:r6 d | |||
r11:r12 c' | |||
r9:r10 d' | |||
Note: do not write to r[] here, it may overlap with a[] | |||
*/ | |||
/* A interleaved with B */ | |||
ldr r0, [r1, #1*4] @ a[1]*2 | |||
ldr r7, [r1, #0*4] @ a[0] | |||
mov r0, r0, asl #1 | |||
ldr r14, [r1, #9*4] @ a[9] | |||
umull r3, r4, r7, r7 @ c = a[0] * a[0] | |||
ldr r8, [r1, #8*4] @ a[8] | |||
mov r7, r7, asl #1 | |||
umull r5, r6, r7, r14 @ d = a[0]*2 * a[9] | |||
ldr r7, [r1, #2*4] @ a[2]*2 | |||
umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9] | |||
ldr r14, [r1, #7*4] @ a[7] | |||
umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8] | |||
mov r7, r7, asl #1 | |||
ldr r0, [r1, #3*4] @ a[3]*2 | |||
umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8] | |||
ldr r8, [r1, #6*4] @ a[6] | |||
umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7] | |||
mov r0, r0, asl #1 | |||
ldr r7, [r1, #4*4] @ a[4]*2 | |||
umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7] | |||