Squashed 'src/secp256k1/' changes from 6c527ec..7a49cac
7a49cac Merge #410: Add string.h include to ecmult_impl 0bbd5d4 Add string.h include to ecmult_impl c5b32e1 Merge #405: Make secp256k1_fe_sqrt constant time 926836a Make secp256k1_fe_sqrt constant time e2a8e92 Merge #404: Replace 3M + 4S doubling formula with 2M + 5S one 8ec49d8 Add note about 2M + 5S doubling formula 5a91bd7 Merge #400: A couple minor cleanups ac01378 build: add -DSECP256K1_BUILD to benchmark_internal build flags a6c6f99 Remove a bunch of unused stdlib #includes 65285a6 Merge #403: configure: add flag to disable OpenSSL tests a9b2a5d configure: add flag to disable OpenSSL tests b340123 Merge #402: Add support for testing quadratic residues e6e9805 Add function for testing quadratic residue field/group elements. efd953a Add Jacobi symbol test via GMP fa36a0d Merge #401: ecmult_const: unify endomorphism and non-endomorphism skew cases c6191fd ecmult_const: unify endomorphism and non-endomorphism skew cases 0b3e618 Merge #378: .gitignore build-aux cleanup 6042217 Merge #384: JNI: align shared files copyright/comments to bitcoinj's 24ad20f Merge #399: build: verify that the native compiler works for static precomp b3be852 Merge #398: Test whether ECDH and Schnorr are enabled for JNI aa0b1fd build: verify that the native compiler works for static precomp eee808d Test whether ECDH and Schnorr are enabled for JNI 7b0fb18 Merge #366: ARM assembly implementation of field_10x26 inner (rebase of #173) 001f176 ARM assembly implementation of field_10x26 inner 0172be9 Merge #397: Small fixes for sha256 3f8b78e Fix undefs in hash_impl.h 2ab4695 Fix state size in sha256 struct 6875b01 Merge #386: Add some missing `VERIFY_CHECK(ctx != NULL)` 2c52b5d Merge #389: Cast pointers through uintptr_t under JNI 43097a4 Merge #390: Update bitcoin-core GitHub links 31c9c12 Merge #391: JNI: Only call ecdsa_verify if its inputs parsed correctly 1cb2302 Merge #392: Add testcase which hits additional branch in secp256k1_scalar_sqr d2ee340 Merge #388: bench_ecdh: fix call to secp256k1_context_create 093a497 Add testcase which hits additional branch in secp256k1_scalar_sqr a40c701 JNI: Only call ecdsa_verify if its inputs parsed correctly faa2a11 Update bitcoin-core GitHub links 47b9e78 Cast pointers through uintptr_t under JNI f36f9c6 bench_ecdh: fix call to secp256k1_context_create bcc4881 Add some missing `VERIFY_CHECK(ctx != NULL)` for functions that use `ARG_CHECK` 6ceea2c align shared files copyright/comments to bitcoinj's 70141a8 Update .gitignore 7b549b1 Merge #373: build: fix x86_64 asm detection for some compilers bc7c93c Merge #374: Add note about y=0 being possible on one of the sextic twists e457018 Merge #364: JNI rebased 86e2d07 JNI library: cleanup, removed unimplemented code 3093576a JNI library bd2895f Merge pull request #371 e72e93a Add note about y=0 being possible on one of the sextic twists 3f8fdfb build: fix x86_64 asm detection for some compilers e5a9047 [Trivial] Remove double semicolons c18b869 Merge pull request #360 3026daa Merge pull request #302 03d4611 Add sage verification script for the group laws a965937 Merge pull request #361 83221ec Add experimental features to configure 5d4c5a3 Prevent damage_array in the signature test from going out of bounds. 419bf7f Merge pull request #356 03d84a4 Benchmark against OpenSSL verification git-subtree-dir: src/secp256k1 git-subtree-split: 7a49cacd3937311fcb1cb36b6ba3336fca811991
This commit is contained in:
parent
5ad5463093
commit
b2135359b3
42 changed files with 3906 additions and 196 deletions
19
.gitignore
vendored
19
.gitignore
vendored
|
@ -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
|
||||
|
|
19
.travis.yml
19
.travis.yml
|
@ -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
|
||||
|
|
74
Makefile.am
74
Makefile.am
|
@ -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
|
||||
|
||||
libsecp256k1_la_SOURCES = src/secp256k1.c
|
||||
libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
|
||||
libsecp256k1_la_LIBADD = $(SECP_LIBS)
|
||||
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 = -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
|
||||
============
|
||||
|
||||
[![Build Status](https://travis-ci.org/bitcoin/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin/secp256k1)
|
||||
[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1)
|
||||
|
||||
Optimized C library for EC operations on curve secp256k1.
|
||||
|
||||
|
|
140
build-aux/m4/ax_jni_include_dir.m4
Normal file
140
build-aux/m4/ax_jni_include_dir.m4
Normal file
|
@ -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])
|
||||
])
|
||||
|
|
144
configure.ac
144
configure.ac
|
@ -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"
|
||||
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
|
||||
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@
|
||||
|
|
322
sage/group_prover.sage
Normal file
322
sage/group_prover.sage
Normal file
|
@ -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)
|
306
sage/secp256k1.sage
Normal file
306
sage/secp256k1.sage
Normal file
|
@ -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)
|
264
sage/weierstrass_prover.sage
Normal file
264
sage/weierstrass_prover.sage
Normal file
|
@ -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)
|
||||
print
|
||||
|
||||
|
||||
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])
|
||||
|
||||
print
|
919
src/asm/field_10x26_arm.s
Normal file
919
src/asm/field_10x26_arm.s
Normal file
|
@ -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]
|
||||
ldr r14, [r1, #5*4] @ a[5]
|
||||
mov r7, r7, asl #1
|
||||
umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6]
|
||||
umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6]
|
||||
umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5]
|
||||
umlal r9, r10, r14, r14 @ d' += a[5] * a[5]
|
||||
|
||||
bic r0, r5, field_not_M @ t9 = d & M
|
||||
str r0, [sp, #4 + 9*4]
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
|
||||
/* B */
|
||||
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 r0, [r1, #0*4] @ a[0]*2
|
||||
ldr r14, [r1, #1*4] @ a[1]
|
||||
mov r0, r0, asl #1
|
||||
ldr r8, [r1, #2*4] @ a[2]
|
||||
umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1]
|
||||
mov r7, r8, asl #1 @ a[2]*2
|
||||
umull r11, r12, r14, r14 @ c' = a[1] * a[1]
|
||||
ldr r14, [r1, #9*4] @ a[9]
|
||||
umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2]
|
||||
ldr r0, [r1, #3*4] @ a[3]*2
|
||||
ldr r8, [r1, #8*4] @ a[8]
|
||||
umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9]
|
||||
mov r0, r0, asl #1
|
||||
ldr r7, [r1, #4*4] @ a[4]*2
|
||||
umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9]
|
||||
ldr r14, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8]
|
||||
mov r7, r7, asl #1
|
||||
ldr r0, [r1, #5*4] @ a[5]*2
|
||||
umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8]
|
||||
ldr r8, [r1, #6*4] @ a[6]
|
||||
mov r0, r0, asl #1
|
||||
umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7]
|
||||
umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7]
|
||||
umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6]
|
||||
umlal r9, r10, r8, r8 @ d' += a[6] * a[6]
|
||||
|
||||
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]*2
|
||||
ldr r0, [r1, #1*4] @ a[1]*2
|
||||
ldr r14, [r1, #2*4] @ a[2]
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #3*4] @ a[3]
|
||||
ldr r2, [r1, #4*4]
|
||||
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3]
|
||||
mov r0, r0, asl #1
|
||||
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4]
|
||||
mov r2, r2, asl #1 @ a[4]*2
|
||||
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3]
|
||||
ldr r8, [r1, #9*4] @ a[9]
|
||||
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2]
|
||||
ldr r0, [r1, #5*4] @ a[5]*2
|
||||
umlal r11, r12, r14, r14 @ c' += a[2] * a[2]
|
||||
ldr r14, [r1, #8*4] @ a[8]
|
||||
mov r0, r0, asl #1
|
||||
umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9]
|
||||
ldr r7, [r1, #6*4] @ a[6]*2
|
||||
umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9]
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8]
|
||||
umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8]
|
||||
umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7]
|
||||
umlal r9, r10, r8, r8 @ d' += a[7] * a[7]
|
||||
|
||||
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]*2
|
||||
ldr r0, [r1, #1*4] @ a[1]*2
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #5*4] @ a[5]
|
||||
ldr r2, [r1, #6*4] @ a[6]
|
||||
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5]
|
||||
ldr r14, [r1, #4*4] @ a[4]
|
||||
mov r0, r0, asl #1
|
||||
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6]
|
||||
ldr r7, [r1, #2*4] @ a[2]*2
|
||||
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5]
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #3*4] @ a[3]
|
||||
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4]
|
||||
mov r0, r2, asl #1 @ a[6]*2
|
||||
umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4]
|
||||
ldr r14, [r1, #9*4] @ a[9]
|
||||
umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3]
|
||||
ldr r7, [r1, #7*4] @ a[7]*2
|
||||
umlal r11, r12, r8, r8 @ c' += a[3] * a[3]
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #8*4] @ a[8]
|
||||
umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9]
|
||||
umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9]
|
||||
umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8]
|
||||
umlal r9, r10, r8, r8 @ d' += a[8] * a[8]
|
||||
|
||||
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 r7, [r1, #0*4] @ a[0]*2
|
||||
ldr r0, [r1, #1*4] @ a[1]*2
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #7*4] @ a[7]
|
||||
ldr r2, [r1, #8*4] @ a[8]
|
||||
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7]
|
||||
ldr r14, [r1, #6*4] @ a[6]
|
||||
mov r0, r0, asl #1
|
||||
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8]
|
||||
ldr r7, [r1, #2*4] @ a[2]*2
|
||||
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7]
|
||||
ldr r8, [r1, #5*4] @ a[5]
|
||||
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6]
|
||||
ldr r0, [r1, #3*4] @ a[3]*2
|
||||
mov r7, r7, asl #1
|
||||
umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6]
|
||||
ldr r14, [r1, #4*4] @ a[4]
|
||||
mov r0, r0, asl #1
|
||||
umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5]
|
||||
mov r2, r2, asl #1 @ a[8]*2
|
||||
umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5]
|
||||
umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4]
|
||||
umlal r11, r12, r14, r14 @ c' += a[4] * a[4]
|
||||
ldr r8, [r1, #9*4] @ a[9]
|
||||
umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9]
|
||||
@ r8 will be used in J
|
||||
|
||||
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
|
||||
umlal r5, r6, r8, r8 @ d += a[9] * a[9]
|
||||
|
||||
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_sqr_inner, .-secp256k1_fe_sqr_inner
|
||||
|
|
@ -28,7 +28,8 @@ static void bench_ecdh_setup(void* arg) {
|
|||
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
|
||||
};
|
||||
|
||||
data->ctx = secp256k1_context_create(0);
|
||||
/* create a context with no capabilities */
|
||||
data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
|
||||
for (i = 0; i < 32; i++) {
|
||||
data->scalar[i] = i + 1;
|
||||
}
|
||||
|
|
|
@ -181,12 +181,12 @@ void bench_field_inverse_var(void* arg) {
|
|||
}
|
||||
}
|
||||
|
||||
void bench_field_sqrt_var(void* arg) {
|
||||
void bench_field_sqrt(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_fe_sqrt_var(&data->fe_x, &data->fe_x);
|
||||
secp256k1_fe_sqrt(&data->fe_x, &data->fe_x);
|
||||
secp256k1_fe_add(&data->fe_x, &data->fe_y);
|
||||
}
|
||||
}
|
||||
|
@ -227,6 +227,15 @@ void bench_group_add_affine_var(void* arg) {
|
|||
}
|
||||
}
|
||||
|
||||
void bench_group_jacobi_var(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_gej_has_quad_y_var(&data->gej_x);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_ecmult_wnaf(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
|
@ -299,6 +308,21 @@ void bench_context_sign(void* arg) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef USE_NUM_NONE
|
||||
void bench_num_jacobi(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
secp256k1_num nx, norder;
|
||||
|
||||
secp256k1_scalar_get_num(&nx, &data->scalar_x);
|
||||
secp256k1_scalar_order_get_num(&norder);
|
||||
secp256k1_scalar_get_num(&norder, &data->scalar_y);
|
||||
|
||||
for (i = 0; i < 200000; i++) {
|
||||
secp256k1_num_jacobi(&nx, &norder);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int have_flag(int argc, char** argv, char *flag) {
|
||||
char** argm = argv + argc;
|
||||
|
@ -333,12 +357,13 @@ int main(int argc, char **argv) {
|
|||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt_var", bench_field_sqrt_var, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000);
|
||||
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000);
|
||||
|
||||
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000);
|
||||
|
@ -350,5 +375,8 @@ int main(int argc, char **argv) {
|
|||
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20);
|
||||
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200);
|
||||
|
||||
#ifndef USE_NUM_NONE
|
||||
if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,12 @@
|
|||
#include "util.h"
|
||||
#include "bench.h"
|
||||
|
||||
#ifdef ENABLE_OPENSSL_TESTS
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context *ctx;
|
||||
unsigned char msg[32];
|
||||
|
@ -19,6 +25,9 @@ typedef struct {
|
|||
size_t siglen;
|
||||
unsigned char pubkey[33];
|
||||
size_t pubkeylen;
|
||||
#ifdef ENABLE_OPENSSL_TESTS
|
||||
EC_GROUP* ec_group;
|
||||
#endif
|
||||
} benchmark_verify_t;
|
||||
|
||||
static void benchmark_verify(void* arg) {
|
||||
|
@ -40,6 +49,36 @@ static void benchmark_verify(void* arg) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OPENSSL_TESTS
|
||||
static void benchmark_verify_openssl(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);
|
||||
{
|
||||
EC_KEY *pkey = EC_KEY_new();
|
||||
const unsigned char *pubkey = &data->pubkey[0];
|
||||
int result;
|
||||
|
||||
CHECK(pkey != NULL);
|
||||
result = EC_KEY_set_group(pkey, data->ec_group);
|
||||
CHECK(result);
|
||||
result = (o2i_ECPublicKey(&pkey, &pubkey, data->pubkeylen)) != NULL;
|
||||
CHECK(result);
|
||||
result = ECDSA_verify(0, &data->msg[0], sizeof(data->msg), &data->sig[0], data->siglen, pkey) == (i == 0);
|
||||
CHECK(result);
|
||||
EC_KEY_free(pkey);
|
||||
}
|
||||
data->sig[data->siglen - 1] ^= (i & 0xFF);
|
||||
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
|
||||
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
int i;
|
||||
secp256k1_pubkey pubkey;
|
||||
|
@ -62,6 +101,11 @@ int main(void) {
|
|||
CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
|
||||
|
||||
run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000);
|
||||
#ifdef ENABLE_OPENSSL_TESTS
|
||||
data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1);
|
||||
run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000);
|
||||
EC_GROUP_free(data.ec_group);
|
||||
#endif
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
|
|
|
@ -58,22 +58,24 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
|
|||
int global_sign;
|
||||
int skew = 0;
|
||||
int word = 0;
|
||||
|
||||
/* 1 2 3 */
|
||||
int u_last;
|
||||
int u;
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
int flip;
|
||||
int bit;
|
||||
secp256k1_scalar neg_s;
|
||||
int not_neg_one;
|
||||
/* If we are using the endomorphism, we cannot handle even numbers by negating
|
||||
* them, since we are working with 128-bit numbers whose negations would be 256
|
||||
* bits, eliminating the performance advantage. Instead we use a technique from
|
||||
/* Note that we cannot handle even numbers by negating them to be odd, as is
|
||||
* done in other implementations, since if our scalars were specified to have
|
||||
* width < 256 for performance reasons, their negations would have width 256
|
||||
* and we'd lose any performance benefit. Instead, we use a technique from
|
||||
* Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even)
|
||||
* or 2 (for odd) to the number we are encoding, then compensating after the
|
||||
* multiplication. */
|
||||
/* Negative 128-bit numbers will be negated, since otherwise they are 256-bit */
|
||||
* or 2 (for odd) to the number we are encoding, returning a skew value indicating
|
||||
* this, and having the caller compensate after doing the multiplication. */
|
||||
|
||||
/* Negative numbers will be negated to keep their bit representation below the maximum width */
|
||||
flip = secp256k1_scalar_is_high(&s);
|
||||
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
|
||||
bit = flip ^ (s.d[0] & 1);
|
||||
|
@ -89,11 +91,6 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
|
|||
global_sign = secp256k1_scalar_cond_negate(&s, flip);
|
||||
global_sign *= not_neg_one * 2 - 1;
|
||||
skew = 1 << bit;
|
||||
#else
|
||||
/* Otherwise, we just negate to force oddness */
|
||||
int is_even = secp256k1_scalar_is_even(&s);
|
||||
global_sign = secp256k1_scalar_cond_negate(&s, is_even);
|
||||
#endif
|
||||
|
||||
/* 4 */
|
||||
u_last = secp256k1_scalar_shr_int(&s, w);
|
||||
|
@ -127,15 +124,13 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
|
|||
secp256k1_ge tmpa;
|
||||
secp256k1_fe Z;
|
||||
|
||||
int skew_1;
|
||||
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
int skew_1;
|
||||
int skew_lam;
|
||||
secp256k1_scalar q_1, q_lam;
|
||||
#else
|
||||
int wnaf[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
#endif
|
||||
|
||||
int i;
|
||||
|
@ -145,18 +140,10 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
|
|||
#ifdef USE_ENDOMORPHISM
|
||||
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
|
||||
secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
|
||||
/* no need for zero correction when using endomorphism since even
|
||||
* numbers have one added to them anyway */
|
||||
skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1);
|
||||
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1);
|
||||
#else
|
||||
int is_zero = secp256k1_scalar_is_zero(scalar);
|
||||
/* the wNAF ladder cannot handle zero, so bump this to one .. we will
|
||||
* correct the result after the fact */
|
||||
sc.d[0] += is_zero;
|
||||
VERIFY_CHECK(!secp256k1_scalar_is_zero(&sc));
|
||||
|
||||
secp256k1_wnaf_const(wnaf, sc, WINDOW_A - 1);
|
||||
skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1);
|
||||
#endif
|
||||
|
||||
/* Calculate odd multiples of a.
|
||||
|
@ -179,21 +166,15 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
|
|||
/* first loop iteration (separated out so we can directly set r, rather
|
||||
* than having it start at infinity, get doubled several times, then have
|
||||
* its new value added to it) */
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)];
|
||||
VERIFY_CHECK(i != 0);
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
|
||||
secp256k1_gej_set_ge(r, &tmpa);
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)];
|
||||
VERIFY_CHECK(i != 0);
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
#else
|
||||
i = wnaf[WNAF_SIZE(WINDOW_A - 1)];
|
||||
VERIFY_CHECK(i != 0);
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
|
||||
secp256k1_gej_set_ge(r, &tmpa);
|
||||
#endif
|
||||
/* remaining loop iterations */
|
||||
for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) {
|
||||
|
@ -202,59 +183,57 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
|
|||
for (j = 0; j < WINDOW_A - 1; ++j) {
|
||||
secp256k1_gej_double_nonzero(r, r, NULL);
|
||||
}
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
|
||||
n = wnaf_1[i];
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
|
||||
VERIFY_CHECK(n != 0);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
n = wnaf_lam[i];
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
|
||||
VERIFY_CHECK(n != 0);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
#else
|
||||
n = wnaf[i];
|
||||
VERIFY_CHECK(n != 0);
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
#endif
|
||||
}
|
||||
|
||||
secp256k1_fe_mul(&r->z, &r->z, &Z);
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
{
|
||||
/* Correct for wNAF skew */
|
||||
secp256k1_ge correction = *a;
|
||||
secp256k1_ge_storage correction_1_stor;
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
secp256k1_ge_storage correction_lam_stor;
|
||||
#endif
|
||||
secp256k1_ge_storage a2_stor;
|
||||
secp256k1_gej tmpj;
|
||||
secp256k1_gej_set_ge(&tmpj, &correction);
|
||||
secp256k1_gej_double_var(&tmpj, &tmpj, NULL);
|
||||
secp256k1_ge_set_gej(&correction, &tmpj);
|
||||
secp256k1_ge_to_storage(&correction_1_stor, a);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
secp256k1_ge_to_storage(&correction_lam_stor, a);
|
||||
#endif
|
||||
secp256k1_ge_to_storage(&a2_stor, &correction);
|
||||
|
||||
/* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
|
||||
secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
|
||||
#endif
|
||||
|
||||
/* Apply the correction */
|
||||
secp256k1_ge_from_storage(&correction, &correction_1_stor);
|
||||
secp256k1_ge_neg(&correction, &correction);
|
||||
secp256k1_gej_add_ge(r, r, &correction);
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
secp256k1_ge_from_storage(&correction, &correction_lam_stor);
|
||||
secp256k1_ge_neg(&correction, &correction);
|
||||
secp256k1_ge_mul_lambda(&correction, &correction);
|
||||
secp256k1_gej_add_ge(r, r, &correction);
|
||||
}
|
||||
#else
|
||||
/* correct for zero */
|
||||
r->infinity |= is_zero;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "scalar.h"
|
||||
#include "ecmult.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* optimal for 128-bit and 256-bit exponents. */
|
||||
#define WINDOW_A 5
|
||||
|
||||
|
|
|
@ -57,6 +57,9 @@ static int secp256k1_fe_is_zero(const secp256k1_fe *a);
|
|||
static int secp256k1_fe_is_odd(const secp256k1_fe *a);
|
||||
|
||||
/** Compare two field elements. Requires magnitude-1 inputs. */
|
||||
static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
|
||||
/** Same as secp256k1_fe_equal, but may be variable time. */
|
||||
static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
|
||||
/** Compare two field elements. Requires both inputs to be normalized */
|
||||
|
@ -92,7 +95,10 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
|
|||
* The input's magnitude can be at most 8. The output magnitude is 1 (but not
|
||||
* guaranteed to be normalized). The result in r will always be a square
|
||||
* itself. */
|
||||
static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
|
||||
/** Checks whether a field element is a quadratic residue. */
|
||||
static int secp256k1_fe_is_quad_var(const secp256k1_fe *a);
|
||||
|
||||
/** 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). */
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
#define _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "util.h"
|
||||
#include "num.h"
|
||||
#include "field.h"
|
||||
|
@ -429,6 +427,14 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(USE_EXTERNAL_ASM)
|
||||
|
||||
/* External assembler implementation */
|
||||
void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b);
|
||||
void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a);
|
||||
|
||||
#else
|
||||
|
||||
#ifdef VERIFY
|
||||
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
|
||||
#else
|
||||
|
@ -1037,7 +1043,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
|
|||
VERIFY_BITS(r[2], 27);
|
||||
/* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
|
||||
#ifdef VERIFY
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "libsecp256k1-config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include "util.h"
|
||||
#include "num.h"
|
||||
#include "field.h"
|
||||
|
|
|
@ -137,7 +137,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
|
|||
VERIFY_BITS(r[2], 52);
|
||||
VERIFY_BITS(c, 63);
|
||||
/* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
c += d * R + t3;;
|
||||
c += d * R + t3;
|
||||
VERIFY_BITS(c, 100);
|
||||
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
r[3] = c & M; c >>= 52;
|
||||
|
@ -259,7 +259,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
|
|||
VERIFY_BITS(c, 63);
|
||||
/* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
|
||||
c += d * R + t3;;
|
||||
c += d * R + t3;
|
||||
VERIFY_BITS(c, 100);
|
||||
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
r[3] = c & M; c >>= 52;
|
||||
|
|
|
@ -21,6 +21,13 @@
|
|||
#error "Please select field implementation"
|
||||
#endif
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
secp256k1_fe na;
|
||||
secp256k1_fe_negate(&na, a, 1);
|
||||
secp256k1_fe_add(&na, b);
|
||||
return secp256k1_fe_normalizes_to_zero(&na);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
secp256k1_fe na;
|
||||
secp256k1_fe_negate(&na, a, 1);
|
||||
|
@ -28,7 +35,7 @@ SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const
|
|||
return secp256k1_fe_normalizes_to_zero_var(&na);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
/** Given that p is congruent to 3 mod 4, we can compute the square root of
|
||||
* a mod p as the (p+1)/4'th power of a.
|
||||
*
|
||||
|
@ -123,7 +130,7 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) {
|
|||
/* Check that a square root was actually calculated */
|
||||
|
||||
secp256k1_fe_sqr(&t1, r);
|
||||
return secp256k1_fe_equal_var(&t1, a);
|
||||
return secp256k1_fe_equal(&t1, a);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
|
@ -280,4 +287,29 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k
|
|||
r[0] = u;
|
||||
}
|
||||
|
||||
static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
|
||||
#ifndef USE_NUM_NONE
|
||||
unsigned char b[32];
|
||||
secp256k1_num n;
|
||||
secp256k1_num m;
|
||||
/* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
|
||||
static const unsigned char prime[32] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
|
||||
};
|
||||
|
||||
secp256k1_fe c = *a;
|
||||
secp256k1_fe_normalize_var(&c);
|
||||
secp256k1_fe_get_b32(b, &c);
|
||||
secp256k1_num_set_bin(&n, b, 32);
|
||||
secp256k1_num_set_bin(&m, prime, 32);
|
||||
return secp256k1_num_jacobi(&n, &m) >= 0;
|
||||
#else
|
||||
secp256k1_fe r;
|
||||
return secp256k1_fe_sqrt(&r, a);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -47,7 +47,7 @@ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const se
|
|||
* and a Y coordinate that is a quadratic residue modulo p. The return value
|
||||
* is true iff a coordinate with the given X coordinate exists.
|
||||
*/
|
||||
static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x);
|
||||
static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x);
|
||||
|
||||
/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness
|
||||
* for Y. Return value indicates whether the result is valid. */
|
||||
|
@ -94,6 +94,9 @@ static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a);
|
|||
/** Check whether a group element is the point at infinity. */
|
||||
static int secp256k1_gej_is_infinity(const secp256k1_gej *a);
|
||||
|
||||
/** Check whether a group element's y coordinate is a quadratic residue. */
|
||||
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a);
|
||||
|
||||
/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0).
|
||||
* a may not be zero. Constant time. */
|
||||
static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
#ifndef _SECP256K1_GROUP_IMPL_H_
|
||||
#define _SECP256K1_GROUP_IMPL_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "num.h"
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
|
@ -165,7 +163,7 @@ static void secp256k1_ge_clear(secp256k1_ge *r) {
|
|||
secp256k1_fe_clear(&r->y);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x) {
|
||||
static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) {
|
||||
secp256k1_fe x2, x3, c;
|
||||
r->x = *x;
|
||||
secp256k1_fe_sqr(&x2, x);
|
||||
|
@ -173,11 +171,11 @@ static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x) {
|
|||
r->infinity = 0;
|
||||
secp256k1_fe_set_int(&c, 7);
|
||||
secp256k1_fe_add(&c, &x3);
|
||||
return secp256k1_fe_sqrt_var(&r->y, &c);
|
||||
return secp256k1_fe_sqrt(&r->y, &c);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
|
||||
if (!secp256k1_ge_set_xquad_var(r, x)) {
|
||||
if (!secp256k1_ge_set_xquad(r, x)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_normalize_var(&r->y);
|
||||
|
@ -251,11 +249,23 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
|
|||
}
|
||||
|
||||
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
|
||||
/* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate */
|
||||
/* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.
|
||||
*
|
||||
* Note that there is an implementation described at
|
||||
* https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
|
||||
* which trades a multiply for a square, but in practice this is actually slower,
|
||||
* mainly because it requires more normalizations.
|
||||
*/
|
||||
secp256k1_fe t1,t2,t3,t4;
|
||||
/** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
|
||||
* Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
|
||||
* y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
|
||||
*
|
||||
* Having said this, if this function receives a point on a sextic twist, e.g. by
|
||||
* a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,
|
||||
* since -6 does have a cube root mod p. For this point, this function will not set
|
||||
* the infinity flag even though the point doubles to infinity, and the result
|
||||
* point will be gibberish (z = 0 but infinity = 0).
|
||||
*/
|
||||
r->infinity = a->infinity;
|
||||
if (r->infinity) {
|
||||
|
@ -623,4 +633,18 @@ static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
|
||||
secp256k1_fe yz;
|
||||
|
||||
if (a->infinity) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We rely on the fact that the Jacobi symbol of 1 / a->z^3 is the same as
|
||||
* that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z
|
||||
is */
|
||||
secp256k1_fe_mul(&yz, &a->y, &a->z);
|
||||
return secp256k1_fe_is_quad_var(&yz);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t s[32];
|
||||
uint32_t s[8];
|
||||
uint32_t buf[16]; /* In big endian */
|
||||
size_t bytes;
|
||||
} secp256k1_sha256_t;
|
||||
|
|
|
@ -269,15 +269,13 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
|
|||
rng->retry = 0;
|
||||
}
|
||||
|
||||
|
||||
#undef BE32
|
||||
#undef Round
|
||||
#undef sigma0
|
||||
#undef sigma1
|
||||
#undef Sigma0
|
||||
#undef sigma0
|
||||
#undef Sigma1
|
||||
#undef Ch
|
||||
#undef Sigma0
|
||||
#undef Maj
|
||||
#undef ReadBE32
|
||||
#undef WriteBE32
|
||||
#undef Ch
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,60 +1,478 @@
|
|||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
* Copyright 2014-2016 the libsecp256k1 contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.bitcoin;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import static org.bitcoin.NativeSecp256k1Util.*;
|
||||
|
||||
/**
|
||||
* This class holds native methods to handle ECDSA verification.
|
||||
* You can find an example library that can be used for this at
|
||||
* https://github.com/sipa/secp256k1
|
||||
* <p>This class holds native methods to handle ECDSA verification.</p>
|
||||
*
|
||||
* <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
|
||||
*
|
||||
* <p>To build secp256k1 for use with bitcoinj, run
|
||||
* `./configure --enable-jni --enable-experimental --enable-module-schnorr --enable-module-ecdh`
|
||||
* and `make` then copy `.libs/libsecp256k1.so` to your system library path
|
||||
* or point the JVM to the folder containing it with -Djava.library.path
|
||||
* </p>
|
||||
*/
|
||||
public class NativeSecp256k1 {
|
||||
public static final boolean enabled;
|
||||
static {
|
||||
boolean isEnabled = true;
|
||||
try {
|
||||
System.loadLibrary("javasecp256k1");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
isEnabled = false;
|
||||
}
|
||||
enabled = isEnabled;
|
||||
}
|
||||
|
||||
|
||||
private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||
private static final Lock r = rwl.readLock();
|
||||
private static final Lock w = rwl.writeLock();
|
||||
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
|
||||
/**
|
||||
* Verifies the given secp256k1 signature in native code.
|
||||
* Calling when enabled == false is undefined (probably library not loaded)
|
||||
*
|
||||
*
|
||||
* @param data The data which was signed, must be exactly 32 bytes
|
||||
* @param signature The signature
|
||||
* @param pub The public key which did the signing
|
||||
*/
|
||||
public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
|
||||
public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{
|
||||
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null) {
|
||||
byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520);
|
||||
if (byteBuff == null || byteBuff.capacity() < 520) {
|
||||
byteBuff = ByteBuffer.allocateDirect(520);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(data);
|
||||
byteBuff.putInt(signature.length);
|
||||
byteBuff.putInt(pub.length);
|
||||
byteBuff.put(signature);
|
||||
byteBuff.put(pub);
|
||||
return secp256k1_ecdsa_verify(byteBuff) == 1;
|
||||
|
||||
byte[][] retByteArray;
|
||||
|
||||
r.lock();
|
||||
try {
|
||||
return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param byteBuff signature format is byte[32] data,
|
||||
* native-endian int signatureLength, native-endian int pubkeyLength,
|
||||
* byte[signatureLength] signature, byte[pubkeyLength] pub
|
||||
* @returns 1 for valid signature, anything else for invalid
|
||||
* libsecp256k1 Create an ECDSA signature.
|
||||
*
|
||||
* @param data Message hash, 32 bytes
|
||||
* @param key Secret key, 32 bytes
|
||||
*
|
||||
* Return values
|
||||
* @param sig byte array of signature
|
||||
*/
|
||||
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff);
|
||||
public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{
|
||||
Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < 32 + 32) {
|
||||
byteBuff = ByteBuffer.allocateDirect(32 + 32);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(data);
|
||||
byteBuff.put(sec);
|
||||
|
||||
byte[][] retByteArray;
|
||||
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] sigArr = retByteArray[0];
|
||||
int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||
|
||||
assertEquals(sigArr.length, sigLen, "Got bad signature length.");
|
||||
|
||||
return retVal == 0 ? new byte[0] : sigArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
|
||||
*
|
||||
* @param seckey ECDSA Secret key, 32 bytes
|
||||
*/
|
||||
public static boolean secKeyVerify(byte[] seckey) {
|
||||
Preconditions.checkArgument(seckey.length == 32);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < seckey.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(seckey.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(seckey);
|
||||
|
||||
r.lock();
|
||||
try {
|
||||
return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1;
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* libsecp256k1 Compute Pubkey - computes public key from secret key
|
||||
*
|
||||
* @param seckey ECDSA Secret key, 32 bytes
|
||||
*
|
||||
* Return values
|
||||
* @param pubkey ECDSA Public key, 33 or 65 bytes
|
||||
*/
|
||||
//TODO add a 'compressed' arg
|
||||
public static byte[] computePubkey(byte[] seckey) throws AssertFailException{
|
||||
Preconditions.checkArgument(seckey.length == 32);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < seckey.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(seckey.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(seckey);
|
||||
|
||||
byte[][] retByteArray;
|
||||
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] pubArr = retByteArray[0];
|
||||
int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||
|
||||
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
|
||||
|
||||
return retVal == 0 ? new byte[0]: pubArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 Cleanup - This destroys the secp256k1 context object
|
||||
* This should be called at the end of the program for proper cleanup of the context.
|
||||
*/
|
||||
public static synchronized void cleanup() {
|
||||
w.lock();
|
||||
try {
|
||||
secp256k1_destroy_context(Secp256k1Context.getContext());
|
||||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public static long cloneContext() {
|
||||
r.lock();
|
||||
try {
|
||||
return secp256k1_ctx_clone(Secp256k1Context.getContext());
|
||||
} finally { r.unlock(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
|
||||
*
|
||||
* @param tweak some bytes to tweak with
|
||||
* @param seckey 32-byte seckey
|
||||
*/
|
||||
public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{
|
||||
Preconditions.checkArgument(privkey.length == 32);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(privkey);
|
||||
byteBuff.put(tweak);
|
||||
|
||||
byte[][] retByteArray;
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] privArr = retByteArray[0];
|
||||
|
||||
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||
|
||||
assertEquals(privArr.length, privLen, "Got bad pubkey length.");
|
||||
|
||||
assertEquals(retVal, 1, "Failed return value check.");
|
||||
|
||||
return privArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
|
||||
*
|
||||
* @param tweak some bytes to tweak with
|
||||
* @param seckey 32-byte seckey
|
||||
*/
|
||||
public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{
|
||||
Preconditions.checkArgument(privkey.length == 32);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(privkey);
|
||||
byteBuff.put(tweak);
|
||||
|
||||
byte[][] retByteArray;
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] privArr = retByteArray[0];
|
||||
|
||||
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||
|
||||
assertEquals(privArr.length, privLen, "Got bad pubkey length.");
|
||||
|
||||
assertEquals(retVal, 1, "Failed return value check.");
|
||||
|
||||
return privArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
|
||||
*
|
||||
* @param tweak some bytes to tweak with
|
||||
* @param pubkey 32-byte seckey
|
||||
*/
|
||||
public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{
|
||||
Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(pubkey);
|
||||
byteBuff.put(tweak);
|
||||
|
||||
byte[][] retByteArray;
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] pubArr = retByteArray[0];
|
||||
|
||||
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||
|
||||
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
|
||||
|
||||
assertEquals(retVal, 1, "Failed return value check.");
|
||||
|
||||
return pubArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
|
||||
*
|
||||
* @param tweak some bytes to tweak with
|
||||
* @param pubkey 32-byte seckey
|
||||
*/
|
||||
public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{
|
||||
Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(pubkey);
|
||||
byteBuff.put(tweak);
|
||||
|
||||
byte[][] retByteArray;
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] pubArr = retByteArray[0];
|
||||
|
||||
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||
|
||||
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
|
||||
|
||||
assertEquals(retVal, 1, "Failed return value check.");
|
||||
|
||||
return pubArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 create ECDH secret - constant time ECDH calculation
|
||||
*
|
||||
* @param seckey byte array of secret key used in exponentiaion
|
||||
* @param pubkey byte array of public key used in exponentiaion
|
||||
*/
|
||||
public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{
|
||||
Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(seckey);
|
||||
byteBuff.put(pubkey);
|
||||
|
||||
byte[][] retByteArray;
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] resArr = retByteArray[0];
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||
|
||||
assertEquals(resArr.length, 32, "Got bad result length.");
|
||||
assertEquals(retVal, 1, "Failed return value check.");
|
||||
|
||||
return resArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 randomize - updates the context randomization
|
||||
*
|
||||
* @param seed 32-byte random seed
|
||||
*/
|
||||
public static synchronized boolean randomize(byte[] seed) throws AssertFailException{
|
||||
Preconditions.checkArgument(seed.length == 32 || seed == null);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < seed.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(seed.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(seed);
|
||||
|
||||
w.lock();
|
||||
try {
|
||||
return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1;
|
||||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] schnorrSign(byte[] data, byte[] sec) throws AssertFailException {
|
||||
Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null) {
|
||||
byteBuff = ByteBuffer.allocateDirect(32 + 32);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(data);
|
||||
byteBuff.put(sec);
|
||||
|
||||
byte[][] retByteArray;
|
||||
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_schnorr_sign(byteBuff, Secp256k1Context.getContext());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] sigArr = retByteArray[0];
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||
|
||||
assertEquals(sigArr.length, 64, "Got bad signature length.");
|
||||
|
||||
return retVal == 0 ? new byte[0] : sigArr;
|
||||
}
|
||||
|
||||
private static native long secp256k1_ctx_clone(long context);
|
||||
|
||||
private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
|
||||
|
||||
private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
|
||||
|
||||
private static native void secp256k1_destroy_context(long context);
|
||||
|
||||
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
|
||||
|
||||
private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
|
||||
|
||||
private static native byte[][] secp256k1_schnorr_sign(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
|
||||
|
||||
}
|
||||
|
|
247
src/java/org/bitcoin/NativeSecp256k1Test.java
Normal file
247
src/java/org/bitcoin/NativeSecp256k1Test.java
Normal file
|
@ -0,0 +1,247 @@
|
|||
package org.bitcoin;
|
||||
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import java.util.Arrays;
|
||||
import java.math.BigInteger;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import static org.bitcoin.NativeSecp256k1Util.*;
|
||||
|
||||
/**
|
||||
* This class holds test cases defined for testing this library.
|
||||
*/
|
||||
public class NativeSecp256k1Test {
|
||||
|
||||
//TODO improve comments/add more tests
|
||||
/**
|
||||
* This tests verify() for a valid signature
|
||||
*/
|
||||
public static void testVerifyPos() throws AssertFailException{
|
||||
boolean result = false;
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
|
||||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||
|
||||
result = NativeSecp256k1.verify( data, sig, pub);
|
||||
assertEquals( result, true , "testVerifyPos");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests verify() for a non-valid signature
|
||||
*/
|
||||
public static void testVerifyNeg() throws AssertFailException{
|
||||
boolean result = false;
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing"
|
||||
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
|
||||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||
|
||||
result = NativeSecp256k1.verify( data, sig, pub);
|
||||
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||
assertEquals( result, false , "testVerifyNeg");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests secret key verify() for a valid secretkey
|
||||
*/
|
||||
public static void testSecKeyVerifyPos() throws AssertFailException{
|
||||
boolean result = false;
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
|
||||
result = NativeSecp256k1.secKeyVerify( sec );
|
||||
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||
assertEquals( result, true , "testSecKeyVerifyPos");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests secret key verify() for a invalid secretkey
|
||||
*/
|
||||
public static void testSecKeyVerifyNeg() throws AssertFailException{
|
||||
boolean result = false;
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
|
||||
|
||||
result = NativeSecp256k1.secKeyVerify( sec );
|
||||
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||
assertEquals( result, false , "testSecKeyVerifyNeg");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests public key create() for a valid secretkey
|
||||
*/
|
||||
public static void testPubKeyCreatePos() throws AssertFailException{
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.computePubkey( sec);
|
||||
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests public key create() for a invalid secretkey
|
||||
*/
|
||||
public static void testPubKeyCreateNeg() throws AssertFailException{
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.computePubkey( sec);
|
||||
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( pubkeyString, "" , "testPubKeyCreateNeg");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests sign() for a valid secretkey
|
||||
*/
|
||||
public static void testSignPos() throws AssertFailException{
|
||||
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.sign(data, sec);
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests sign() for a invalid secretkey
|
||||
*/
|
||||
public static void testSignNeg() throws AssertFailException{
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.sign(data, sec);
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString, "" , "testSignNeg");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests private key tweak-add
|
||||
*/
|
||||
public static void testPrivKeyTweakAdd_1() throws AssertFailException {
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data );
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests private key tweak-mul
|
||||
*/
|
||||
public static void testPrivKeyTweakMul_1() throws AssertFailException {
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data );
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests private key tweak-add uncompressed
|
||||
*/
|
||||
public static void testPrivKeyTweakAdd_2() throws AssertFailException {
|
||||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data );
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests private key tweak-mul uncompressed
|
||||
*/
|
||||
public static void testPrivKeyTweakMul_2() throws AssertFailException {
|
||||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data );
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests seed randomization
|
||||
*/
|
||||
public static void testRandomize() throws AssertFailException {
|
||||
byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random"
|
||||
boolean result = NativeSecp256k1.randomize(seed);
|
||||
assertEquals( result, true, "testRandomize");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests signSchnorr() for a valid secretkey
|
||||
*/
|
||||
public static void testSchnorrSign() throws AssertFailException{
|
||||
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.schnorrSign(data, sec);
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString, "C5E929AA058B982048760422D3B563749B7D0E50C5EBD8CD2FFC23214BD6A2F1B072C13880997EBA847CF20F2F90FCE07C1CA33A890A4127095A351127F8D95F" , "testSchnorrSign");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests signSchnorr() for a valid secretkey
|
||||
*/
|
||||
public static void testCreateECDHSecret() throws AssertFailException{
|
||||
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub);
|
||||
String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws AssertFailException{
|
||||
|
||||
|
||||
System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n");
|
||||
|
||||
assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" );
|
||||
|
||||
//Test verify() success/fail
|
||||
testVerifyPos();
|
||||
testVerifyNeg();
|
||||
|
||||
//Test secKeyVerify() success/fail
|
||||
testSecKeyVerifyPos();
|
||||
testSecKeyVerifyNeg();
|
||||
|
||||
//Test computePubkey() success/fail
|
||||
testPubKeyCreatePos();
|
||||
testPubKeyCreateNeg();
|
||||
|
||||
//Test sign() success/fail
|
||||
testSignPos();
|
||||
testSignNeg();
|
||||
|
||||
//Test Schnorr (partial support) //TODO
|
||||
testSchnorrSign();
|
||||
//testSchnorrVerify
|
||||
//testSchnorrRecovery
|
||||
|
||||
//Test privKeyTweakAdd() 1
|
||||
testPrivKeyTweakAdd_1();
|
||||
|
||||
//Test privKeyTweakMul() 2
|
||||
testPrivKeyTweakMul_1();
|
||||
|
||||
//Test privKeyTweakAdd() 3
|
||||
testPrivKeyTweakAdd_2();
|
||||
|
||||
//Test privKeyTweakMul() 4
|
||||
testPrivKeyTweakMul_2();
|
||||
|
||||
//Test randomize()
|
||||
testRandomize();
|
||||
|
||||
//Test ECDH
|
||||
testCreateECDHSecret();
|
||||
|
||||
NativeSecp256k1.cleanup();
|
||||
|
||||
System.out.println(" All tests passed." );
|
||||
|
||||
}
|
||||
}
|
45
src/java/org/bitcoin/NativeSecp256k1Util.java
Normal file
45
src/java/org/bitcoin/NativeSecp256k1Util.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2014-2016 the libsecp256k1 contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.bitcoin;
|
||||
|
||||
public class NativeSecp256k1Util{
|
||||
|
||||
public static void assertEquals( int val, int val2, String message ) throws AssertFailException{
|
||||
if( val != val2 )
|
||||
throw new AssertFailException("FAIL: " + message);
|
||||
}
|
||||
|
||||
public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{
|
||||
if( val != val2 )
|
||||
throw new AssertFailException("FAIL: " + message);
|
||||
else
|
||||
System.out.println("PASS: " + message);
|
||||
}
|
||||
|
||||
public static void assertEquals( String val, String val2, String message ) throws AssertFailException{
|
||||
if( !val.equals(val2) )
|
||||
throw new AssertFailException("FAIL: " + message);
|
||||
else
|
||||
System.out.println("PASS: " + message);
|
||||
}
|
||||
|
||||
public static class AssertFailException extends Exception {
|
||||
public AssertFailException(String message) {
|
||||
super( message );
|
||||
}
|
||||
}
|
||||
}
|
51
src/java/org/bitcoin/Secp256k1Context.java
Normal file
51
src/java/org/bitcoin/Secp256k1Context.java
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2014-2016 the libsecp256k1 contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.bitcoin;
|
||||
|
||||
/**
|
||||
* This class holds the context reference used in native methods
|
||||
* to handle ECDSA operations.
|
||||
*/
|
||||
public class Secp256k1Context {
|
||||
private static final boolean enabled; //true if the library is loaded
|
||||
private static final long context; //ref to pointer to context obj
|
||||
|
||||
static { //static initializer
|
||||
boolean isEnabled = true;
|
||||
long contextRef = -1;
|
||||
try {
|
||||
System.loadLibrary("secp256k1");
|
||||
contextRef = secp256k1_init_context();
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
System.out.println("UnsatisfiedLinkError: " + e.toString());
|
||||
isEnabled = false;
|
||||
}
|
||||
enabled = isEnabled;
|
||||
context = contextRef;
|
||||
}
|
||||
|
||||
public static boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public static long getContext() {
|
||||
if(!enabled) return -1; //sanity check
|
||||
return context;
|
||||
}
|
||||
|
||||
private static native long secp256k1_init_context();
|
||||
}
|
|
@ -1,23 +1,411 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "org_bitcoin_NativeSecp256k1.h"
|
||||
#include "include/secp256k1.h"
|
||||
#include "include/secp256k1_ecdh.h"
|
||||
#include "include/secp256k1_recovery.h"
|
||||
#include "include/secp256k1_schnorr.h"
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject)
|
||||
|
||||
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
|
||||
(JNIEnv* env, jclass classObject, jlong ctx_l)
|
||||
{
|
||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
int sigLen = *((int*)(data + 32));
|
||||
int pubLen = *((int*)(data + 32 + 4));
|
||||
const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
|
||||
jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx);
|
||||
|
||||
(void)classObject;(void)env;
|
||||
|
||||
return ctx_clone_l;
|
||||
|
||||
return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen);
|
||||
}
|
||||
|
||||
static void __javasecp256k1_attach(void) __attribute__((constructor));
|
||||
static void __javasecp256k1_detach(void) __attribute__((destructor));
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
|
||||
const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return secp256k1_context_randomize(ctx, seed);
|
||||
|
||||
static void __javasecp256k1_attach(void) {
|
||||
secp256k1_start(SECP256K1_START_VERIFY);
|
||||
}
|
||||
|
||||
static void __javasecp256k1_detach(void) {
|
||||
secp256k1_stop();
|
||||
SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
|
||||
(JNIEnv* env, jclass classObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
|
||||
secp256k1_context_destroy(ctx);
|
||||
|
||||
(void)classObject;(void)env;
|
||||
}
|
||||
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
|
||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
const unsigned char* sigdata = { (unsigned char*) (data + 32) };
|
||||
const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) };
|
||||
|
||||
secp256k1_ecdsa_signature sig;
|
||||
secp256k1_pubkey pubkey;
|
||||
|
||||
int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen);
|
||||
|
||||
if( ret ) {
|
||||
ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
|
||||
|
||||
if( ret ) {
|
||||
ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey);
|
||||
}
|
||||
}
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
unsigned char* secKey = (unsigned char*) (data + 32);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray sigArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
|
||||
secp256k1_ecdsa_signature sig[72];
|
||||
|
||||
int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL );
|
||||
|
||||
unsigned char outputSer[72];
|
||||
size_t outputLen = 72;
|
||||
|
||||
if( ret ) {
|
||||
int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2;
|
||||
}
|
||||
|
||||
intsarray[0] = outputLen;
|
||||
intsarray[1] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
sigArray = (*env)->NewByteArray(env, outputLen);
|
||||
(*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return secp256k1_ec_seckey_verify(ctx, secKey);
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
|
||||
secp256k1_pubkey pubkey;
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray pubkeyArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
|
||||
int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey);
|
||||
|
||||
unsigned char outputSer[65];
|
||||
size_t outputLen = 65;
|
||||
|
||||
if( ret ) {
|
||||
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||
}
|
||||
|
||||
intsarray[0] = outputLen;
|
||||
intsarray[1] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
pubkeyArray = (*env)->NewByteArray(env, outputLen);
|
||||
(*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
const unsigned char* tweak = (unsigned char*) (privkey + 32);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray privArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
|
||||
int privkeylen = 32;
|
||||
|
||||
int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak);
|
||||
|
||||
intsarray[0] = privkeylen;
|
||||
intsarray[1] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
privArray = (*env)->NewByteArray(env, privkeylen);
|
||||
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, privArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
const unsigned char* tweak = (unsigned char*) (privkey + 32);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray privArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
|
||||
int privkeylen = 32;
|
||||
|
||||
int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak);
|
||||
|
||||
intsarray[0] = privkeylen;
|
||||
intsarray[1] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
privArray = (*env)->NewByteArray(env, privkeylen);
|
||||
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, privArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/
|
||||
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
const unsigned char* tweak = (unsigned char*) (pkey + publen);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray pubArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
unsigned char outputSer[65];
|
||||
size_t outputLen = 65;
|
||||
|
||||
secp256k1_pubkey pubkey;
|
||||
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
|
||||
|
||||
if( ret ) {
|
||||
ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak);
|
||||
}
|
||||
|
||||
if( ret ) {
|
||||
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||
}
|
||||
|
||||
intsarray[0] = outputLen;
|
||||
intsarray[1] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
pubArray = (*env)->NewByteArray(env, outputLen);
|
||||
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
const unsigned char* tweak = (unsigned char*) (pkey + publen);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray pubArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
unsigned char outputSer[65];
|
||||
size_t outputLen = 65;
|
||||
|
||||
secp256k1_pubkey pubkey;
|
||||
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
|
||||
|
||||
if ( ret ) {
|
||||
ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak);
|
||||
}
|
||||
|
||||
if( ret ) {
|
||||
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||
}
|
||||
|
||||
intsarray[0] = outputLen;
|
||||
intsarray[1] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
pubArray = (*env)->NewByteArray(env, outputLen);
|
||||
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
||||
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine
|
||||
(JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys)
|
||||
{
|
||||
(void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
unsigned char* secKey = (unsigned char*) (data + 32);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray sigArray, intsByteArray;
|
||||
unsigned char intsarray[1];
|
||||
unsigned char sig[64];
|
||||
|
||||
int ret = secp256k1_schnorr_sign(ctx, sig, data, secKey, NULL, NULL);
|
||||
|
||||
intsarray[0] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
sigArray = (*env)->NewByteArray(env, 64);
|
||||
(*env)->SetByteArrayRegion(env, sigArray, 0, 64, (jbyte*)sig);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 1);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
const unsigned char* pubdata = (const unsigned char*) (secdata + 32);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray outArray, intsByteArray;
|
||||
unsigned char intsarray[1];
|
||||
secp256k1_pubkey pubkey;
|
||||
unsigned char nonce_res[32];
|
||||
size_t outputLen = 32;
|
||||
|
||||
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
|
||||
|
||||
if (ret) {
|
||||
ret = secp256k1_ecdh(
|
||||
ctx,
|
||||
nonce_res,
|
||||
&pubkey,
|
||||
secdata
|
||||
);
|
||||
}
|
||||
|
||||
intsarray[0] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
outArray = (*env)->NewByteArray(env, outputLen);
|
||||
(*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, outArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 1);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
#include "include/secp256k1.h"
|
||||
/* Header for class org_bitcoin_NativeSecp256k1 */
|
||||
|
||||
#ifndef _Included_org_bitcoin_NativeSecp256k1
|
||||
|
@ -9,11 +10,116 @@ extern "C" {
|
|||
#endif
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ecdsa_verify
|
||||
* Signature: (Ljava/nio/ByteBuffer;)I
|
||||
* Method: secp256k1_ctx_clone
|
||||
* Signature: (J)J
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||
(JNIEnv *, jclass, jobject);
|
||||
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
|
||||
(JNIEnv *, jclass, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_context_randomize
|
||||
* Signature: (Ljava/nio/ByteBuffer;J)I
|
||||
*/
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_privkey_tweak_add
|
||||
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_privkey_tweak_mul
|
||||
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_pubkey_tweak_add
|
||||
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
|
||||
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_pubkey_tweak_mul
|
||||
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
|
||||
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_destroy_context
|
||||
* Signature: (J)V
|
||||
*/
|
||||
SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
|
||||
(JNIEnv *, jclass, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ecdsa_verify
|
||||
* Signature: (Ljava/nio/ByteBuffer;JII)I
|
||||
*/
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||
(JNIEnv *, jclass, jobject, jlong, jint, jint);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ecdsa_sign
|
||||
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ec_seckey_verify
|
||||
* Signature: (Ljava/nio/ByteBuffer;J)I
|
||||
*/
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ec_pubkey_create
|
||||
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ec_pubkey_parse
|
||||
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
|
||||
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_schnorr_sign
|
||||
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ecdh
|
||||
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
15
src/java/org_bitcoin_Secp256k1Context.c
Normal file
15
src/java/org_bitcoin_Secp256k1Context.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "org_bitcoin_Secp256k1Context.h"
|
||||
#include "include/secp256k1.h"
|
||||
|
||||
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
|
||||
(JNIEnv* env, jclass classObject)
|
||||
{
|
||||
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
|
||||
(void)classObject;(void)env;
|
||||
|
||||
return (uintptr_t)ctx;
|
||||
}
|
||||
|
22
src/java/org_bitcoin_Secp256k1Context.h
Normal file
22
src/java/org_bitcoin_Secp256k1Context.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
#include "include/secp256k1.h"
|
||||
/* Header for class org_bitcoin_Secp256k1Context */
|
||||
|
||||
#ifndef _Included_org_bitcoin_Secp256k1Context
|
||||
#define _Included_org_bitcoin_Secp256k1Context
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: org_bitcoin_Secp256k1Context
|
||||
* Method: secp256k1_init_context
|
||||
* Signature: ()J
|
||||
*/
|
||||
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -4,5 +4,5 @@ noinst_HEADERS += src/modules/ecdh/tests_impl.h
|
|||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_ecdh
|
||||
bench_ecdh_SOURCES = src/bench_ecdh.c
|
||||
bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
|
||||
endif
|
||||
|
|
|
@ -4,5 +4,5 @@ noinst_HEADERS += src/modules/recovery/tests_impl.h
|
|||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_recover
|
||||
bench_recover_SOURCES = src/bench_recover.c
|
||||
bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
|
||||
endif
|
||||
|
|
|
@ -6,5 +6,5 @@ noinst_HEADERS += src/modules/schnorr/tests_impl.h
|
|||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_schnorr_verify
|
||||
bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c
|
||||
bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
|
||||
endif
|
||||
|
|
|
@ -32,6 +32,9 @@ static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsi
|
|||
/** Compute a modular inverse. The input must be less than the modulus. */
|
||||
static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m);
|
||||
|
||||
/** Compute the jacobi symbol (a|b). b must be positive and odd. */
|
||||
static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b);
|
||||
|
||||
/** Compare the absolute value of two numbers. */
|
||||
static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b);
|
||||
|
||||
|
@ -57,6 +60,9 @@ static void secp256k1_num_shift(secp256k1_num *r, int bits);
|
|||
/** Check whether a number is zero. */
|
||||
static int secp256k1_num_is_zero(const secp256k1_num *a);
|
||||
|
||||
/** Check whether a number is one. */
|
||||
static int secp256k1_num_is_one(const secp256k1_num *a);
|
||||
|
||||
/** Check whether a number is strictly negative. */
|
||||
static int secp256k1_num_is_neg(const secp256k1_num *a);
|
||||
|
||||
|
|
|
@ -144,6 +144,32 @@ static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a,
|
|||
memset(v, 0, sizeof(v));
|
||||
}
|
||||
|
||||
static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b) {
|
||||
int ret;
|
||||
mpz_t ga, gb;
|
||||
secp256k1_num_sanity(a);
|
||||
secp256k1_num_sanity(b);
|
||||
VERIFY_CHECK(!b->neg && (b->limbs > 0) && (b->data[0] & 1));
|
||||
|
||||
mpz_inits(ga, gb, NULL);
|
||||
|
||||
mpz_import(gb, b->limbs, -1, sizeof(mp_limb_t), 0, 0, b->data);
|
||||
mpz_import(ga, a->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data);
|
||||
if (a->neg) {
|
||||
mpz_neg(ga, ga);
|
||||
}
|
||||
|
||||
ret = mpz_jacobi(ga, gb);
|
||||
|
||||
mpz_clears(ga, gb, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int secp256k1_num_is_one(const secp256k1_num *a) {
|
||||
return (a->limbs == 1 && a->data[0] == 1);
|
||||
}
|
||||
|
||||
static int secp256k1_num_is_zero(const secp256k1_num *a) {
|
||||
return (a->limbs == 1 && a->data[0] == 0);
|
||||
}
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
#ifndef _SECP256K1_SCALAR_IMPL_H_
|
||||
#define _SECP256K1_SCALAR_IMPL_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#define SECP256K1_BUILD (1)
|
||||
|
||||
#include "include/secp256k1.h"
|
||||
|
||||
#include "util.h"
|
||||
|
@ -152,7 +150,6 @@ static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
|
|||
int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) {
|
||||
secp256k1_ge Q;
|
||||
|
||||
(void)ctx;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
|
@ -170,7 +167,6 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o
|
|||
size_t len;
|
||||
int ret = 0;
|
||||
|
||||
(void)ctx;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(outputlen != NULL);
|
||||
ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65));
|
||||
|
@ -216,7 +212,7 @@ static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const
|
|||
int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
|
||||
secp256k1_scalar r, s;
|
||||
|
||||
(void)ctx;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(input != NULL);
|
||||
|
||||
|
@ -234,7 +230,7 @@ int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp25
|
|||
int ret = 1;
|
||||
int overflow = 0;
|
||||
|
||||
(void)ctx;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(input64 != NULL);
|
||||
|
||||
|
@ -253,7 +249,7 @@ int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp25
|
|||
int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) {
|
||||
secp256k1_scalar r, s;
|
||||
|
||||
(void)ctx;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output != NULL);
|
||||
ARG_CHECK(outputlen != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
|
@ -265,7 +261,7 @@ int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsign
|
|||
int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) {
|
||||
secp256k1_scalar r, s;
|
||||
|
||||
(void)ctx;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output64 != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
|
||||
|
@ -398,7 +394,6 @@ int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char
|
|||
int overflow;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
(void)ctx;
|
||||
|
||||
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
|
||||
ret = !overflow && !secp256k1_scalar_is_zero(&sec);
|
||||
|
@ -437,7 +432,6 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *
|
|||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
ARG_CHECK(tweak != NULL);
|
||||
(void)ctx;
|
||||
|
||||
secp256k1_scalar_set_b32(&term, tweak, &overflow);
|
||||
secp256k1_scalar_set_b32(&sec, seckey, NULL);
|
||||
|
@ -485,7 +479,6 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *
|
|||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
ARG_CHECK(tweak != NULL);
|
||||
(void)ctx;
|
||||
|
||||
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
|
||||
secp256k1_scalar_set_b32(&sec, seckey, NULL);
|
||||
|
|
190
src/tests.c
190
src/tests.c
|
@ -473,6 +473,8 @@ void test_num_negate(void) {
|
|||
}
|
||||
|
||||
void test_num_add_sub(void) {
|
||||
int i;
|
||||
secp256k1_scalar s;
|
||||
secp256k1_num n1;
|
||||
secp256k1_num n2;
|
||||
secp256k1_num n1p2, n2p1, n1m2, n2m1;
|
||||
|
@ -498,6 +500,110 @@ void test_num_add_sub(void) {
|
|||
CHECK(!secp256k1_num_eq(&n2p1, &n1));
|
||||
secp256k1_num_sub(&n2p1, &n2p1, &n2); /* n2p1 = R2 + R1 - R2 = R1 */
|
||||
CHECK(secp256k1_num_eq(&n2p1, &n1));
|
||||
|
||||
/* check is_one */
|
||||
secp256k1_scalar_set_int(&s, 1);
|
||||
secp256k1_scalar_get_num(&n1, &s);
|
||||
CHECK(secp256k1_num_is_one(&n1));
|
||||
/* check that 2^n + 1 is never 1 */
|
||||
secp256k1_scalar_get_num(&n2, &s);
|
||||
for (i = 0; i < 250; ++i) {
|
||||
secp256k1_num_add(&n1, &n1, &n1); /* n1 *= 2 */
|
||||
secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = n1 + 1 */
|
||||
CHECK(!secp256k1_num_is_one(&n1p2));
|
||||
}
|
||||
}
|
||||
|
||||
void test_num_mod(void) {
|
||||
int i;
|
||||
secp256k1_scalar s;
|
||||
secp256k1_num order, n;
|
||||
|
||||
/* check that 0 mod anything is 0 */
|
||||
random_scalar_order_test(&s);
|
||||
secp256k1_scalar_get_num(&order, &s);
|
||||
secp256k1_scalar_set_int(&s, 0);
|
||||
secp256k1_scalar_get_num(&n, &s);
|
||||
secp256k1_num_mod(&n, &order);
|
||||
CHECK(secp256k1_num_is_zero(&n));
|
||||
|
||||
/* check that anything mod 1 is 0 */
|
||||
secp256k1_scalar_set_int(&s, 1);
|
||||
secp256k1_scalar_get_num(&order, &s);
|
||||
secp256k1_scalar_get_num(&n, &s);
|
||||
secp256k1_num_mod(&n, &order);
|
||||
CHECK(secp256k1_num_is_zero(&n));
|
||||
|
||||
/* check that increasing the number past 2^256 does not break this */
|
||||
random_scalar_order_test(&s);
|
||||
secp256k1_scalar_get_num(&n, &s);
|
||||
/* multiply by 2^8, which'll test this case with high probability */
|
||||
for (i = 0; i < 8; ++i) {
|
||||
secp256k1_num_add(&n, &n, &n);
|
||||
}
|
||||
secp256k1_num_mod(&n, &order);
|
||||
CHECK(secp256k1_num_is_zero(&n));
|
||||
}
|
||||
|
||||
void test_num_jacobi(void) {
|
||||
secp256k1_scalar sqr;
|
||||
secp256k1_scalar small;
|
||||
secp256k1_scalar five; /* five is not a quadratic residue */
|
||||
secp256k1_num order, n;
|
||||
int i;
|
||||
/* squares mod 5 are 1, 4 */
|
||||
const int jacobi5[10] = { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1 };
|
||||
|
||||
/* check some small values with 5 as the order */
|
||||
secp256k1_scalar_set_int(&five, 5);
|
||||
secp256k1_scalar_get_num(&order, &five);
|
||||
for (i = 0; i < 10; ++i) {
|
||||
secp256k1_scalar_set_int(&small, i);
|
||||
secp256k1_scalar_get_num(&n, &small);
|
||||
CHECK(secp256k1_num_jacobi(&n, &order) == jacobi5[i]);
|
||||
}
|
||||
|
||||
/** test large values with 5 as group order */
|
||||
secp256k1_scalar_get_num(&order, &five);
|
||||
/* we first need a scalar which is not a multiple of 5 */
|
||||
do {
|
||||
secp256k1_num fiven;
|
||||
random_scalar_order_test(&sqr);
|
||||
secp256k1_scalar_get_num(&fiven, &five);
|
||||
secp256k1_scalar_get_num(&n, &sqr);
|
||||
secp256k1_num_mod(&n, &fiven);
|
||||
} while (secp256k1_num_is_zero(&n));
|
||||
/* next force it to be a residue. 2 is a nonresidue mod 5 so we can
|
||||
* just multiply by two, i.e. add the number to itself */
|
||||
if (secp256k1_num_jacobi(&n, &order) == -1) {
|
||||
secp256k1_num_add(&n, &n, &n);
|
||||
}
|
||||
|
||||
/* test residue */
|
||||
CHECK(secp256k1_num_jacobi(&n, &order) == 1);
|
||||
/* test nonresidue */
|
||||
secp256k1_num_add(&n, &n, &n);
|
||||
CHECK(secp256k1_num_jacobi(&n, &order) == -1);
|
||||
|
||||
/** test with secp group order as order */
|
||||
secp256k1_scalar_order_get_num(&order);
|
||||
random_scalar_order_test(&sqr);
|
||||
secp256k1_scalar_sqr(&sqr, &sqr);
|
||||
/* test residue */
|
||||
secp256k1_scalar_get_num(&n, &sqr);
|
||||
CHECK(secp256k1_num_jacobi(&n, &order) == 1);
|
||||
/* test nonresidue */
|
||||
secp256k1_scalar_mul(&sqr, &sqr, &five);
|
||||
secp256k1_scalar_get_num(&n, &sqr);
|
||||
CHECK(secp256k1_num_jacobi(&n, &order) == -1);
|
||||
/* test multiple of the order*/
|
||||
CHECK(secp256k1_num_jacobi(&order, &order) == 0);
|
||||
|
||||
/* check one less than the order */
|
||||
secp256k1_scalar_set_int(&small, 1);
|
||||
secp256k1_scalar_get_num(&n, &small);
|
||||
secp256k1_num_sub(&n, &order, &n);
|
||||
CHECK(secp256k1_num_jacobi(&n, &order) == 1); /* sage confirms this is 1 */
|
||||
}
|
||||
|
||||
void run_num_smalltests(void) {
|
||||
|
@ -505,6 +611,8 @@ void run_num_smalltests(void) {
|
|||
for (i = 0; i < 100*count; i++) {
|
||||
test_num_negate();
|
||||
test_num_add_sub();
|
||||
test_num_mod();
|
||||
test_num_jacobi();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -689,6 +797,10 @@ void scalar_test(void) {
|
|||
secp256k1_scalar_inverse(&inv, &inv);
|
||||
/* Inverting one must result in one. */
|
||||
CHECK(secp256k1_scalar_is_one(&inv));
|
||||
#ifndef USE_NUM_NONE
|
||||
secp256k1_scalar_get_num(&invnum, &inv);
|
||||
CHECK(secp256k1_num_is_one(&invnum));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -855,7 +967,7 @@ void run_scalar_tests(void) {
|
|||
secp256k1_scalar zzv;
|
||||
#endif
|
||||
int overflow;
|
||||
unsigned char chal[32][2][32] = {
|
||||
unsigned char chal[33][2][32] = {
|
||||
{{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,
|
||||
|
@ -1111,9 +1223,17 @@ void run_scalar_tests(void) {
|
|||
{0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,
|
||||
0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}}
|
||||
0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}},
|
||||
{{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
|
||||
0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb,
|
||||
0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03},
|
||||
{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
|
||||
0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb,
|
||||
0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}}
|
||||
};
|
||||
unsigned char res[32][2][32] = {
|
||||
unsigned char res[33][2][32] = {
|
||||
{{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9,
|
||||
0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1,
|
||||
0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6,
|
||||
|
@ -1369,10 +1489,18 @@ void run_scalar_tests(void) {
|
|||
{0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2,
|
||||
0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38,
|
||||
0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34,
|
||||
0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}}
|
||||
0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}},
|
||||
{{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34,
|
||||
0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13,
|
||||
0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46,
|
||||
0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5},
|
||||
{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34,
|
||||
0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13,
|
||||
0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46,
|
||||
0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}}
|
||||
};
|
||||
secp256k1_scalar_set_int(&one, 1);
|
||||
for (i = 0; i < 32; i++) {
|
||||
for (i = 0; i < 33; i++) {
|
||||
secp256k1_scalar_set_b32(&x, chal[i][0], &overflow);
|
||||
CHECK(!overflow);
|
||||
secp256k1_scalar_set_b32(&y, chal[i][1], &overflow);
|
||||
|
@ -1446,7 +1574,7 @@ void random_fe_non_zero(secp256k1_fe *nz) {
|
|||
void random_fe_non_square(secp256k1_fe *ns) {
|
||||
secp256k1_fe r;
|
||||
random_fe_non_zero(ns);
|
||||
if (secp256k1_fe_sqrt_var(&r, ns)) {
|
||||
if (secp256k1_fe_sqrt(&r, ns)) {
|
||||
secp256k1_fe_negate(ns, ns, 1);
|
||||
}
|
||||
}
|
||||
|
@ -1641,7 +1769,7 @@ void run_sqr(void) {
|
|||
|
||||
void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) {
|
||||
secp256k1_fe r1, r2;
|
||||
int v = secp256k1_fe_sqrt_var(&r1, a);
|
||||
int v = secp256k1_fe_sqrt(&r1, a);
|
||||
CHECK((v == 0) == (k == NULL));
|
||||
|
||||
if (k != NULL) {
|
||||
|
@ -1951,8 +2079,8 @@ void test_add_neg_y_diff_x(void) {
|
|||
* of the sum to be wrong (since infinity has no xy coordinates).
|
||||
* HOWEVER, if the x-coordinates are different, infinity is the
|
||||
* wrong answer, and such degeneracies are exposed. This is the
|
||||
* root of https://github.com/bitcoin/secp256k1/issues/257 which
|
||||
* this test is a regression test for.
|
||||
* root of https://github.com/bitcoin-core/secp256k1/issues/257
|
||||
* which this test is a regression test for.
|
||||
*
|
||||
* These points were generated in sage as
|
||||
* # secp256k1 params
|
||||
|
@ -2051,15 +2179,16 @@ void run_ec_combine(void) {
|
|||
void test_group_decompress(const secp256k1_fe* x) {
|
||||
/* The input itself, normalized. */
|
||||
secp256k1_fe fex = *x;
|
||||
secp256k1_fe tmp;
|
||||
secp256k1_fe fez;
|
||||
/* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */
|
||||
secp256k1_ge ge_quad, ge_even, ge_odd;
|
||||
secp256k1_gej gej_quad;
|
||||
/* Return values of the above calls. */
|
||||
int res_quad, res_even, res_odd;
|
||||
|
||||
secp256k1_fe_normalize_var(&fex);
|
||||
|
||||
res_quad = secp256k1_ge_set_xquad_var(&ge_quad, &fex);
|
||||
res_quad = secp256k1_ge_set_xquad(&ge_quad, &fex);
|
||||
res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0);
|
||||
res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1);
|
||||
|
||||
|
@ -2085,13 +2214,29 @@ void test_group_decompress(const secp256k1_fe* x) {
|
|||
CHECK(secp256k1_fe_equal_var(&ge_odd.x, x));
|
||||
|
||||
/* Check that the Y coordinate result in ge_quad is a square. */
|
||||
CHECK(secp256k1_fe_sqrt_var(&tmp, &ge_quad.y));
|
||||
secp256k1_fe_sqr(&tmp, &tmp);
|
||||
CHECK(secp256k1_fe_equal_var(&tmp, &ge_quad.y));
|
||||
CHECK(secp256k1_fe_is_quad_var(&ge_quad.y));
|
||||
|
||||
/* Check odd/even Y in ge_odd, ge_even. */
|
||||
CHECK(secp256k1_fe_is_odd(&ge_odd.y));
|
||||
CHECK(!secp256k1_fe_is_odd(&ge_even.y));
|
||||
|
||||
/* Check secp256k1_gej_has_quad_y_var. */
|
||||
secp256k1_gej_set_ge(&gej_quad, &ge_quad);
|
||||
CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));
|
||||
do {
|
||||
random_fe_test(&fez);
|
||||
} while (secp256k1_fe_is_zero(&fez));
|
||||
secp256k1_gej_rescale(&gej_quad, &fez);
|
||||
CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));
|
||||
secp256k1_gej_neg(&gej_quad, &gej_quad);
|
||||
CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad));
|
||||
do {
|
||||
random_fe_test(&fez);
|
||||
} while (secp256k1_fe_is_zero(&fez));
|
||||
secp256k1_gej_rescale(&gej_quad, &fez);
|
||||
CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad));
|
||||
secp256k1_gej_neg(&gej_quad, &gej_quad);
|
||||
CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2383,9 +2528,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
|
|||
secp256k1_scalar x, shift;
|
||||
int wnaf[256] = {0};
|
||||
int i;
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
int skew;
|
||||
#endif
|
||||
secp256k1_scalar num = *number;
|
||||
|
||||
secp256k1_scalar_set_int(&x, 0);
|
||||
|
@ -2395,10 +2538,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
|
|||
for (i = 0; i < 16; ++i) {
|
||||
secp256k1_scalar_shr_int(&num, 8);
|
||||
}
|
||||
skew = secp256k1_wnaf_const(wnaf, num, w);
|
||||
#else
|
||||
secp256k1_wnaf_const(wnaf, num, w);
|
||||
#endif
|
||||
skew = secp256k1_wnaf_const(wnaf, num, w);
|
||||
|
||||
for (i = WNAF_SIZE(w); i >= 0; --i) {
|
||||
secp256k1_scalar t;
|
||||
|
@ -2417,10 +2558,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
|
|||
}
|
||||
secp256k1_scalar_add(&x, &x, &t);
|
||||
}
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
/* Skew num because when encoding 128-bit numbers as odd we use an offset */
|
||||
/* Skew num because when encoding numbers as odd we use an offset */
|
||||
secp256k1_scalar_cadd_bit(&num, skew == 2, 1);
|
||||
#endif
|
||||
CHECK(secp256k1_scalar_eq(&x, &num));
|
||||
}
|
||||
|
||||
|
@ -3484,12 +3623,14 @@ void run_ecdsa_end_to_end(void) {
|
|||
|
||||
int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) {
|
||||
static const unsigned char zeroes[32] = {0};
|
||||
#ifdef ENABLE_OPENSSL_TESTS
|
||||
static const unsigned char max_scalar[32] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
|
||||
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40
|
||||
};
|
||||
#endif
|
||||
|
||||
int ret = 0;
|
||||
|
||||
|
@ -3607,13 +3748,13 @@ static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) {
|
|||
static void damage_array(unsigned char *sig, size_t *len) {
|
||||
int pos;
|
||||
int action = secp256k1_rand_bits(3);
|
||||
if (action < 1) {
|
||||
if (action < 1 && *len > 3) {
|
||||
/* Delete a byte. */
|
||||
pos = secp256k1_rand_int(*len);
|
||||
memmove(sig + pos, sig + pos + 1, *len - pos - 1);
|
||||
(*len)--;
|
||||
return;
|
||||
} else if (action < 2) {
|
||||
} else if (action < 2 && *len < 2048) {
|
||||
/* Insert a byte. */
|
||||
pos = secp256k1_rand_int(1 + *len);
|
||||
memmove(sig + pos + 1, sig + pos, *len - pos);
|
||||
|
@ -3785,6 +3926,7 @@ void run_ecdsa_der_parse(void) {
|
|||
int certainly_der = 0;
|
||||
int certainly_not_der = 0;
|
||||
random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der);
|
||||
CHECK(buflen <= 2048);
|
||||
for (j = 0; j < 16; j++) {
|
||||
int ret = 0;
|
||||
if (j > 0) {
|
||||
|
|
Loading…
Reference in a new issue