From 984d94e7114d94f6fec0152b99bb7a2f53fa47af Mon Sep 17 00:00:00 2001 From: Navia Bheeman Date: Mon, 17 Jan 2022 01:45:15 +0530 Subject: [PATCH 01/11] removing secp256k1 to make it a submodule --- src/secp256k1/.gitignore | 49 - src/secp256k1/.travis.yml | 69 - src/secp256k1/CMakeLists.txt | 168 - src/secp256k1/COPYING | 19 - src/secp256k1/Makefile.am | 181 - src/secp256k1/README.md | 61 - src/secp256k1/TODO | 3 - src/secp256k1/autogen.sh | 3 - .../build-aux/m4/ax_jni_include_dir.m4 | 140 - .../build-aux/m4/ax_prog_cc_for_build.m4 | 125 - src/secp256k1/build-aux/m4/bitcoin_secp.m4 | 69 - src/secp256k1/configure.ac | 504 -- src/secp256k1/contrib/lax_der_parsing.c | 150 - src/secp256k1/contrib/lax_der_parsing.h | 91 - .../contrib/lax_der_privatekey_parsing.c | 113 - .../contrib/lax_der_privatekey_parsing.h | 90 - src/secp256k1/include/secp256k1.h | 621 --- src/secp256k1/include/secp256k1_ecdh.h | 31 - src/secp256k1/include/secp256k1_recovery.h | 110 - src/secp256k1/include/secp256k1_schnorr.h | 57 - src/secp256k1/libsecp256k1.pc.in | 13 - src/secp256k1/obj/.gitignore | 0 src/secp256k1/sage/group_prover.sage | 322 -- src/secp256k1/sage/secp256k1.sage | 306 -- src/secp256k1/sage/weierstrass_prover.sage | 264 - src/secp256k1/src/asm/field_10x26_arm.s | 919 ---- src/secp256k1/src/basic-config.h | 33 - src/secp256k1/src/bench.h | 66 - src/secp256k1/src/bench_ecdh.c | 54 - src/secp256k1/src/bench_internal.c | 382 -- src/secp256k1/src/bench_recover.c | 60 - src/secp256k1/src/bench_sign.c | 56 - src/secp256k1/src/bench_verify.c | 112 - src/secp256k1/src/ecdsa.h | 21 - src/secp256k1/src/ecdsa_impl.h | 313 -- src/secp256k1/src/eckey.h | 25 - src/secp256k1/src/eckey_impl.h | 100 - src/secp256k1/src/ecmult.h | 31 - src/secp256k1/src/ecmult_const.h | 15 - src/secp256k1/src/ecmult_const_impl.h | 240 - src/secp256k1/src/ecmult_gen.h | 43 - src/secp256k1/src/ecmult_gen_impl.h | 210 - src/secp256k1/src/ecmult_impl.h | 406 -- src/secp256k1/src/field.h | 132 - src/secp256k1/src/field_10x26.h | 48 - src/secp256k1/src/field_10x26_impl.h | 1161 ----- src/secp256k1/src/field_5x52.h | 47 - src/secp256k1/src/field_5x52_asm_impl.h | 502 -- src/secp256k1/src/field_5x52_impl.h | 496 -- src/secp256k1/src/field_5x52_int128_impl.h | 277 - src/secp256k1/src/field_impl.h | 315 -- src/secp256k1/src/gen_context.c | 74 - src/secp256k1/src/group.h | 144 - src/secp256k1/src/group_impl.h | 700 --- src/secp256k1/src/hash.h | 41 - src/secp256k1/src/hash_impl.h | 281 - .../src/java/org/bitcoin/NativeSecp256k1.java | 446 -- .../java/org/bitcoin/NativeSecp256k1Test.java | 226 - .../java/org/bitcoin/NativeSecp256k1Util.java | 45 - .../java/org/bitcoin/Secp256k1Context.java | 51 - .../src/java/org_bitcoin_NativeSecp256k1.c | 377 -- .../src/java/org_bitcoin_NativeSecp256k1.h | 119 - .../src/java/org_bitcoin_Secp256k1Context.c | 15 - .../src/java/org_bitcoin_Secp256k1Context.h | 22 - .../src/libsecp256k1-config.h.cmake.in | 31 - .../src/modules/ecdh/Makefile.am.include | 8 - src/secp256k1/src/modules/ecdh/main_impl.h | 54 - src/secp256k1/src/modules/ecdh/tests_impl.h | 105 - .../src/modules/recovery/Makefile.am.include | 8 - .../src/modules/recovery/main_impl.h | 193 - .../src/modules/recovery/tests_impl.h | 393 -- .../src/modules/schnorr/Makefile.am.include | 3 - src/secp256k1/src/modules/schnorr/main_impl.h | 235 - .../src/modules/schnorr/tests_impl.h | 680 --- src/secp256k1/src/num.h | 74 - src/secp256k1/src/num_gmp.h | 20 - src/secp256k1/src/num_gmp_impl.h | 288 -- src/secp256k1/src/num_impl.h | 24 - src/secp256k1/src/scalar.h | 106 - src/secp256k1/src/scalar_4x64.h | 19 - src/secp256k1/src/scalar_4x64_impl.h | 949 ---- src/secp256k1/src/scalar_8x32.h | 19 - src/secp256k1/src/scalar_8x32_impl.h | 721 --- src/secp256k1/src/scalar_impl.h | 333 -- src/secp256k1/src/scalar_low.h | 15 - src/secp256k1/src/scalar_low_impl.h | 114 - src/secp256k1/src/secp256k1.c | 589 --- src/secp256k1/src/testrand.h | 38 - src/secp256k1/src/testrand_impl.h | 110 - src/secp256k1/src/tests.c | 4545 ----------------- src/secp256k1/src/tests_exhaustive.c | 470 -- src/secp256k1/src/util.h | 113 - 92 files changed, 22421 deletions(-) delete mode 100644 src/secp256k1/.gitignore delete mode 100644 src/secp256k1/.travis.yml delete mode 100644 src/secp256k1/CMakeLists.txt delete mode 100644 src/secp256k1/COPYING delete mode 100644 src/secp256k1/Makefile.am delete mode 100644 src/secp256k1/README.md delete mode 100644 src/secp256k1/TODO delete mode 100755 src/secp256k1/autogen.sh delete mode 100644 src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 delete mode 100644 src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 delete mode 100644 src/secp256k1/build-aux/m4/bitcoin_secp.m4 delete mode 100644 src/secp256k1/configure.ac delete mode 100644 src/secp256k1/contrib/lax_der_parsing.c delete mode 100644 src/secp256k1/contrib/lax_der_parsing.h delete mode 100644 src/secp256k1/contrib/lax_der_privatekey_parsing.c delete mode 100644 src/secp256k1/contrib/lax_der_privatekey_parsing.h delete mode 100644 src/secp256k1/include/secp256k1.h delete mode 100644 src/secp256k1/include/secp256k1_ecdh.h delete mode 100644 src/secp256k1/include/secp256k1_recovery.h delete mode 100644 src/secp256k1/include/secp256k1_schnorr.h delete mode 100644 src/secp256k1/libsecp256k1.pc.in delete mode 100644 src/secp256k1/obj/.gitignore delete mode 100644 src/secp256k1/sage/group_prover.sage delete mode 100644 src/secp256k1/sage/secp256k1.sage delete mode 100644 src/secp256k1/sage/weierstrass_prover.sage delete mode 100644 src/secp256k1/src/asm/field_10x26_arm.s delete mode 100644 src/secp256k1/src/basic-config.h delete mode 100644 src/secp256k1/src/bench.h delete mode 100644 src/secp256k1/src/bench_ecdh.c delete mode 100644 src/secp256k1/src/bench_internal.c delete mode 100644 src/secp256k1/src/bench_recover.c delete mode 100644 src/secp256k1/src/bench_sign.c delete mode 100644 src/secp256k1/src/bench_verify.c delete mode 100644 src/secp256k1/src/ecdsa.h delete mode 100644 src/secp256k1/src/ecdsa_impl.h delete mode 100644 src/secp256k1/src/eckey.h delete mode 100644 src/secp256k1/src/eckey_impl.h delete mode 100644 src/secp256k1/src/ecmult.h delete mode 100644 src/secp256k1/src/ecmult_const.h delete mode 100644 src/secp256k1/src/ecmult_const_impl.h delete mode 100644 src/secp256k1/src/ecmult_gen.h delete mode 100644 src/secp256k1/src/ecmult_gen_impl.h delete mode 100644 src/secp256k1/src/ecmult_impl.h delete mode 100644 src/secp256k1/src/field.h delete mode 100644 src/secp256k1/src/field_10x26.h delete mode 100644 src/secp256k1/src/field_10x26_impl.h delete mode 100644 src/secp256k1/src/field_5x52.h delete mode 100644 src/secp256k1/src/field_5x52_asm_impl.h delete mode 100644 src/secp256k1/src/field_5x52_impl.h delete mode 100644 src/secp256k1/src/field_5x52_int128_impl.h delete mode 100644 src/secp256k1/src/field_impl.h delete mode 100644 src/secp256k1/src/gen_context.c delete mode 100644 src/secp256k1/src/group.h delete mode 100644 src/secp256k1/src/group_impl.h delete mode 100644 src/secp256k1/src/hash.h delete mode 100644 src/secp256k1/src/hash_impl.h delete mode 100644 src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java delete mode 100644 src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java delete mode 100644 src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java delete mode 100644 src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java delete mode 100644 src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c delete mode 100644 src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h delete mode 100644 src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c delete mode 100644 src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h delete mode 100644 src/secp256k1/src/libsecp256k1-config.h.cmake.in delete mode 100644 src/secp256k1/src/modules/ecdh/Makefile.am.include delete mode 100644 src/secp256k1/src/modules/ecdh/main_impl.h delete mode 100644 src/secp256k1/src/modules/ecdh/tests_impl.h delete mode 100644 src/secp256k1/src/modules/recovery/Makefile.am.include delete mode 100755 src/secp256k1/src/modules/recovery/main_impl.h delete mode 100644 src/secp256k1/src/modules/recovery/tests_impl.h delete mode 100644 src/secp256k1/src/modules/schnorr/Makefile.am.include delete mode 100755 src/secp256k1/src/modules/schnorr/main_impl.h delete mode 100644 src/secp256k1/src/modules/schnorr/tests_impl.h delete mode 100644 src/secp256k1/src/num.h delete mode 100644 src/secp256k1/src/num_gmp.h delete mode 100644 src/secp256k1/src/num_gmp_impl.h delete mode 100644 src/secp256k1/src/num_impl.h delete mode 100644 src/secp256k1/src/scalar.h delete mode 100644 src/secp256k1/src/scalar_4x64.h delete mode 100644 src/secp256k1/src/scalar_4x64_impl.h delete mode 100644 src/secp256k1/src/scalar_8x32.h delete mode 100644 src/secp256k1/src/scalar_8x32_impl.h delete mode 100644 src/secp256k1/src/scalar_impl.h delete mode 100644 src/secp256k1/src/scalar_low.h delete mode 100644 src/secp256k1/src/scalar_low_impl.h delete mode 100644 src/secp256k1/src/secp256k1.c delete mode 100644 src/secp256k1/src/testrand.h delete mode 100644 src/secp256k1/src/testrand_impl.h delete mode 100644 src/secp256k1/src/tests.c delete mode 100644 src/secp256k1/src/tests_exhaustive.c delete mode 100644 src/secp256k1/src/util.h diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore deleted file mode 100644 index 87fea161ba..0000000000 --- a/src/secp256k1/.gitignore +++ /dev/null @@ -1,49 +0,0 @@ -bench_inv -bench_ecdh -bench_sign -bench_verify -bench_schnorr_verify -bench_recover -bench_internal -tests -exhaustive_tests -gen_context -*.exe -*.so -*.a -!.gitignore - -Makefile -configure -.libs/ -Makefile.in -aclocal.m4 -autom4te.cache/ -config.log -config.status -*.tar.gz -*.la -libtool -.deps/ -.dirstamp -*.lo -*.o -*~ -src/libsecp256k1-config.h -src/libsecp256k1-config.h.in -src/ecmult_static_context.h -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 diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml deleted file mode 100644 index 2439529242..0000000000 --- a/src/secp256k1/.travis.yml +++ /dev/null @@ -1,69 +0,0 @@ -language: c -sudo: false -addons: - apt: - packages: libgmp-dev -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 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 EXPERIMENTAL=yes - - SCALAR=64bit - - FIELD=64bit RECOVERY=yes - - FIELD=64bit ENDOMORPHISM=yes - - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes - - FIELD=64bit ASM=x86_64 - - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 - - FIELD=32bit ENDOMORPHISM=yes - - BIGNUM=no - - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes - - BIGNUM=no STATICPRECOMPUTATION=no - - BUILD=distcheck - - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC - - EXTRAFLAGS=CFLAGS=-O0 - - BUILD=check-java ECDH=yes EXPERIMENTAL=yes -matrix: - fast_finish: true - include: - - compiler: clang - env: HOST=i686-linux-gnu ENDOMORPHISM=yes - addons: - apt: - packages: - - gcc-multilib - - libgmp-dev:i386 - - compiler: clang - env: HOST=i686-linux-gnu - addons: - apt: - packages: - - gcc-multilib - - compiler: gcc - env: HOST=i686-linux-gnu ENDOMORPHISM=yes - addons: - apt: - packages: - - gcc-multilib - - compiler: gcc - env: HOST=i686-linux-gnu - addons: - apt: - 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-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-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD -os: linux diff --git a/src/secp256k1/CMakeLists.txt b/src/secp256k1/CMakeLists.txt deleted file mode 100644 index 3aad19f497..0000000000 --- a/src/secp256k1/CMakeLists.txt +++ /dev/null @@ -1,168 +0,0 @@ -# Copyright (c) 2017 The Bitcoin developers - -cmake_minimum_required(VERSION 3.5) -project(secp256k1) - -# libsecp256k1 use a different set of flags. -add_compiler_flag( - -pedantic - -Wshadow - -Wno-unused-function - -Wno-nonnull - -Wno-overlength-strings -) - -add_c_compiler_flag( - -Wno-long-long -) - -# Default visibility is hidden on all targets. -set(CMAKE_C_VISIBILITY_PRESET hidden) - -include_directories( - . - src - # For the config - ${CMAKE_CURRENT_BINARY_DIR}/src -) - -# The library -add_library(secp256k1 src/secp256k1.c) -target_include_directories(secp256k1 PUBLIC include) - -# We need to link in GMP -find_package(GMP) -if(GMP_FOUND) - target_include_directories(secp256k1 PUBLIC ${GMP_INCLUDE_DIR}) - target_link_libraries(secp256k1 ${GMP_LIBRARY}) - set(USE_NUM_GMP 1) - set(USE_FIELD_INV_NUM 1) - set(USE_SCALAR_INV_NUM 1) -else() - set(USE_NUM_NONE 1) - set(USE_FIELD_INV_BUILTIN 1) - set(USE_SCALAR_INV_BUILTIN 1) -endif() - -# We check if amd64 asm is supported. -check_c_source_compiles(" - #include - int main() { - uint64_t a = 11, tmp; - __asm__ __volatile__(\"movq \$0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\"); - return 0; - } -" USE_ASM_X86_64) - -# We make sure __int128 is defined -include(CheckTypeSize) -check_type_size(__int128 SIZEOF___INT128) -if(SIZEOF___INT128 EQUAL 16) - set(HAVE___INT128 1) -else() - # If we do not support __int128, we should be falling back - # on 32bits implementations for field and scalar. -endif() - -# Detect if we are on a 32 or 64 bits plateform and chose -# scalar and filed implementation accordingly -if(CMAKE_SIZEOF_VOID_P EQUAL 8) - # 64 bits implementationr require either __int128 or asm support. - if (HAVE___INT128 OR USE_ASM_X86_64) - set(USE_SCALAR_4X64 1) - set(USE_FIELD_5X52 1) - else() - message(SEND_ERROR "Compiler does not support __int128 or insline assembly") - endif() -else() - set(USE_SCALAR_8X32 1) - set(USE_FIELD_10X26 1) -endif() - -# Executable internal to secp256k1 need to have the HAVE_CONFIG_H define set. -# For convenience, we wrap this into a function. -function(link_secp256k1_internal NAME) - target_link_libraries(${NAME} secp256k1) - target_compile_definitions(${NAME} PRIVATE HAVE_CONFIG_H SECP256K1_BUILD) -endfunction(link_secp256k1_internal) - -# Phony target to build benchmarks -add_custom_target(bench-secp256k1) - -function(add_secp256k1_bench NAME) - add_executable(${NAME} EXCLUDE_FROM_ALL ${ARGN}) - link_secp256k1_internal(${NAME}) - add_dependencies(bench-secp256k1 ${NAME}) -endfunction(add_secp256k1_bench) - -# ECDH module -option(SECP256K1_ENABLE_MODULE_ECDH "Build libsecp256k1's ECDH module" OFF) -if(SECP256K1_ENABLE_MODULE_ECDH) - set(ENABLE_MODULE_ECDH 1) - add_secp256k1_bench(bench_ecdh src/bench_ecdh.c) -endif() - -# MultiSet module -#option(SECP256K1_ENABLE_MODULE_MULTISET "Build libsecp256k1's MULTISET module" ON) -#if(SECP256K1_ENABLE_MODULE_MULTISET) -# set(ENABLE_MODULE_MULTISET 1) -# add_secp256k1_bench(bench_multiset src/bench_multiset.c) -#endif() - -# Recovery module -option(SECP256K1_ENABLE_MODULE_RECOVERY "Build libsecp256k1's recovery module" ON) -if(SECP256K1_ENABLE_MODULE_RECOVERY) - set(ENABLE_MODULE_RECOVERY 1) - add_secp256k1_bench(bench_recover src/bench_recover.c) -endif() - -# Schnorr module -option(SECP256K1_ENABLE_MODULE_SCHNORR "Build libsecp256k1's Schnorr module" ON) -if(SECP256K1_ENABLE_MODULE_SCHNORR) - set(ENABLE_MODULE_SCHNORR 1) -endif() - -# Static precomputation for eliptic curve mutliplication -option(SECP256K1_ECMULT_STATIC_PRECOMPUTATION "Precompute libsecp256k1's eliptic curve mutliplication tables" ON) -if(SECP256K1_ECMULT_STATIC_PRECOMPUTATION) - set(USE_ECMULT_STATIC_PRECOMPUTATION 1) - - include(NativeExecutable) - add_native_executable(gen_context src/gen_context.c) - - add_custom_command( - OUTPUT ecmult_static_context.h - COMMAND gen_context - ) - - target_sources(secp256k1 PRIVATE ecmult_static_context.h) -endif() - -# Generate the config -configure_file(src/libsecp256k1-config.h.cmake.in src/libsecp256k1-config.h ESCAPE_QUOTES) -target_compile_definitions(secp256k1 PRIVATE HAVE_CONFIG_H SECP256K1_BUILD) - -# Tests -option(SECP256K1_BUILD_TEST "Build secp256k1's unit tests" ON) -if(SECP256K1_BUILD_TEST) - include(TestSuite) - create_test_suite(secp256k1) - - function(create_secp256k1_test NAME FILES) - add_test_to_suite(secp256k1 ${NAME} EXCLUDE_FROM_ALL ${FILES}) - link_secp256k1_internal(${NAME}) - endfunction() - - create_secp256k1_test(tests src/tests.c) - target_compile_definitions(tests PRIVATE VERIFY) - - create_secp256k1_test(exhaustive_tests src/tests_exhaustive.c) - # This should not be enabled at the same time as coverage is. - # TODO: support coverage. - target_compile_definitions(exhaustive_tests PRIVATE VERIFY) -endif(SECP256K1_BUILD_TEST) - -# Benchmarks -add_secp256k1_bench(bench_verify src/bench_verify.c) -add_secp256k1_bench(bench_sign src/bench_sign.c) -add_secp256k1_bench(bench_internal src/bench_internal.c) diff --git a/src/secp256k1/COPYING b/src/secp256k1/COPYING deleted file mode 100644 index 4522a5990e..0000000000 --- a/src/secp256k1/COPYING +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2013 Pieter Wuille - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am deleted file mode 100644 index ea1301bfb0..0000000000 --- a/src/secp256k1/Makefile.am +++ /dev/null @@ -1,181 +0,0 @@ -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 -noinst_HEADERS += src/scalar_4x64.h -noinst_HEADERS += src/scalar_8x32.h -noinst_HEADERS += src/scalar_low.h -noinst_HEADERS += src/scalar_impl.h -noinst_HEADERS += src/scalar_4x64_impl.h -noinst_HEADERS += src/scalar_8x32_impl.h -noinst_HEADERS += src/scalar_low_impl.h -noinst_HEADERS += src/group.h -noinst_HEADERS += src/group_impl.h -noinst_HEADERS += src/num_gmp.h -noinst_HEADERS += src/num_gmp_impl.h -noinst_HEADERS += src/ecdsa.h -noinst_HEADERS += src/ecdsa_impl.h -noinst_HEADERS += src/eckey.h -noinst_HEADERS += src/eckey_impl.h -noinst_HEADERS += src/ecmult.h -noinst_HEADERS += src/ecmult_impl.h -noinst_HEADERS += src/ecmult_const.h -noinst_HEADERS += src/ecmult_const_impl.h -noinst_HEADERS += src/ecmult_gen.h -noinst_HEADERS += src/ecmult_gen_impl.h -noinst_HEADERS += src/num.h -noinst_HEADERS += src/num_impl.h -noinst_HEADERS += src/field_10x26.h -noinst_HEADERS += src/field_10x26_impl.h -noinst_HEADERS += src/field_5x52.h -noinst_HEADERS += src/field_5x52_impl.h -noinst_HEADERS += src/field_5x52_int128_impl.h -noinst_HEADERS += src/field_5x52_asm_impl.h -noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h -noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h -noinst_HEADERS += src/util.h -noinst_HEADERS += src/testrand.h -noinst_HEADERS += src/testrand_impl.h -noinst_HEADERS += src/hash.h -noinst_HEADERS += src/hash_impl.h -noinst_HEADERS += src/field.h -noinst_HEADERS += src/field_impl.h -noinst_HEADERS += src/bench.h -noinst_HEADERS += contrib/lax_der_parsing.h -noinst_HEADERS += contrib/lax_der_parsing.c -noinst_HEADERS += contrib/lax_der_privatekey_parsing.h -noinst_HEADERS += contrib/lax_der_privatekey_parsing.c - -if USE_EXTERNAL_ASM -COMMON_LIB = libsecp256k1_common.la -noinst_LTLIBRARIES = $(COMMON_LIB) -else -COMMON_LIB = -endif - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libsecp256k1.pc - -if USE_EXTERNAL_ASM -if USE_ASM_ARM -libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s -endif -endif - -libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = -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) $(SECP_TEST_LIBS) $(COMMON_LIB) -bench_sign_SOURCES = src/bench_sign.c -bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) -bench_internal_SOURCES = src/bench_internal.c -bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) -bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES) -endif - -TESTS = -if USE_TESTS -noinst_PROGRAMS += tests -tests_SOURCES = src/tests.c -tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) -if !ENABLE_COVERAGE -tests_CPPFLAGS += -DVERIFY -endif -tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) -tests_LDFLAGS = -static -TESTS += tests -endif - -if USE_EXHAUSTIVE_TESTS -noinst_PROGRAMS += exhaustive_tests -exhaustive_tests_SOURCES = src/tests_exhaustive.c -exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES) -if !ENABLE_COVERAGE -exhaustive_tests_CPPFLAGS += -DVERIFY -endif -exhaustive_tests_LDADD = $(SECP_LIBS) -exhaustive_tests_LDFLAGS = -static -TESTS += exhaustive_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 - -gen_context_OBJECTS = gen_context.o -gen_context_BIN = gen_context$(BUILD_EXEEXT) -gen_%.o: src/gen_%.c - $(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@ - -$(gen_context_BIN): $(gen_context_OBJECTS) - $(CC_FOR_BUILD) $^ -o $@ - -$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h -$(tests_OBJECTS): src/ecmult_static_context.h -$(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 $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java -endif - -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 -endif - -if ENABLE_MODULE_RECOVERY -include src/modules/recovery/Makefile.am.include -endif - -if ENABLE_MODULE_SCHNORR -include src/modules/schnorr/Makefile.am.include -endif diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md deleted file mode 100644 index 8cd344ea81..0000000000 --- a/src/secp256k1/README.md +++ /dev/null @@ -1,61 +0,0 @@ -libsecp256k1 -============ - -[![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. - -This library is a work in progress and is being used to research best practices. Use at your own risk. - -Features: -* secp256k1 ECDSA signing/verification and key generation. -* Adding/multiplying private/public keys. -* Serialization/parsing of private keys, public keys, signatures. -* Constant time, constant memory access signing and pubkey generation. -* Derandomized DSA (via RFC6979 or with a caller provided function.) -* Very efficient implementation. - -Implementation details ----------------------- - -* General - * No runtime heap allocation. - * Extensive testing infrastructure. - * Structured to facilitate review and analysis. - * Intended to be portable to any system with a C89 compiler and uint64_t support. - * Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.") -* Field operations - * Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1). - * Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys). - * Using 10 26-bit limbs. - * Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman). -* Scalar operations - * Optimized implementation without data-dependent branches of arithmetic modulo the curve's order. - * Using 4 64-bit limbs (relying on __int128 support in the compiler). - * Using 8 32-bit limbs. -* Group operations - * Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7). - * Use addition between points in Jacobian and affine coordinates where possible. - * Use a unified addition/doubling formula where necessary to avoid data-dependent branches. - * Point/x comparison without a field inversion by comparison in the Jacobian coordinate space. -* Point multiplication for verification (a*P + b*G). - * Use wNAF notation for point multiplicands. - * Use a much larger window for multiples of G, using precomputed multiples. - * Use Shamir's trick to do the multiplication with the public key and the generator simultaneously. - * Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. -* Point multiplication for signing - * Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions. - * Access the table with branch-free conditional moves so memory access is uniform. - * No data-dependent branches - * The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally. - -Build steps ------------ - -libsecp256k1 is built using autotools: - - $ ./autogen.sh - $ ./configure - $ make - $ ./tests - $ sudo make install # optional diff --git a/src/secp256k1/TODO b/src/secp256k1/TODO deleted file mode 100644 index a300e1c5eb..0000000000 --- a/src/secp256k1/TODO +++ /dev/null @@ -1,3 +0,0 @@ -* Unit tests for fieldelem/groupelem, including ones intended to - trigger fieldelem's boundary cases. -* Complete constant-time operations for signing/keygen diff --git a/src/secp256k1/autogen.sh b/src/secp256k1/autogen.sh deleted file mode 100755 index 65286b9353..0000000000 --- a/src/secp256k1/autogen.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -set -e -autoreconf -if --warnings=all diff --git a/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 b/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 deleted file mode 100644 index 1fc3627614..0000000000 --- a/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 +++ /dev/null @@ -1,140 +0,0 @@ -# =========================================================================== -# 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 -# -# 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 -# Follows symbolic links on , -# 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 diff --git a/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 b/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 deleted file mode 100644 index 77fd346a79..0000000000 --- a/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 +++ /dev/null @@ -1,125 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_CC_FOR_BUILD -# -# DESCRIPTION -# -# This macro searches for a C compiler that generates native executables, -# that is a C compiler that surely is not a cross-compiler. This can be -# useful if you have to generate source code at compile-time like for -# example GCC does. -# -# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything -# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD). -# The value of these variables can be overridden by the user by specifying -# a compiler with an environment variable (like you do for standard CC). -# -# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object -# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if -# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are -# substituted in the Makefile. -# -# LICENSE -# -# Copyright (c) 2008 Paolo Bonzini -# -# 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 8 - -AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD]) -AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl -AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_PROG_CPP])dnl -AC_REQUIRE([AC_EXEEXT])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl - -dnl Use the standard macros, but make them use other variable names -dnl -pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl -pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl -pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl -pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl -pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl -pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl -pushdef([ac_cv_objext], ac_cv_build_objext)dnl -pushdef([ac_exeext], ac_build_exeext)dnl -pushdef([ac_objext], ac_build_objext)dnl -pushdef([CC], CC_FOR_BUILD)dnl -pushdef([CPP], CPP_FOR_BUILD)dnl -pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl -pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl -pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl -pushdef([host], build)dnl -pushdef([host_alias], build_alias)dnl -pushdef([host_cpu], build_cpu)dnl -pushdef([host_vendor], build_vendor)dnl -pushdef([host_os], build_os)dnl -pushdef([ac_cv_host], ac_cv_build)dnl -pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl -pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl -pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl -pushdef([ac_cv_host_os], ac_cv_build_os)dnl -pushdef([ac_cpp], ac_build_cpp)dnl -pushdef([ac_compile], ac_build_compile)dnl -pushdef([ac_link], ac_build_link)dnl - -save_cross_compiling=$cross_compiling -save_ac_tool_prefix=$ac_tool_prefix -cross_compiling=no -ac_tool_prefix= - -AC_PROG_CC -AC_PROG_CPP -AC_EXEEXT - -ac_tool_prefix=$save_ac_tool_prefix -cross_compiling=$save_cross_compiling - -dnl Restore the old definitions -dnl -popdef([ac_link])dnl -popdef([ac_compile])dnl -popdef([ac_cpp])dnl -popdef([ac_cv_host_os])dnl -popdef([ac_cv_host_vendor])dnl -popdef([ac_cv_host_cpu])dnl -popdef([ac_cv_host_alias])dnl -popdef([ac_cv_host])dnl -popdef([host_os])dnl -popdef([host_vendor])dnl -popdef([host_cpu])dnl -popdef([host_alias])dnl -popdef([host])dnl -popdef([LDFLAGS])dnl -popdef([CPPFLAGS])dnl -popdef([CFLAGS])dnl -popdef([CPP])dnl -popdef([CC])dnl -popdef([ac_objext])dnl -popdef([ac_exeext])dnl -popdef([ac_cv_objext])dnl -popdef([ac_cv_exeext])dnl -popdef([ac_cv_prog_cc_g])dnl -popdef([ac_cv_prog_cc_cross])dnl -popdef([ac_cv_prog_cc_works])dnl -popdef([ac_cv_prog_gcc])dnl -popdef([ac_cv_prog_CPP])dnl - -dnl Finally, set Makefile variables -dnl -BUILD_EXEEXT=$ac_build_exeext -BUILD_OBJEXT=$ac_build_objext -AC_SUBST(BUILD_EXEEXT)dnl -AC_SUBST(BUILD_OBJEXT)dnl -AC_SUBST([CFLAGS_FOR_BUILD])dnl -AC_SUBST([CPPFLAGS_FOR_BUILD])dnl -AC_SUBST([LDFLAGS_FOR_BUILD])dnl -]) diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 deleted file mode 100644 index b74acb8c13..0000000000 --- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 +++ /dev/null @@ -1,69 +0,0 @@ -dnl libsecp25k1 helper checks -AC_DEFUN([SECP_INT128_CHECK],[ -has_int128=$ac_cv_type___int128 -]) - -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 ]],[[ - uint64_t a = 11, tmp; - __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]) -]) - -dnl -AC_DEFUN([SECP_OPENSSL_CHECK],[ - has_libcrypto=no - m4_ifdef([PKG_CHECK_MODULES],[ - PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no]) - if test x"$has_libcrypto" = x"yes"; then - TEMP_LIBS="$LIBS" - LIBS="$LIBS $CRYPTO_LIBS" - AC_CHECK_LIB(crypto, main,[AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])],[has_libcrypto=no]) - LIBS="$TEMP_LIBS" - fi - ]) - if test x$has_libcrypto = xno; then - AC_CHECK_HEADER(openssl/crypto.h,[ - AC_CHECK_LIB(crypto, main,[ - has_libcrypto=yes - CRYPTO_LIBS=-lcrypto - AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed]) - ]) - ]) - LIBS= - fi -if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then - AC_MSG_CHECKING(for EC functions in libcrypto) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include - #include - #include ]],[[ - EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1); - ECDSA_sign(0, NULL, 0, NULL, NULL, eckey); - ECDSA_verify(0, NULL, 0, NULL, 0, eckey); - EC_KEY_free(eckey); - ECDSA_SIG *sig_openssl; - sig_openssl = ECDSA_SIG_new(); - (void)sig_openssl->r; - ECDSA_SIG_free(sig_openssl); - ]])],[has_openssl_ec=yes],[has_openssl_ec=no]) - AC_MSG_RESULT([$has_openssl_ec]) -fi -]) - -dnl -AC_DEFUN([SECP_GMP_CHECK],[ -if test x"$has_gmp" != x"yes"; then - CPPFLAGS_TEMP="$CPPFLAGS" - CPPFLAGS="$GMP_CPPFLAGS $CPPFLAGS" - LIBS_TEMP="$LIBS" - LIBS="$GMP_LIBS $LIBS" - AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS="$GMP_LIBS -lgmp"; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])]) - CPPFLAGS="$CPPFLAGS_TEMP" - LIBS="$LIBS_TEMP" -fi -]) diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac deleted file mode 100644 index 02c532a56a..0000000000 --- a/src/secp256k1/configure.ac +++ /dev/null @@ -1,504 +0,0 @@ -AC_PREREQ([2.60]) -AC_INIT([libsecp256k1],[0.1]) -AC_CONFIG_AUX_DIR([build-aux]) -AC_CONFIG_MACRO_DIR([build-aux/m4]) -AC_CANONICAL_HOST -AH_TOP([#ifndef LIBSECP256K1_CONFIG_H]) -AH_TOP([#define LIBSECP256K1_CONFIG_H]) -AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/]) -AM_INIT_AUTOMAKE([foreign subdir-objects]) -LT_INIT - -dnl make the compilation flags quiet unless V=1 is used -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -PKG_PROG_PKG_CONFIG - -AC_PATH_TOOL(AR, ar) -AC_PATH_TOOL(RANLIB, ranlib) -AC_PATH_TOOL(STRIP, strip) -AX_PROG_CC_FOR_BUILD - -if test "x$CFLAGS" = "x"; then - CFLAGS="-g" -fi - -AM_PROG_CC_C_O - -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*) - if test x$cross_compiling != xyes; then - AC_PATH_PROG([BREW],brew,) - if test x$BREW != x; then - dnl These Homebrew packages may be keg-only, meaning that they won't be found - dnl in expected paths because they may conflict with system files. Ask - dnl Homebrew where each one is located, then adjust paths accordingly. - - openssl_prefix=`$BREW --prefix openssl 2>/dev/null` - gmp_prefix=`$BREW --prefix gmp 2>/dev/null` - if test x$openssl_prefix != x; then - PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH" - export PKG_CONFIG_PATH - fi - if test x$gmp_prefix != x; then - GMP_CPPFLAGS="-I$gmp_prefix/include" - GMP_LIBS="-L$gmp_prefix/lib" - fi - else - AC_PATH_PROG([PORT],port,) - dnl if homebrew isn't installed and macports is, add the macports default paths - dnl as a last resort. - if test x$PORT != x; then - CPPFLAGS="$CPPFLAGS -isystem /opt/local/include" - LDFLAGS="$LDFLAGS -L/opt/local/lib" - fi - fi - fi - ;; -esac - -CFLAGS="$CFLAGS -W" - -warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings" -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS $warn_CFLAGS" -AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}]) -AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], - [ AC_MSG_RESULT([yes]) ], - [ AC_MSG_RESULT([no]) - CFLAGS="$saved_CFLAGS" - ]) - -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS -fvisibility=hidden" -AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden]) -AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], - [ AC_MSG_RESULT([yes]) ], - [ AC_MSG_RESULT([no]) - CFLAGS="$saved_CFLAGS" - ]) - -AC_ARG_ENABLE(benchmark, - AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]), - [use_benchmark=$enableval], - [use_benchmark=no]) - -AC_ARG_ENABLE(coverage, - AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]), - [enable_coverage=$enableval], - [enable_coverage=no]) - -AC_ARG_ENABLE(tests, - AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), - [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(exhaustive_tests, - AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]), - [use_exhaustive_tests=$enableval], - [use_exhaustive_tests=yes]) - -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=auto]) - -AC_ARG_ENABLE(module_ecdh, - AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]), - [enable_module_ecdh=$enableval], - [enable_module_ecdh=no]) - -AC_ARG_ENABLE(module_recovery, - AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]), - [enable_module_recovery=$enableval], - [enable_module_recovery=yes]) - -AC_ARG_ENABLE(module_schnorr, - AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signatures module (default is yes)]), - [enable_module_schnorr=$enableval], - [enable_module_schnorr=yes]) - -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]) - -AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto], -[Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto]) - -AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], -[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto]) - -AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto] -[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto]) - -AC_CHECK_TYPES([__int128]) - -AC_MSG_CHECKING([for __builtin_expect]) -AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])], - [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ], - [ AC_MSG_RESULT([no]) - ]) - -if test x"$enable_coverage" = x"yes"; then - AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code]) - CFLAGS="$CFLAGS -O0 --coverage" - LDFLAGS="--coverage" -else - CFLAGS="$CFLAGS -O3" -fi - -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 - set_asm=x86_64 - fi - if test x"$set_asm" = x; then - set_asm=no - fi -else - set_asm=$req_asm - case $set_asm in - x86_64) - SECP_64BIT_ASM_CHECK - if test x"$has_64bit_asm" != x"yes"; then - AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) - fi - ;; - arm) - ;; - no) - ;; - *) - AC_MSG_ERROR([invalid assembly optimization selection]) - ;; - esac -fi - -if test x"$req_field" = x"auto"; then - if test x"set_asm" = x"x86_64"; then - set_field=64bit - fi - if test x"$set_field" = x; then - SECP_INT128_CHECK - if test x"$has_int128" = x"yes"; then - set_field=64bit - fi - fi - if test x"$set_field" = x; then - set_field=32bit - fi -else - set_field=$req_field - case $set_field in - 64bit) - if test x"$set_asm" != x"x86_64"; then - SECP_INT128_CHECK - if test x"$has_int128" != x"yes"; then - AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available]) - fi - fi - ;; - 32bit) - ;; - *) - AC_MSG_ERROR([invalid field implementation selection]) - ;; - esac -fi - -if test x"$req_scalar" = x"auto"; then - SECP_INT128_CHECK - if test x"$has_int128" = x"yes"; then - set_scalar=64bit - fi - if test x"$set_scalar" = x; then - set_scalar=32bit - fi -else - set_scalar=$req_scalar - case $set_scalar in - 64bit) - SECP_INT128_CHECK - if test x"$has_int128" != x"yes"; then - AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available]) - fi - ;; - 32bit) - ;; - *) - AC_MSG_ERROR([invalid scalar implementation selected]) - ;; - esac -fi - -if test x"$req_bignum" = x"auto"; then - SECP_GMP_CHECK - if test x"$has_gmp" = x"yes"; then - set_bignum=gmp - fi - - if test x"$set_bignum" = x; then - set_bignum=no - fi -else - set_bignum=$req_bignum - case $set_bignum in - gmp) - SECP_GMP_CHECK - if test x"$has_gmp" != x"yes"; then - AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available]) - fi - ;; - no) - ;; - *) - AC_MSG_ERROR([invalid bignum implementation selection]) - ;; - esac -fi - -# select assembly optimization -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) - ;; -*) - AC_MSG_ERROR([invalid assembly optimizations]) - ;; -esac - -# select field implementation -case $set_field in -64bit) - AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation]) - ;; -32bit) - AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation]) - ;; -*) - AC_MSG_ERROR([invalid field implementation]) - ;; -esac - -# select bignum implementation -case $set_bignum in -gmp) - AC_DEFINE(HAVE_LIBGMP, 1, [Define this symbol if libgmp is installed]) - AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation for num]) - AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation]) - AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation]) - ;; -no) - AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation]) - AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation]) - AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation]) - ;; -*) - AC_MSG_ERROR([invalid bignum implementation]) - ;; -esac - -#select scalar implementation -case $set_scalar in -64bit) - AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation]) - ;; -32bit) - AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation]) - ;; -*) - AC_MSG_ERROR([invalid scalar implementation]) - ;; -esac - -if test x"$use_tests" = x"yes"; then - SECP_OPENSSL_CHECK - if test x"$has_openssl_ec" = x"yes"; then - if test x"$enable_openssl_tests" != x"no"; then - AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) - SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS" - SECP_TEST_LIBS="$CRYPTO_LIBS" - - case $host in - *mingw*) - SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32" - ;; - esac - fi - else - if test x"$enable_openssl_tests" = x"yes"; then - AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available]) - fi - fi -else - if test x"$enable_openssl_tests" = x"yes"; then - AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled]) - fi -fi - -if test x"$use_jni" != x"no"; then - AX_JNI_INCLUDE_DIR - have_jni_dependencies=yes - if test x"$enable_module_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 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 - -if test x"$set_bignum" = x"gmp"; then - SECP_LIBS="$SECP_LIBS $GMP_LIBS" - SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS" -fi - -if test x"$use_endomorphism" = x"yes"; then - AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) -fi - -if test x"$set_precomp" = x"yes"; then - AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table]) -fi - -if test x"$enable_module_ecdh" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module]) -fi - -if test x"$enable_module_recovery" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) -fi - -if test x"$enable_module_schnorr" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module]) -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 for coverage analysis: $enable_coverage]) -AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) -AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery]) -AC_MSG_NOTICE([Building Schnorr signature module: $enable_module_schnorr]) -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([******]) -else - 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) -AC_SUBST(SECP_TEST_INCLUDES) -AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) -AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) -AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"]) -AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) -AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = 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" -unset PKG_CONFIG_PATH -PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP" - -AC_OUTPUT diff --git a/src/secp256k1/contrib/lax_der_parsing.c b/src/secp256k1/contrib/lax_der_parsing.c deleted file mode 100644 index 5b141a9948..0000000000 --- a/src/secp256k1/contrib/lax_der_parsing.c +++ /dev/null @@ -1,150 +0,0 @@ -/********************************************************************** - * Copyright (c) 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include -#include - -#include "lax_der_parsing.h" - -int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { - size_t rpos, rlen, spos, slen; - size_t pos = 0; - size_t lenbyte; - unsigned char tmpsig[64] = {0}; - int overflow = 0; - - /* Hack to initialize sig with a correctly-parsed but invalid signature. */ - secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); - - /* Sequence tag byte */ - if (pos == inputlen || input[pos] != 0x30) { - return 0; - } - pos++; - - /* Sequence length bytes */ - if (pos == inputlen) { - return 0; - } - lenbyte = input[pos++]; - if (lenbyte & 0x80) { - lenbyte -= 0x80; - if (pos + lenbyte > inputlen) { - return 0; - } - pos += lenbyte; - } - - /* Integer tag byte for R */ - if (pos == inputlen || input[pos] != 0x02) { - return 0; - } - pos++; - - /* Integer length for R */ - if (pos == inputlen) { - return 0; - } - lenbyte = input[pos++]; - if (lenbyte & 0x80) { - lenbyte -= 0x80; - if (pos + lenbyte > inputlen) { - return 0; - } - while (lenbyte > 0 && input[pos] == 0) { - pos++; - lenbyte--; - } - if (lenbyte >= sizeof(size_t)) { - return 0; - } - rlen = 0; - while (lenbyte > 0) { - rlen = (rlen << 8) + input[pos]; - pos++; - lenbyte--; - } - } else { - rlen = lenbyte; - } - if (rlen > inputlen - pos) { - return 0; - } - rpos = pos; - pos += rlen; - - /* Integer tag byte for S */ - if (pos == inputlen || input[pos] != 0x02) { - return 0; - } - pos++; - - /* Integer length for S */ - if (pos == inputlen) { - return 0; - } - lenbyte = input[pos++]; - if (lenbyte & 0x80) { - lenbyte -= 0x80; - if (pos + lenbyte > inputlen) { - return 0; - } - while (lenbyte > 0 && input[pos] == 0) { - pos++; - lenbyte--; - } - if (lenbyte >= sizeof(size_t)) { - return 0; - } - slen = 0; - while (lenbyte > 0) { - slen = (slen << 8) + input[pos]; - pos++; - lenbyte--; - } - } else { - slen = lenbyte; - } - if (slen > inputlen - pos) { - return 0; - } - spos = pos; - pos += slen; - - /* Ignore leading zeroes in R */ - while (rlen > 0 && input[rpos] == 0) { - rlen--; - rpos++; - } - /* Copy R value */ - if (rlen > 32) { - overflow = 1; - } else { - memcpy(tmpsig + 32 - rlen, input + rpos, rlen); - } - - /* Ignore leading zeroes in S */ - while (slen > 0 && input[spos] == 0) { - slen--; - spos++; - } - /* Copy S value */ - if (slen > 32) { - overflow = 1; - } else { - memcpy(tmpsig + 64 - slen, input + spos, slen); - } - - if (!overflow) { - overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); - } - if (overflow) { - memset(tmpsig, 0, 64); - secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); - } - return 1; -} - diff --git a/src/secp256k1/contrib/lax_der_parsing.h b/src/secp256k1/contrib/lax_der_parsing.h deleted file mode 100644 index 7eaf63bf6a..0000000000 --- a/src/secp256k1/contrib/lax_der_parsing.h +++ /dev/null @@ -1,91 +0,0 @@ -/********************************************************************** - * Copyright (c) 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -/**** - * Please do not link this file directly. It is not part of the libsecp256k1 - * project and does not promise any stability in its API, functionality or - * presence. Projects which use this code should instead copy this header - * and its accompanying .c file directly into their codebase. - ****/ - -/* This file defines a function that parses DER with various errors and - * violations. This is not a part of the library itself, because the allowed - * violations are chosen arbitrarily and do not follow or establish any - * standard. - * - * In many places it matters that different implementations do not only accept - * the same set of valid signatures, but also reject the same set of signatures. - * The only means to accomplish that is by strictly obeying a standard, and not - * accepting anything else. - * - * Nonetheless, sometimes there is a need for compatibility with systems that - * use signatures which do not strictly obey DER. The snippet below shows how - * certain violations are easily supported. You may need to adapt it. - * - * Do not use this for new systems. Use well-defined DER or compact signatures - * instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and - * secp256k1_ecdsa_signature_parse_compact). - * - * The supported violations are: - * - All numbers are parsed as nonnegative integers, even though X.609-0207 - * section 8.3.3 specifies that integers are always encoded as two's - * complement. - * - Integers can have length 0, even though section 8.3.1 says they can't. - * - Integers with overly long padding are accepted, violation section - * 8.3.2. - * - 127-byte long length descriptors are accepted, even though section - * 8.1.3.5.c says that they are not. - * - Trailing garbage data inside or after the signature is ignored. - * - The length descriptor of the sequence is ignored. - * - * Compared to for example OpenSSL, many violations are NOT supported: - * - Using overly long tag descriptors for the sequence or integers inside, - * violating section 8.1.2.2. - * - Encoding primitive integers as constructed values, violating section - * 8.3.1. - */ - -#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H -#define SECP256K1_CONTRIB_LAX_DER_PARSING_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** Parse a signature in "lax DER" format - * - * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input: a pointer to the signature to be parsed - * inputlen: the length of the array pointed to be input - * - * This function will accept any valid DER encoded signature, even if the - * encoded numbers are out of range. In addition, it will accept signatures - * which violate the DER spec in various ways. Its purpose is to allow - * validation of the Bitcoin blockchain, which includes non-DER signatures - * from before the network rules were updated to enforce DER. Note that - * the set of supported violations is a strict subset of what OpenSSL will - * accept. - * - * After the call, sig will always be initialized. If parsing failed or the - * encoded numbers are out of range, signature validation with it is - * guaranteed to fail for every message and public key. - */ -int ecdsa_signature_parse_der_lax( - const secp256k1_context* ctx, - secp256k1_ecdsa_signature* sig, - const unsigned char *input, - size_t inputlen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_CONTRIB_LAX_DER_PARSING_H */ diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.c b/src/secp256k1/contrib/lax_der_privatekey_parsing.c deleted file mode 100644 index c2e63b4b8d..0000000000 --- a/src/secp256k1/contrib/lax_der_privatekey_parsing.c +++ /dev/null @@ -1,113 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014, 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include -#include - -#include "lax_der_privatekey_parsing.h" - -int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) { - const unsigned char *end = privkey + privkeylen; - int lenb = 0; - int len = 0; - memset(out32, 0, 32); - /* sequence header */ - if (end < privkey+1 || *privkey != 0x30) { - return 0; - } - privkey++; - /* sequence length constructor */ - if (end < privkey+1 || !(*privkey & 0x80)) { - return 0; - } - lenb = *privkey & ~0x80; privkey++; - if (lenb < 1 || lenb > 2) { - return 0; - } - if (end < privkey+lenb) { - return 0; - } - /* sequence length */ - len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); - privkey += lenb; - if (end < privkey+len) { - return 0; - } - /* sequence element 0: version number (=1) */ - if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { - return 0; - } - privkey += 3; - /* sequence element 1: octet string, up to 32 bytes */ - if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { - return 0; - } - memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); - if (!secp256k1_ec_seckey_verify(ctx, out32)) { - memset(out32, 0, 32); - return 0; - } - return 1; -} - -int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { - secp256k1_pubkey pubkey; - size_t pubkeylen = 0; - if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { - *privkeylen = 0; - return 0; - } - if (compressed) { - static const unsigned char begin[] = { - 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 - }; - static const unsigned char middle[] = { - 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, - 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,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,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, - 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, - 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, - 0x17,0x98,0x02,0x21,0x00,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,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 - }; - unsigned char *ptr = privkey; - memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); - memcpy(ptr, key32, 32); ptr += 32; - memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - pubkeylen = 33; - secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); - ptr += pubkeylen; - *privkeylen = ptr - privkey; - } else { - static const unsigned char begin[] = { - 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 - }; - static const unsigned char middle[] = { - 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, - 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,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,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, - 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, - 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, - 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, - 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, - 0xD4,0xB8,0x02,0x21,0x00,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,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 - }; - unsigned char *ptr = privkey; - memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); - memcpy(ptr, key32, 32); ptr += 32; - memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - pubkeylen = 65; - secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); - ptr += pubkeylen; - *privkeylen = ptr - privkey; - } - return 1; -} diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.h b/src/secp256k1/contrib/lax_der_privatekey_parsing.h deleted file mode 100644 index fece261fb9..0000000000 --- a/src/secp256k1/contrib/lax_der_privatekey_parsing.h +++ /dev/null @@ -1,90 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014, 2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -/**** - * Please do not link this file directly. It is not part of the libsecp256k1 - * project and does not promise any stability in its API, functionality or - * presence. Projects which use this code should instead copy this header - * and its accompanying .c file directly into their codebase. - ****/ - -/* This file contains code snippets that parse DER private keys with - * various errors and violations. This is not a part of the library - * itself, because the allowed violations are chosen arbitrarily and - * do not follow or establish any standard. - * - * It also contains code to serialize private keys in a compatible - * manner. - * - * These functions are meant for compatibility with applications - * that require BER encoded keys. When working with secp256k1-specific - * code, the simple 32-byte private keys normally used by the - * library are sufficient. - */ - -#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H -#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** Export a private key in DER format. - * - * Returns: 1 if the private key was valid. - * Args: ctx: pointer to a context object, initialized for signing (cannot - * be NULL) - * Out: privkey: pointer to an array for storing the private key in BER. - * Should have space for 279 bytes, and cannot be NULL. - * privkeylen: Pointer to an int where the length of the private key in - * privkey will be stored. - * In: seckey: pointer to a 32-byte secret key to export. - * compressed: 1 if the key should be exported in - * compressed format, 0 otherwise - * - * This function is purely meant for compatibility with applications that - * require BER encoded keys. When working with secp256k1-specific code, the - * simple 32-byte private keys are sufficient. - * - * Note that this function does not guarantee correct DER output. It is - * guaranteed to be parsable by secp256k1_ec_privkey_import_der - */ -SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der( - const secp256k1_context* ctx, - unsigned char *privkey, - size_t *privkeylen, - const unsigned char *seckey, - int compressed -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Import a private key in DER format. - * Returns: 1 if a private key was extracted. - * Args: ctx: pointer to a context object (cannot be NULL). - * Out: seckey: pointer to a 32-byte array for storing the private key. - * (cannot be NULL). - * In: privkey: pointer to a private key in DER format (cannot be NULL). - * privkeylen: length of the DER private key pointed to be privkey. - * - * This function will accept more than just strict DER, and even allow some BER - * violations. The public key stored inside the DER-encoded private key is not - * verified for correctness, nor are the curve parameters. Use this function - * only if you know in advance it is supposed to contain a secp256k1 private - * key. - */ -SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der( - const secp256k1_context* ctx, - unsigned char *seckey, - const unsigned char *privkey, - size_t privkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_CONTRIB_BER_PRIVATEKEY_H */ diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h deleted file mode 100644 index 3e9c098d19..0000000000 --- a/src/secp256k1/include/secp256k1.h +++ /dev/null @@ -1,621 +0,0 @@ -#ifndef SECP256K1_H -#define SECP256K1_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* These rules specify the order of arguments in API calls: - * - * 1. Context pointers go first, followed by output arguments, combined - * output/input arguments, and finally input-only arguments. - * 2. Array lengths always immediately the follow the argument whose length - * they describe, even if this violates rule 1. - * 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated - * later go first. This means: signatures, public nonces, private nonces, - * messages, public keys, secret keys, tweaks. - * 4. Arguments that are not data pointers go last, from more complex to less - * complex: function pointers, algorithm names, messages, void pointers, - * counts, flags, booleans. - * 5. Opaque data pointers follow the function pointer they are to be passed to. - */ - -/** Opaque data structure that holds context information (precomputed tables etc.). - * - * The purpose of context structures is to cache large precomputed data tables - * that are expensive to construct, and also to maintain the randomization data - * for blinding. - * - * Do not create a new context object for each operation, as construction is - * far slower than all other API calls (~100 times slower than an ECDSA - * verification). - * - * A constructed context can safely be used from multiple threads - * simultaneously, but API call that take a non-const pointer to a context - * need exclusive access to it. In particular this is the case for - * secp256k1_context_destroy and secp256k1_context_randomize. - * - * Regarding randomization, either do it once at creation time (in which case - * you do not need any locking for the other calls), or use a read-write lock. - */ -typedef struct secp256k1_context_struct secp256k1_context; - -/** Opaque data structure that holds a parsed and valid public key. - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. It is - * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage, transmission, or - * comparison, use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. - */ -typedef struct { - unsigned char data[64]; -} secp256k1_pubkey; - -/** Opaque data structured that holds a parsed ECDSA signature. - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. It is - * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage, transmission, or - * comparison, use the secp256k1_ecdsa_signature_serialize_* and - * secp256k1_ecdsa_signature_parse_* functions. - */ -typedef struct { - unsigned char data[64]; -} secp256k1_ecdsa_signature; - -/** A pointer to a function to deterministically generate a nonce. - * - * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. - * Out: nonce32: pointer to a 32-byte array to be filled by the function. - * In: msg32: the 32-byte message hash being verified (will not be NULL) - * key32: pointer to a 32-byte secret key (will not be NULL) - * algo16: pointer to a 16-byte array describing the signature - * algorithm (will be NULL for ECDSA for compatibility). - * data: Arbitrary data pointer that is passed through. - * attempt: how many iterations we have tried to find a nonce. - * This will almost always be 0, but different attempt values - * are required to result in a different nonce. - * - * Except for test cases, this function should compute some cryptographic hash of - * the message, the algorithm, the key and the attempt. - */ -typedef int (*secp256k1_nonce_function)( - unsigned char *nonce32, - const unsigned char *msg32, - const unsigned char *key32, - const unsigned char *algo16, - void *data, - unsigned int attempt -); - -# if !defined(SECP256K1_GNUC_PREREQ) -# if defined(__GNUC__)&&defined(__GNUC_MINOR__) -# define SECP256K1_GNUC_PREREQ(_maj,_min) \ - ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) -# else -# define SECP256K1_GNUC_PREREQ(_maj,_min) 0 -# endif -# endif - -# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) -# if SECP256K1_GNUC_PREREQ(2,7) -# define SECP256K1_INLINE __inline__ -# elif (defined(_MSC_VER)) -# define SECP256K1_INLINE __inline -# else -# define SECP256K1_INLINE -# endif -# else -# define SECP256K1_INLINE inline -# endif - -#ifndef SECP256K1_API -# if defined(_WIN32) -# ifdef SECP256K1_BUILD -# define SECP256K1_API __declspec(dllexport) -# else -# define SECP256K1_API -# endif -# elif defined(__GNUC__) && defined(SECP256K1_BUILD) -# define SECP256K1_API __attribute__ ((visibility ("default"))) -# else -# define SECP256K1_API -# endif -#endif - -/**Warning attributes - * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out - * some paranoid null checks. */ -# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) -# define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) -# else -# define SECP256K1_WARN_UNUSED_RESULT -# endif -# if !defined(SECP256K1_BUILD) && defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) -# define SECP256K1_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x))) -# else -# define SECP256K1_ARG_NONNULL(_x) -# endif - -/** All flags' lower 8 bits indicate what they're for. Do not use directly. */ -#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) -#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) -#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) -/** The higher bits contain the actual data. Do not use directly. */ -#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8) -#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) -#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) - -/** Flags to pass to secp256k1_context_create. */ -#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) -#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) -#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) - -/** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */ -#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) -#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) - -/** Prefix byte used to tag various encoded curvepoints for specific purposes */ -#define SECP256K1_TAG_PUBKEY_EVEN 0x02 -#define SECP256K1_TAG_PUBKEY_ODD 0x03 -#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04 -#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06 -#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07 - -/** Create a secp256k1 context object. - * - * Returns: a newly created context object. - * In: flags: which parts of the context to initialize. - * - * See also secp256k1_context_randomize. - */ -SECP256K1_API secp256k1_context* secp256k1_context_create( - unsigned int flags -) SECP256K1_WARN_UNUSED_RESULT; - -/** Copies a secp256k1 context object. - * - * Returns: a newly created context object. - * Args: ctx: an existing context to copy (cannot be NULL) - */ -SECP256K1_API secp256k1_context* secp256k1_context_clone( - const secp256k1_context* ctx -) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; - -/** Destroy a secp256k1 context object. - * - * The context pointer may not be used afterwards. - * Args: ctx: an existing context to destroy (cannot be NULL) - */ -SECP256K1_API void secp256k1_context_destroy( - secp256k1_context* ctx -); - -/** Set a callback function to be called when an illegal argument is passed to - * an API call. It will only trigger for violations that are mentioned - * explicitly in the header. - * - * The philosophy is that these shouldn't be dealt with through a - * specific return value, as calling code should not have branches to deal with - * the case that this code itself is broken. - * - * On the other hand, during debug stage, one would want to be informed about - * such mistakes, and the default (crashing) may be inadvisable. - * When this callback is triggered, the API function called is guaranteed not - * to cause a crash, though its return value and output arguments are - * undefined. - * - * Args: ctx: an existing context object (cannot be NULL) - * In: fun: a pointer to a function to call when an illegal argument is - * passed to the API, taking a message and an opaque pointer - * (NULL restores a default handler that calls abort). - * data: the opaque pointer to pass to fun above. - */ -SECP256K1_API void secp256k1_context_set_illegal_callback( - secp256k1_context* ctx, - void (*fun)(const char* message, void* data), - const void* data -) SECP256K1_ARG_NONNULL(1); - -/** Set a callback function to be called when an internal consistency check - * fails. The default is crashing. - * - * This can only trigger in case of a hardware failure, miscompilation, - * memory corruption, serious bug in the library, or other error would can - * otherwise result in undefined behaviour. It will not trigger due to mere - * incorrect usage of the API (see secp256k1_context_set_illegal_callback - * for that). After this callback returns, anything may happen, including - * crashing. - * - * Args: ctx: an existing context object (cannot be NULL) - * In: fun: a pointer to a function to call when an internal error occurs, - * taking a message and an opaque pointer (NULL restores a default - * handler that calls abort). - * data: the opaque pointer to pass to fun above. - */ -SECP256K1_API void secp256k1_context_set_error_callback( - secp256k1_context* ctx, - void (*fun)(const char* message, void* data), - const void* data -) SECP256K1_ARG_NONNULL(1); - -/** Parse a variable-length public key into the pubkey object. - * - * Returns: 1 if the public key was fully valid. - * 0 if the public key could not be parsed or is invalid. - * Args: ctx: a secp256k1 context object. - * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a - * parsed version of input. If not, its value is undefined. - * In: input: pointer to a serialized public key - * inputlen: length of the array pointed to by input - * - * This function supports parsing compressed (33 bytes, header byte 0x02 or - * 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header - * byte 0x06 or 0x07) format public keys. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse( - const secp256k1_context* ctx, - secp256k1_pubkey* pubkey, - const unsigned char *input, - size_t inputlen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize a pubkey object into a serialized byte sequence. - * - * Returns: 1 always. - * Args: ctx: a secp256k1 context object. - * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if - * compressed==1) byte array to place the serialized key - * in. - * In/Out: outputlen: a pointer to an integer which is initially set to the - * size of output, and is overwritten with the written - * size. - * In: pubkey: a pointer to a secp256k1_pubkey containing an - * initialized public key. - * flags: SECP256K1_EC_COMPRESSED if serialization should be in - * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED. - */ -SECP256K1_API int secp256k1_ec_pubkey_serialize( - const secp256k1_context* ctx, - unsigned char *output, - size_t *outputlen, - const secp256k1_pubkey* pubkey, - unsigned int flags -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Parse an ECDSA signature in compact (64 bytes) format. - * - * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input64: a pointer to the 64-byte array to parse - * - * The signature must consist of a 32-byte big endian R value, followed by a - * 32-byte big endian S value. If R or S fall outside of [0..order-1], the - * encoding is invalid. R and S with value 0 are allowed in the encoding. - * - * After the call, sig will always be initialized. If parsing failed or R or - * S are zero, the resulting sig value is guaranteed to fail validation for any - * message and public key. - */ -SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( - const secp256k1_context* ctx, - secp256k1_ecdsa_signature* sig, - const unsigned char *input64 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Parse a DER ECDSA signature. - * - * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input: a pointer to the signature to be parsed - * inputlen: the length of the array pointed to be input - * - * This function will accept any valid DER encoded signature, even if the - * encoded numbers are out of range. - * - * After the call, sig will always be initialized. If parsing failed or the - * encoded numbers are out of range, signature validation with it is - * guaranteed to fail for every message and public key. - */ -SECP256K1_API int secp256k1_ecdsa_signature_parse_der( - const secp256k1_context* ctx, - secp256k1_ecdsa_signature* sig, - const unsigned char *input, - size_t inputlen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize an ECDSA signature in DER format. - * - * Returns: 1 if enough space was available to serialize, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: output: a pointer to an array to store the DER serialization - * In/Out: outputlen: a pointer to a length integer. Initially, this integer - * should be set to the length of output. After the call - * it will be set to the length of the serialization (even - * if 0 was returned). - * In: sig: a pointer to an initialized signature object - */ -SECP256K1_API int secp256k1_ecdsa_signature_serialize_der( - const secp256k1_context* ctx, - unsigned char *output, - size_t *outputlen, - const secp256k1_ecdsa_signature* sig -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Serialize an ECDSA signature in compact (64 byte) format. - * - * Returns: 1 - * Args: ctx: a secp256k1 context object - * Out: output64: a pointer to a 64-byte array to store the compact serialization - * In: sig: a pointer to an initialized signature object - * - * See secp256k1_ecdsa_signature_parse_compact for details about the encoding. - */ -SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( - const secp256k1_context* ctx, - unsigned char *output64, - const secp256k1_ecdsa_signature* sig -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Verify an ECDSA signature. - * - * Returns: 1: correct signature - * 0: incorrect or unparseable signature - * Args: ctx: a secp256k1 context object, initialized for verification. - * In: sig: the signature being verified (cannot be NULL) - * msg32: the 32-byte message hash being verified (cannot be NULL) - * pubkey: pointer to an initialized public key to verify with (cannot be NULL) - * - * To avoid accepting malleable signatures, only ECDSA signatures in lower-S - * form are accepted. - * - * If you need to accept ECDSA signatures from sources that do not obey this - * rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to - * validation, but be aware that doing so results in malleable signatures. - * - * For details, see the comments for that function. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( - const secp256k1_context* ctx, - const secp256k1_ecdsa_signature *sig, - const unsigned char *msg32, - const secp256k1_pubkey *pubkey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Convert a signature to a normalized lower-S form. - * - * Returns: 1 if sigin was not normalized, 0 if it already was. - * Args: ctx: a secp256k1 context object - * Out: sigout: a pointer to a signature to fill with the normalized form, - * or copy if the input was already normalized. (can be NULL if - * you're only interested in whether the input was already - * normalized). - * In: sigin: a pointer to a signature to check/normalize (cannot be NULL, - * can be identical to sigout) - * - * With ECDSA a third-party can forge a second distinct signature of the same - * message, given a single initial signature, but without knowing the key. This - * is done by negating the S value modulo the order of the curve, 'flipping' - * the sign of the random point R which is not included in the signature. - * - * Forgery of the same message isn't universally problematic, but in systems - * where message malleability or uniqueness of signatures is important this can - * cause issues. This forgery can be blocked by all verifiers forcing signers - * to use a normalized form. - * - * The lower-S form reduces the size of signatures slightly on average when - * variable length encodings (such as DER) are used and is cheap to verify, - * making it a good choice. Security of always using lower-S is assured because - * anyone can trivially modify a signature after the fact to enforce this - * property anyway. - * - * The lower S value is always between 0x1 and - * 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, - * inclusive. - * - * No other forms of ECDSA malleability are known and none seem likely, but - * there is no formal proof that ECDSA, even with this additional restriction, - * is free of other malleability. Commonly used serialization schemes will also - * accept various non-unique encodings, so care should be taken when this - * property is required for an application. - * - * The secp256k1_ecdsa_sign function will by default create signatures in the - * lower-S form, and secp256k1_ecdsa_verify will not accept others. In case - * signatures come from a system that cannot enforce this property, - * secp256k1_ecdsa_signature_normalize must be called before verification. - */ -SECP256K1_API int secp256k1_ecdsa_signature_normalize( - const secp256k1_context* ctx, - secp256k1_ecdsa_signature *sigout, - const secp256k1_ecdsa_signature *sigin -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); - -/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. - * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of - * extra entropy. - */ -SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; - -/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ -SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default; - -/** Create an ECDSA signature. - * - * Returns: 1: signature created - * 0: the nonce generation function failed, or the private key was invalid. - * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) - * In: msg32: the 32-byte message hash being signed (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) - * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used - * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) - * - * The created signature is always in lower-S form. See - * secp256k1_ecdsa_signature_normalize for more details. - */ -SECP256K1_API int secp256k1_ecdsa_sign( - const secp256k1_context* ctx, - secp256k1_ecdsa_signature *sig, - const unsigned char *msg32, - const unsigned char *seckey, - secp256k1_nonce_function noncefp, - const void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Verify an ECDSA secret key. - * - * Returns: 1: secret key is valid - * 0: secret key is invalid - * Args: ctx: pointer to a context object (cannot be NULL) - * In: seckey: pointer to a 32-byte secret key (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( - const secp256k1_context* ctx, - const unsigned char *seckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Compute the public key for a secret key. - * - * Returns: 1: secret was valid, public key stores - * 0: secret was invalid, try again - * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * Out: pubkey: pointer to the created public key (cannot be NULL) - * In: seckey: pointer to a 32-byte private key (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( - const secp256k1_context* ctx, - secp256k1_pubkey *pubkey, - const unsigned char *seckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Negates a private key in place. - * - * Returns: 1 always - * Args: ctx: pointer to a context object - * In/Out: pubkey: pointer to the public key to be negated (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate( - const secp256k1_context* ctx, - unsigned char *seckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Negates a public key in place. - * - * Returns: 1 always - * Args: ctx: pointer to a context object - * In/Out: pubkey: pointer to the public key to be negated (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate( - const secp256k1_context* ctx, - secp256k1_pubkey *pubkey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Tweak a private key by adding tweak to it. - * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for - * uniformly random 32-byte arrays, or if the resulting private key - * would be invalid (only when the tweak is the complement of the - * private key). 1 otherwise. - * Args: ctx: pointer to a context object (cannot be NULL). - * In/Out: seckey: pointer to a 32-byte private key. - * In: tweak: pointer to a 32-byte tweak. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( - const secp256k1_context* ctx, - unsigned char *seckey, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Tweak a public key by adding tweak times the generator to it. - * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for - * uniformly random 32-byte arrays, or if the resulting public key - * would be invalid (only when the tweak is the complement of the - * corresponding private key). 1 otherwise. - * Args: ctx: pointer to a context object initialized for validation - * (cannot be NULL). - * In/Out: pubkey: pointer to a public key object. - * In: tweak: pointer to a 32-byte tweak. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( - const secp256k1_context* ctx, - secp256k1_pubkey *pubkey, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Tweak a private key by multiplying it by a tweak. - * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for - * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. - * Args: ctx: pointer to a context object (cannot be NULL). - * In/Out: seckey: pointer to a 32-byte private key. - * In: tweak: pointer to a 32-byte tweak. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( - const secp256k1_context* ctx, - unsigned char *seckey, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Tweak a public key by multiplying it by a tweak value. - * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for - * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. - * Args: ctx: pointer to a context object initialized for validation - * (cannot be NULL). - * In/Out: pubkey: pointer to a public key obkect. - * In: tweak: pointer to a 32-byte tweak. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( - const secp256k1_context* ctx, - secp256k1_pubkey *pubkey, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Updates the context randomization to protect against side-channel leakage. - * Returns: 1: randomization successfully updated - * 0: error - * Args: ctx: pointer to a context object (cannot be NULL) - * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) - * - * While secp256k1 code is written to be constant-time no matter what secret - * values are, it's possible that a future compiler may output code which isn't, - * and also that the CPU may not emit the same radio frequencies or draw the same - * amount power for all values. - * - * This function provides a seed which is combined into the blinding value: that - * blinding value is added before each multiplication (and removed afterwards) so - * that it does not affect function results, but shields against attacks which - * rely on any input-dependent behaviour. - * - * You should call this after secp256k1_context_create or - * secp256k1_context_clone, and may call this repeatedly afterwards. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( - secp256k1_context* ctx, - const unsigned char *seed32 -) SECP256K1_ARG_NONNULL(1); - -/** Add a number of public keys together. - * Returns: 1: the sum of the public keys is valid. - * 0: the sum of the public keys is not valid. - * Args: ctx: pointer to a context object - * Out: out: pointer to a public key object for placing the resulting public key - * (cannot be NULL) - * In: ins: pointer to array of pointers to public keys (cannot be NULL) - * n: the number of public keys to add together (must be at least 1) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( - const secp256k1_context* ctx, - secp256k1_pubkey *out, - const secp256k1_pubkey * const * ins, - size_t n -) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_H */ diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h deleted file mode 100644 index 88492dc1a4..0000000000 --- a/src/secp256k1/include/secp256k1_ecdh.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef SECP256K1_ECDH_H -#define SECP256K1_ECDH_H - -#include "secp256k1.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Compute an EC Diffie-Hellman secret in constant time - * Returns: 1: exponentiation was successful - * 0: scalar was invalid (zero or overflow) - * Args: ctx: pointer to a context object (cannot be NULL) - * Out: result: a 32-byte array which will be populated by an ECDH - * secret computed from the point and scalar - * In: pubkey: a pointer to a secp256k1_pubkey containing an - * initialized public key - * privkey: a 32-byte scalar with which to multiply the point - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( - const secp256k1_context* ctx, - unsigned char *result, - const secp256k1_pubkey *pubkey, - const unsigned char *privkey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_ECDH_H */ diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h deleted file mode 100644 index cf6c5ed7f5..0000000000 --- a/src/secp256k1/include/secp256k1_recovery.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef SECP256K1_RECOVERY_H -#define SECP256K1_RECOVERY_H - -#include "secp256k1.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Opaque data structured that holds a parsed ECDSA signature, - * supporting pubkey recovery. - * - * The exact representation of data inside is implementation defined and not - * guaranteed to be portable between different platforms or versions. It is - * however guaranteed to be 65 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage or transmission, use - * the secp256k1_ecdsa_signature_serialize_* and - * secp256k1_ecdsa_signature_parse_* functions. - * - * Furthermore, it is guaranteed that identical signatures (including their - * recoverability) will have identical representation, so they can be - * memcmp'ed. - */ -typedef struct { - unsigned char data[65]; -} secp256k1_ecdsa_recoverable_signature; - -/** Parse a compact ECDSA signature (64 bytes + recovery id). - * - * Returns: 1 when the signature could be parsed, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input64: a pointer to a 64-byte compact signature - * recid: the recovery id (0, 1, 2 or 3) - */ -SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact( - const secp256k1_context* ctx, - secp256k1_ecdsa_recoverable_signature* sig, - const unsigned char *input64, - int recid -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Convert a recoverable signature into a normal signature. - * - * Returns: 1 - * Out: sig: a pointer to a normal signature (cannot be NULL). - * In: sigin: a pointer to a recoverable signature (cannot be NULL). - */ -SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert( - const secp256k1_context* ctx, - secp256k1_ecdsa_signature* sig, - const secp256k1_ecdsa_recoverable_signature* sigin -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Serialize an ECDSA signature in compact format (64 bytes + recovery id). - * - * Returns: 1 - * Args: ctx: a secp256k1 context object - * Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL) - * recid: a pointer to an integer to hold the recovery id (can be NULL). - * In: sig: a pointer to an initialized signature object (cannot be NULL) - */ -SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( - const secp256k1_context* ctx, - unsigned char *output64, - int *recid, - const secp256k1_ecdsa_recoverable_signature* sig -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Create a recoverable ECDSA signature. - * - * Returns: 1: signature created - * 0: the nonce generation function failed, or the private key was invalid. - * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) - * In: msg32: the 32-byte message hash being signed (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) - * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used - * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) - */ -SECP256K1_API int secp256k1_ecdsa_sign_recoverable( - const secp256k1_context* ctx, - secp256k1_ecdsa_recoverable_signature *sig, - const unsigned char *msg32, - const unsigned char *seckey, - secp256k1_nonce_function noncefp, - const void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Recover an ECDSA public key from a signature. - * - * Returns: 1: public key successfully recovered (which guarantees a correct signature). - * 0: otherwise. - * Args: ctx: pointer to a context object, initialized for verification (cannot be NULL) - * Out: pubkey: pointer to the recovered public key (cannot be NULL) - * In: sig: pointer to initialized signature that supports pubkey recovery (cannot be NULL) - * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover( - const secp256k1_context* ctx, - secp256k1_pubkey *pubkey, - const secp256k1_ecdsa_recoverable_signature *sig, - const unsigned char *msg32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -#ifdef __cplusplus -} -#endif - -#endif /* SECP256K1_RECOVERY_H */ diff --git a/src/secp256k1/include/secp256k1_schnorr.h b/src/secp256k1/include/secp256k1_schnorr.h deleted file mode 100644 index afbae86040..0000000000 --- a/src/secp256k1/include/secp256k1_schnorr.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef _SECP256K1_SCHNORR_ -# define _SECP256K1_SCHNORR_ - -# include "secp256k1.h" - -# ifdef __cplusplus -extern "C" { -# endif - -/** - * Verify a signature created by secp256k1_schnorr_sign. - * Returns: 1: correct signature - * 0: incorrect signature - * Args: ctx: a secp256k1 context object, initialized for verification. - * In: sig64: the 64-byte signature being verified (cannot be NULL) - * msg32: the 32-byte message hash being verified (cannot be NULL) - * pubkey: the public key to verify with (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify( - const secp256k1_context* ctx, - const unsigned char *sig64, - const unsigned char *msg32, - const secp256k1_pubkey *pubkey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** - * Create a signature using a custom EC-Schnorr-SHA256 construction. It - * produces non-malleable 64-byte signatures which support batch validation, - * and multiparty signing. - * Returns: 1: signature created - * 0: the nonce generation function failed, or the private key was - * invalid. - * Args: ctx: pointer to a context object, initialized for signing - * (cannot be NULL) - * Out: sig64: pointer to a 64-byte array where the signature will be - * placed (cannot be NULL) - * In: msg32: the 32-byte message hash being signed (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) - * noncefp:pointer to a nonce generation function. If NULL, - * secp256k1_nonce_function_default is used - * ndata: pointer to arbitrary data used by the nonce generation - * function (can be NULL) - */ -SECP256K1_API int secp256k1_schnorr_sign( - const secp256k1_context *ctx, - unsigned char *sig64, - const unsigned char *msg32, - const unsigned char *seckey, - secp256k1_nonce_function noncefp, - const void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -# ifdef __cplusplus -} -# endif - -#endif diff --git a/src/secp256k1/libsecp256k1.pc.in b/src/secp256k1/libsecp256k1.pc.in deleted file mode 100644 index a0d006f113..0000000000 --- a/src/secp256k1/libsecp256k1.pc.in +++ /dev/null @@ -1,13 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libsecp256k1 -Description: Optimized C library for EC operations on curve secp256k1 -URL: https://github.com/bitcoin-core/secp256k1 -Version: @PACKAGE_VERSION@ -Cflags: -I${includedir} -Libs.private: @SECP_LIBS@ -Libs: -L${libdir} -lsecp256k1 - diff --git a/src/secp256k1/obj/.gitignore b/src/secp256k1/obj/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/secp256k1/sage/group_prover.sage b/src/secp256k1/sage/group_prover.sage deleted file mode 100644 index 8521f07999..0000000000 --- a/src/secp256k1/sage/group_prover.sage +++ /dev/null @@ -1,322 +0,0 @@ -# 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 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 -# executed. 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) diff --git a/src/secp256k1/sage/secp256k1.sage b/src/secp256k1/sage/secp256k1.sage deleted file mode 100644 index a97e732f7f..0000000000 --- a/src/secp256k1/sage/secp256k1.sage +++ /dev/null @@ -1,306 +0,0 @@ -# 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) diff --git a/src/secp256k1/sage/weierstrass_prover.sage b/src/secp256k1/sage/weierstrass_prover.sage deleted file mode 100644 index 03ef2ec901..0000000000 --- a/src/secp256k1/sage/weierstrass_prover.sage +++ /dev/null @@ -1,264 +0,0 @@ -# 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. = 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 diff --git a/src/secp256k1/src/asm/field_10x26_arm.s b/src/secp256k1/src/asm/field_10x26_arm.s deleted file mode 100644 index 5a9cc3ffcf..0000000000 --- a/src/secp256k1/src/asm/field_10x26_arm.s +++ /dev/null @@ -1,919 +0,0 @@ -@ 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 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 = Aggressive 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 - diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h deleted file mode 100644 index fc588061ca..0000000000 --- a/src/secp256k1/src/basic-config.h +++ /dev/null @@ -1,33 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_BASIC_CONFIG_H -#define SECP256K1_BASIC_CONFIG_H - -#ifdef USE_BASIC_CONFIG - -#undef USE_ASM_X86_64 -#undef USE_ENDOMORPHISM -#undef USE_FIELD_10X26 -#undef USE_FIELD_5X52 -#undef USE_FIELD_INV_BUILTIN -#undef USE_FIELD_INV_NUM -#undef USE_NUM_GMP -#undef USE_NUM_NONE -#undef USE_SCALAR_4X64 -#undef USE_SCALAR_8X32 -#undef USE_SCALAR_INV_BUILTIN -#undef USE_SCALAR_INV_NUM - -#define USE_NUM_NONE 1 -#define USE_FIELD_INV_BUILTIN 1 -#define USE_SCALAR_INV_BUILTIN 1 -#define USE_FIELD_10X26 1 -#define USE_SCALAR_8X32 1 - -#endif /* USE_BASIC_CONFIG */ - -#endif /* SECP256K1_BASIC_CONFIG_H */ diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h deleted file mode 100644 index d5ebe01301..0000000000 --- a/src/secp256k1/src/bench.h +++ /dev/null @@ -1,66 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_BENCH_H -#define SECP256K1_BENCH_H - -#include -#include -#include "sys/time.h" - -static double gettimedouble(void) { - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_usec * 0.000001 + tv.tv_sec; -} - -void print_number(double x) { - double y = x; - int c = 0; - if (y < 0.0) { - y = -y; - } - while (y > 0 && y < 100.0) { - y *= 10.0; - c++; - } - printf("%.*f", c, x); -} - -void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) { - int i; - double min = HUGE_VAL; - double sum = 0.0; - double max = 0.0; - for (i = 0; i < count; i++) { - double begin, total; - if (setup != NULL) { - setup(data); - } - begin = gettimedouble(); - benchmark(data); - total = gettimedouble() - begin; - if (teardown != NULL) { - teardown(data); - } - if (total < min) { - min = total; - } - if (total > max) { - max = total; - } - sum += total; - } - printf("%s: min ", name); - print_number(min * 1000000.0 / iter); - printf("us / avg "); - print_number((sum / count) * 1000000.0 / iter); - printf("us / max "); - print_number(max * 1000000.0 / iter); - printf("us\n"); -} - -#endif /* SECP256K1_BENCH_H */ diff --git a/src/secp256k1/src/bench_ecdh.c b/src/secp256k1/src/bench_ecdh.c deleted file mode 100644 index cde5e2dbb4..0000000000 --- a/src/secp256k1/src/bench_ecdh.c +++ /dev/null @@ -1,54 +0,0 @@ -/********************************************************************** - * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include - -#include "include/secp256k1.h" -#include "include/secp256k1_ecdh.h" -#include "util.h" -#include "bench.h" - -typedef struct { - secp256k1_context *ctx; - secp256k1_pubkey point; - unsigned char scalar[32]; -} bench_ecdh_t; - -static void bench_ecdh_setup(void* arg) { - int i; - bench_ecdh_t *data = (bench_ecdh_t*)arg; - const unsigned char point[] = { - 0x03, - 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, - 0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd, - 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb, - 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f - }; - - /* 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; - } - CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); -} - -static void bench_ecdh(void* arg) { - int i; - unsigned char res[32]; - bench_ecdh_t *data = (bench_ecdh_t*)arg; - - for (i = 0; i < 20000; i++) { - CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1); - } -} - -int main(void) { - bench_ecdh_t data; - - run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000); - return 0; -} diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c deleted file mode 100644 index 0809f77bda..0000000000 --- a/src/secp256k1/src/bench_internal.c +++ /dev/null @@ -1,382 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ -#include - -#include "include/secp256k1.h" - -#include "util.h" -#include "hash_impl.h" -#include "num_impl.h" -#include "field_impl.h" -#include "group_impl.h" -#include "scalar_impl.h" -#include "ecmult_const_impl.h" -#include "ecmult_impl.h" -#include "bench.h" -#include "secp256k1.c" - -typedef struct { - secp256k1_scalar scalar_x, scalar_y; - secp256k1_fe fe_x, fe_y; - secp256k1_ge ge_x, ge_y; - secp256k1_gej gej_x, gej_y; - unsigned char data[64]; - int wnaf[256]; -} bench_inv_t; - -void bench_setup(void* arg) { - bench_inv_t *data = (bench_inv_t*)arg; - - static const unsigned char init_x[32] = { - 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, - 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35, - 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, - 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83 - }; - - static const unsigned char init_y[32] = { - 0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83, - 0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5, - 0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9, - 0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3 - }; - - secp256k1_scalar_set_b32(&data->scalar_x, init_x, NULL); - secp256k1_scalar_set_b32(&data->scalar_y, init_y, NULL); - secp256k1_fe_set_b32(&data->fe_x, init_x); - secp256k1_fe_set_b32(&data->fe_y, init_y); - CHECK(secp256k1_ge_set_xo_var(&data->ge_x, &data->fe_x, 0)); - CHECK(secp256k1_ge_set_xo_var(&data->ge_y, &data->fe_y, 1)); - secp256k1_gej_set_ge(&data->gej_x, &data->ge_x); - secp256k1_gej_set_ge(&data->gej_y, &data->ge_y); - memcpy(data->data, init_x, 32); - memcpy(data->data + 32, init_y, 32); -} - -void bench_scalar_add(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 2000000; i++) { - secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); - } -} - -void bench_scalar_negate(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 2000000; i++) { - secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x); - } -} - -void bench_scalar_sqr(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 200000; i++) { - secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x); - } -} - -void bench_scalar_mul(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 200000; i++) { - secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y); - } -} - -#ifdef USE_ENDOMORPHISM -void bench_scalar_split(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 20000; i++) { - secp256k1_scalar l, r; - secp256k1_scalar_split_lambda(&l, &r, &data->scalar_x); - secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); - } -} -#endif - -void bench_scalar_inverse(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 2000; i++) { - secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x); - secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); - } -} - -void bench_scalar_inverse_var(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 2000; i++) { - secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x); - secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); - } -} - -void bench_field_normalize(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 2000000; i++) { - secp256k1_fe_normalize(&data->fe_x); - } -} - -void bench_field_normalize_weak(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 2000000; i++) { - secp256k1_fe_normalize_weak(&data->fe_x); - } -} - -void bench_field_mul(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 200000; i++) { - secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y); - } -} - -void bench_field_sqr(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 200000; i++) { - secp256k1_fe_sqr(&data->fe_x, &data->fe_x); - } -} - -void bench_field_inverse(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 20000; i++) { - secp256k1_fe_inv(&data->fe_x, &data->fe_x); - secp256k1_fe_add(&data->fe_x, &data->fe_y); - } -} - -void bench_field_inverse_var(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 20000; i++) { - secp256k1_fe_inv_var(&data->fe_x, &data->fe_x); - secp256k1_fe_add(&data->fe_x, &data->fe_y); - } -} - -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(&data->fe_x, &data->fe_x); - secp256k1_fe_add(&data->fe_x, &data->fe_y); - } -} - -void bench_group_double_var(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 200000; i++) { - secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL); - } -} - -void bench_group_add_var(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 200000; i++) { - secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL); - } -} - -void bench_group_add_affine(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 200000; i++) { - secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y); - } -} - -void bench_group_add_affine_var(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 200000; i++) { - secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL); - } -} - -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; - - for (i = 0; i < 20000; i++) { - secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A); - secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); - } -} - -void bench_wnaf_const(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - - for (i = 0; i < 20000; i++) { - secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A); - secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); - } -} - - -void bench_sha256(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - secp256k1_sha256_t sha; - - for (i = 0; i < 20000; i++) { - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, data->data, 32); - secp256k1_sha256_finalize(&sha, data->data); - } -} - -void bench_hmac_sha256(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - secp256k1_hmac_sha256_t hmac; - - for (i = 0; i < 20000; i++) { - secp256k1_hmac_sha256_initialize(&hmac, data->data, 32); - secp256k1_hmac_sha256_write(&hmac, data->data, 32); - secp256k1_hmac_sha256_finalize(&hmac, data->data); - } -} - -void bench_rfc6979_hmac_sha256(void* arg) { - int i; - bench_inv_t *data = (bench_inv_t*)arg; - secp256k1_rfc6979_hmac_sha256_t rng; - - for (i = 0; i < 20000; i++) { - secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); - secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32); - } -} - -void bench_context_verify(void* arg) { - int i; - (void)arg; - for (i = 0; i < 20; i++) { - secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY)); - } -} - -void bench_context_sign(void* arg) { - int i; - (void)arg; - for (i = 0; i < 200; i++) { - secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN)); - } -} - -#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; - argv++; - if (argv == argm) { - return 1; - } - while (argv != NULL && argv != argm) { - if (strcmp(*argv, flag) == 0) { - return 1; - } - argv++; - } - return 0; -} - -int main(int argc, char **argv) { - bench_inv_t data; - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000); - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000); - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000); - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, 200000); -#ifdef USE_ENDOMORPHISM - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, 20000); -#endif - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000); - if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000); - - if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, 2000000); - if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, 2000000); - if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, 200000); - 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", 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); - - if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000); - if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, 20000); - if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, 20000); - - 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; -} diff --git a/src/secp256k1/src/bench_recover.c b/src/secp256k1/src/bench_recover.c deleted file mode 100644 index 6489378cc6..0000000000 --- a/src/secp256k1/src/bench_recover.c +++ /dev/null @@ -1,60 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include "include/secp256k1.h" -#include "include/secp256k1_recovery.h" -#include "util.h" -#include "bench.h" - -typedef struct { - secp256k1_context *ctx; - unsigned char msg[32]; - unsigned char sig[64]; -} bench_recover_t; - -void bench_recover(void* arg) { - int i; - bench_recover_t *data = (bench_recover_t*)arg; - secp256k1_pubkey pubkey; - unsigned char pubkeyc[33]; - - for (i = 0; i < 20000; i++) { - int j; - size_t pubkeylen = 33; - secp256k1_ecdsa_recoverable_signature sig; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2)); - CHECK(secp256k1_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg)); - CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); - for (j = 0; j < 32; j++) { - data->sig[j + 32] = data->msg[j]; /* Move former message to S. */ - data->msg[j] = data->sig[j]; /* Move former R to message. */ - data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ - } - } -} - -void bench_recover_setup(void* arg) { - int i; - bench_recover_t *data = (bench_recover_t*)arg; - - for (i = 0; i < 32; i++) { - data->msg[i] = 1 + i; - } - for (i = 0; i < 64; i++) { - data->sig[i] = 65 + i; - } -} - -int main(void) { - bench_recover_t data; - - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - - run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, 20000); - - secp256k1_context_destroy(data.ctx); - return 0; -} diff --git a/src/secp256k1/src/bench_sign.c b/src/secp256k1/src/bench_sign.c deleted file mode 100644 index ed7224d757..0000000000 --- a/src/secp256k1/src/bench_sign.c +++ /dev/null @@ -1,56 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include "include/secp256k1.h" -#include "util.h" -#include "bench.h" - -typedef struct { - secp256k1_context* ctx; - unsigned char msg[32]; - unsigned char key[32]; -} bench_sign_t; - -static void bench_sign_setup(void* arg) { - int i; - bench_sign_t *data = (bench_sign_t*)arg; - - for (i = 0; i < 32; i++) { - data->msg[i] = i + 1; - } - for (i = 0; i < 32; i++) { - data->key[i] = i + 65; - } -} - -static void bench_sign(void* arg) { - int i; - bench_sign_t *data = (bench_sign_t*)arg; - - unsigned char sig[74]; - for (i = 0; i < 20000; i++) { - size_t siglen = 74; - int j; - secp256k1_ecdsa_signature signature; - CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL)); - CHECK(secp256k1_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature)); - for (j = 0; j < 32; j++) { - data->msg[j] = sig[j]; - data->key[j] = sig[j + 32]; - } - } -} - -int main(void) { - bench_sign_t data; - - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - - run_benchmark("ecdsa_sign", bench_sign, bench_sign_setup, NULL, &data, 10, 20000); - - secp256k1_context_destroy(data.ctx); - return 0; -} diff --git a/src/secp256k1/src/bench_verify.c b/src/secp256k1/src/bench_verify.c deleted file mode 100644 index 418defa0aa..0000000000 --- a/src/secp256k1/src/bench_verify.c +++ /dev/null @@ -1,112 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include -#include - -#include "include/secp256k1.h" -#include "util.h" -#include "bench.h" - -#ifdef ENABLE_OPENSSL_TESTS -#include -#include -#include -#endif - -typedef struct { - secp256k1_context *ctx; - unsigned char msg[32]; - unsigned char key[32]; - unsigned char sig[72]; - 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) { - int i; - benchmark_verify_t* data = (benchmark_verify_t*)arg; - - for (i = 0; i < 20000; i++) { - secp256k1_pubkey pubkey; - secp256k1_ecdsa_signature sig; - data->sig[data->siglen - 1] ^= (i & 0xFF); - data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); - data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); - CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); - CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); - CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0)); - data->sig[data->siglen - 1] ^= (i & 0xFF); - data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); - data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); - } -} - -#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; - secp256k1_ecdsa_signature sig; - benchmark_verify_t data; - - data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - for (i = 0; i < 32; i++) { - data.msg[i] = 1 + i; - } - for (i = 0; i < 32; i++) { - data.key[i] = 33 + i; - } - data.siglen = 72; - CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL)); - CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); - CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key)); - data.pubkeylen = 33; - 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; -} diff --git a/src/secp256k1/src/ecdsa.h b/src/secp256k1/src/ecdsa.h deleted file mode 100644 index 80590c7cc8..0000000000 --- a/src/secp256k1/src/ecdsa.h +++ /dev/null @@ -1,21 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_ECDSA_H -#define SECP256K1_ECDSA_H - -#include - -#include "scalar.h" -#include "group.h" -#include "ecmult.h" - -static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *r, secp256k1_scalar *s, const unsigned char *sig, size_t size); -static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s); -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message); -static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid); - -#endif /* SECP256K1_ECDSA_H */ diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h deleted file mode 100644 index c3400042d8..0000000000 --- a/src/secp256k1/src/ecdsa_impl.h +++ /dev/null @@ -1,313 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - - -#ifndef SECP256K1_ECDSA_IMPL_H -#define SECP256K1_ECDSA_IMPL_H - -#include "scalar.h" -#include "field.h" -#include "group.h" -#include "ecmult.h" -#include "ecmult_gen.h" -#include "ecdsa.h" - -/** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1 - * sage: for t in xrange(1023, -1, -1): - * .. p = 2**256 - 2**32 - t - * .. if p.is_prime(): - * .. print '%x'%p - * .. break - * 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f' - * sage: a = 0 - * sage: b = 7 - * sage: F = FiniteField (p) - * sage: '%x' % (EllipticCurve ([F (a), F (b)]).order()) - * 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141' - */ -static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, - 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL -); - -/** Difference between field and order, values 'p' and 'n' values defined in - * "Standards for Efficient Cryptography" (SEC2) 2.7.1. - * sage: p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F - * sage: a = 0 - * sage: b = 7 - * sage: F = FiniteField (p) - * sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order()) - * '14551231950b75fc4402da1722fc9baee' - */ -static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( - 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL -); - -static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) { - int lenleft, b1; - size_t ret = 0; - if (*sigp >= sigend) { - return -1; - } - b1 = *((*sigp)++); - if (b1 == 0xFF) { - /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */ - return -1; - } - if ((b1 & 0x80) == 0) { - /* X.690-0207 8.1.3.4 short form length octets */ - return b1; - } - if (b1 == 0x80) { - /* Indefinite length is not allowed in DER. */ - return -1; - } - /* X.690-207 8.1.3.5 long form length octets */ - lenleft = b1 & 0x7F; - if (lenleft > sigend - *sigp) { - return -1; - } - if (**sigp == 0) { - /* Not the shortest possible length encoding. */ - return -1; - } - if ((size_t)lenleft > sizeof(size_t)) { - /* The resulting length would exceed the range of a size_t, so - * certainly longer than the passed array size. - */ - return -1; - } - while (lenleft > 0) { - ret = (ret << 8) | **sigp; - if (ret + lenleft > (size_t)(sigend - *sigp)) { - /* Result exceeds the length of the passed array. */ - return -1; - } - (*sigp)++; - lenleft--; - } - if (ret < 128) { - /* Not the shortest possible length encoding. */ - return -1; - } - return ret; -} - -static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) { - int overflow = 0; - unsigned char ra[32] = {0}; - int rlen; - - if (*sig == sigend || **sig != 0x02) { - /* Not a primitive integer (X.690-0207 8.3.1). */ - return 0; - } - (*sig)++; - rlen = secp256k1_der_read_len(sig, sigend); - if (rlen <= 0 || (*sig) + rlen > sigend) { - /* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */ - return 0; - } - if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) { - /* Excessive 0x00 padding. */ - return 0; - } - if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) { - /* Excessive 0xFF padding. */ - return 0; - } - if ((**sig & 0x80) == 0x80) { - /* Negative. */ - overflow = 1; - } - while (rlen > 0 && **sig == 0) { - /* Skip leading zero bytes */ - rlen--; - (*sig)++; - } - if (rlen > 32) { - overflow = 1; - } - if (!overflow) { - memcpy(ra + 32 - rlen, *sig, rlen); - secp256k1_scalar_set_b32(r, ra, &overflow); - } - if (overflow) { - secp256k1_scalar_set_int(r, 0); - } - (*sig) += rlen; - return 1; -} - -static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) { - const unsigned char *sigend = sig + size; - int rlen; - if (sig == sigend || *(sig++) != 0x30) { - /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */ - return 0; - } - rlen = secp256k1_der_read_len(&sig, sigend); - if (rlen < 0 || sig + rlen > sigend) { - /* Tuple exceeds bounds */ - return 0; - } - if (sig + rlen != sigend) { - /* Garbage after tuple. */ - return 0; - } - - if (!secp256k1_der_parse_integer(rr, &sig, sigend)) { - return 0; - } - if (!secp256k1_der_parse_integer(rs, &sig, sigend)) { - return 0; - } - - if (sig != sigend) { - /* Trailing garbage inside tuple. */ - return 0; - } - - return 1; -} - -static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar* ar, const secp256k1_scalar* as) { - unsigned char r[33] = {0}, s[33] = {0}; - unsigned char *rp = r, *sp = s; - size_t lenR = 33, lenS = 33; - secp256k1_scalar_get_b32(&r[1], ar); - secp256k1_scalar_get_b32(&s[1], as); - while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; } - while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; } - if (*size < 6+lenS+lenR) { - *size = 6 + lenS + lenR; - return 0; - } - *size = 6 + lenS + lenR; - sig[0] = 0x30; - sig[1] = 4 + lenS + lenR; - sig[2] = 0x02; - sig[3] = lenR; - memcpy(sig+4, rp, lenR); - sig[4+lenR] = 0x02; - sig[5+lenR] = lenS; - memcpy(sig+lenR+6, sp, lenS); - return 1; -} - -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) { - unsigned char c[32]; - secp256k1_scalar sn, u1, u2; -#if !defined(EXHAUSTIVE_TEST_ORDER) - secp256k1_fe xr; -#endif - secp256k1_gej pubkeyj; - secp256k1_gej pr; - - if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { - return 0; - } - - secp256k1_scalar_inverse_var(&sn, sigs); - secp256k1_scalar_mul(&u1, &sn, message); - secp256k1_scalar_mul(&u2, &sn, sigr); - secp256k1_gej_set_ge(&pubkeyj, pubkey); - secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1); - if (secp256k1_gej_is_infinity(&pr)) { - return 0; - } - -#if defined(EXHAUSTIVE_TEST_ORDER) -{ - secp256k1_scalar computed_r; - secp256k1_ge pr_ge; - secp256k1_ge_set_gej(&pr_ge, &pr); - secp256k1_fe_normalize(&pr_ge.x); - - secp256k1_fe_get_b32(c, &pr_ge.x); - secp256k1_scalar_set_b32(&computed_r, c, NULL); - return secp256k1_scalar_eq(sigr, &computed_r); -} -#else - secp256k1_scalar_get_b32(c, sigr); - secp256k1_fe_set_b32(&xr, c); - - /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) - * in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p), - * compute the remainder modulo n, and compare it to xr. However: - * - * xr == X(pr) mod n - * <=> exists h. (xr + h * n < p && xr + h * n == X(pr)) - * [Since 2 * n > p, h can only be 0 or 1] - * <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr)) - * [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p] - * <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p) - * [Multiplying both sides of the equations by pr.z^2 mod p] - * <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x) - * - * Thus, we can avoid the inversion, but we have to check both cases separately. - * secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. - */ - if (secp256k1_gej_eq_x_var(&xr, &pr)) { - /* xr * pr.z^2 mod p == pr.x, so the signature is valid. */ - return 1; - } - if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) { - /* xr + n >= p, so we can skip testing the second case. */ - return 0; - } - secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe); - if (secp256k1_gej_eq_x_var(&xr, &pr)) { - /* (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. */ - return 1; - } - return 0; -#endif -} - -static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) { - unsigned char b[32]; - secp256k1_gej rp; - secp256k1_ge r; - secp256k1_scalar n; - int overflow = 0; - - secp256k1_ecmult_gen(ctx, &rp, nonce); - secp256k1_ge_set_gej(&r, &rp); - secp256k1_fe_normalize(&r.x); - secp256k1_fe_normalize(&r.y); - secp256k1_fe_get_b32(b, &r.x); - secp256k1_scalar_set_b32(sigr, b, &overflow); - /* These two conditions should be checked before calling */ - VERIFY_CHECK(!secp256k1_scalar_is_zero(sigr)); - VERIFY_CHECK(overflow == 0); - - if (recid) { - /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log - * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria. - */ - *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); - } - secp256k1_scalar_mul(&n, sigr, seckey); - secp256k1_scalar_add(&n, &n, message); - secp256k1_scalar_inverse(sigs, nonce); - secp256k1_scalar_mul(sigs, sigs, &n); - secp256k1_scalar_clear(&n); - secp256k1_gej_clear(&rp); - secp256k1_ge_clear(&r); - if (secp256k1_scalar_is_zero(sigs)) { - return 0; - } - if (secp256k1_scalar_is_high(sigs)) { - secp256k1_scalar_negate(sigs, sigs); - if (recid) { - *recid ^= 1; - } - } - return 1; -} - -#endif /* SECP256K1_ECDSA_IMPL_H */ diff --git a/src/secp256k1/src/eckey.h b/src/secp256k1/src/eckey.h deleted file mode 100644 index b621f1e6c3..0000000000 --- a/src/secp256k1/src/eckey.h +++ /dev/null @@ -1,25 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_ECKEY_H -#define SECP256K1_ECKEY_H - -#include - -#include "group.h" -#include "scalar.h" -#include "ecmult.h" -#include "ecmult_gen.h" - -static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size); -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed); - -static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak); -static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); -static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak); -static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); - -#endif /* SECP256K1_ECKEY_H */ diff --git a/src/secp256k1/src/eckey_impl.h b/src/secp256k1/src/eckey_impl.h deleted file mode 100644 index 1ab9a68ec0..0000000000 --- a/src/secp256k1/src/eckey_impl.h +++ /dev/null @@ -1,100 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_ECKEY_IMPL_H -#define SECP256K1_ECKEY_IMPL_H - -#include "eckey.h" - -#include "scalar.h" -#include "field.h" -#include "group.h" -#include "ecmult_gen.h" - -static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) { - if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) { - secp256k1_fe x; - return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD); - } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) { - secp256k1_fe x, y; - if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) { - return 0; - } - secp256k1_ge_set_xy(elem, &x, &y); - if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) && - secp256k1_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { - return 0; - } - return secp256k1_ge_is_valid_var(elem); - } else { - return 0; - } -} - -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) { - if (secp256k1_ge_is_infinity(elem)) { - return 0; - } - secp256k1_fe_normalize_var(&elem->x); - secp256k1_fe_normalize_var(&elem->y); - secp256k1_fe_get_b32(&pub[1], &elem->x); - if (compressed) { - *size = 33; - pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; - } else { - *size = 65; - pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; - secp256k1_fe_get_b32(&pub[33], &elem->y); - } - return 1; -} - -static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) { - secp256k1_scalar_add(key, key, tweak); - if (secp256k1_scalar_is_zero(key)) { - return 0; - } - return 1; -} - -static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) { - secp256k1_gej pt; - secp256k1_scalar one; - secp256k1_gej_set_ge(&pt, key); - secp256k1_scalar_set_int(&one, 1); - secp256k1_ecmult(ctx, &pt, &pt, &one, tweak); - - if (secp256k1_gej_is_infinity(&pt)) { - return 0; - } - secp256k1_ge_set_gej(key, &pt); - return 1; -} - -static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) { - if (secp256k1_scalar_is_zero(tweak)) { - return 0; - } - - secp256k1_scalar_mul(key, key, tweak); - return 1; -} - -static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) { - secp256k1_scalar zero; - secp256k1_gej pt; - if (secp256k1_scalar_is_zero(tweak)) { - return 0; - } - - secp256k1_scalar_set_int(&zero, 0); - secp256k1_gej_set_ge(&pt, key); - secp256k1_ecmult(ctx, &pt, &pt, tweak, &zero); - secp256k1_ge_set_gej(key, &pt); - return 1; -} - -#endif /* SECP256K1_ECKEY_IMPL_H */ diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h deleted file mode 100644 index 6d44aba60b..0000000000 --- a/src/secp256k1/src/ecmult.h +++ /dev/null @@ -1,31 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_ECMULT_H -#define SECP256K1_ECMULT_H - -#include "num.h" -#include "group.h" - -typedef struct { - /* For accelerating the computation of a*P + b*G: */ - secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */ -#ifdef USE_ENDOMORPHISM - secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */ -#endif -} secp256k1_ecmult_context; - -static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx); -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb); -static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, - const secp256k1_ecmult_context *src, const secp256k1_callback *cb); -static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx); -static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx); - -/** Double multiply: R = na*A + ng*G */ -static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng); - -#endif /* SECP256K1_ECMULT_H */ diff --git a/src/secp256k1/src/ecmult_const.h b/src/secp256k1/src/ecmult_const.h deleted file mode 100644 index 72bf7d7582..0000000000 --- a/src/secp256k1/src/ecmult_const.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_ECMULT_CONST_H -#define SECP256K1_ECMULT_CONST_H - -#include "scalar.h" -#include "group.h" - -static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q); - -#endif /* SECP256K1_ECMULT_CONST_H */ diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h deleted file mode 100644 index 7d7a172b7b..0000000000 --- a/src/secp256k1/src/ecmult_const_impl.h +++ /dev/null @@ -1,240 +0,0 @@ -/********************************************************************** - * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_ECMULT_CONST_IMPL_H -#define SECP256K1_ECMULT_CONST_IMPL_H - -#include "scalar.h" -#include "group.h" -#include "ecmult_const.h" -#include "ecmult_impl.h" - -#ifdef USE_ENDOMORPHISM - #define WNAF_BITS 128 -#else - #define WNAF_BITS 256 -#endif -#define WNAF_SIZE(w) ((WNAF_BITS + (w) - 1) / (w)) - -/* This is like `ECMULT_TABLE_GET_GE` but is constant time */ -#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \ - int m; \ - int abs_n = (n) * (((n) > 0) * 2 - 1); \ - int idx_n = abs_n / 2; \ - secp256k1_fe neg_y; \ - VERIFY_CHECK(((n) & 1) == 1); \ - VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ - VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ - VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \ - VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \ - for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \ - /* This loop is used to avoid secret data in array indices. See - * the comment in ecmult_gen_impl.h for rationale. */ \ - secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \ - secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \ - } \ - (r)->infinity = 0; \ - secp256k1_fe_negate(&neg_y, &(r)->y, 1); \ - secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \ -} while(0) - - -/** Convert a number to WNAF notation. - * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. - * It has the following guarantees: - * - each wnaf[i] an odd integer between -(1 << w) and (1 << w) - * - each wnaf[i] is nonzero - * - the number of words set is always WNAF_SIZE(w) + 1 - * - * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar - * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.) - * CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003 - * - * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335 - */ -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; - - int flip; - int bit; - secp256k1_scalar neg_s; - int not_neg_one; - /* 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, 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 ^ !secp256k1_scalar_is_even(&s); - /* We check for negative one, since adding 2 to it will cause an overflow */ - secp256k1_scalar_negate(&neg_s, &s); - not_neg_one = !secp256k1_scalar_is_one(&neg_s); - secp256k1_scalar_cadd_bit(&s, bit, not_neg_one); - /* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects - * that we added two to it and flipped it. In fact for -1 these operations are - * identical. We only flipped, but since skewing is required (in the sense that - * the skew must be 1 or 2, never zero) and flipping is not, we need to change - * our flags to claim that we only skewed. */ - global_sign = secp256k1_scalar_cond_negate(&s, flip); - global_sign *= not_neg_one * 2 - 1; - skew = 1 << bit; - - /* 4 */ - u_last = secp256k1_scalar_shr_int(&s, w); - while (word * w < WNAF_BITS) { - int sign; - int even; - - /* 4.1 4.4 */ - u = secp256k1_scalar_shr_int(&s, w); - /* 4.2 */ - even = ((u & 1) == 0); - sign = 2 * (u_last > 0) - 1; - u += sign * even; - u_last -= sign * even * (1 << w); - - /* 4.3, adapted for global sign change */ - wnaf[word++] = u_last * global_sign; - - u_last = u; - } - wnaf[word] = u * global_sign; - - VERIFY_CHECK(secp256k1_scalar_is_zero(&s)); - VERIFY_CHECK(word == WNAF_SIZE(w)); - return skew; -} - - -static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) { - secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; - 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_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; - int skew_lam; - secp256k1_scalar q_1, q_lam; -#endif - - int i; - secp256k1_scalar sc = *scalar; - - /* build wnaf representation for q. */ -#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); - 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 - skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1); -#endif - - /* Calculate odd multiples of a. - * All multiples are brought to the same Z 'denominator', which is stored - * in Z. Due to secp256k1' isomorphism we can do all operations pretending - * that the Z coordinate was 1, use affine addition formulae, and correct - * the Z coordinate of the result once at the end. - */ - secp256k1_gej_set_ge(r, a); - secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r); - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - secp256k1_fe_normalize_weak(&pre_a[i].y); - } -#ifdef USE_ENDOMORPHISM - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); - } -#endif - - /* 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) */ - 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); -#endif - /* remaining loop iterations */ - for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) { - int n; - int j; - for (j = 0; j < WINDOW_A - 1; ++j) { - secp256k1_gej_double_nonzero(r, r, NULL); - } - - 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); -#endif - } - - secp256k1_fe_mul(&r->z, &r->z, &Z); - - { - /* 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); -#endif - } -} - -#endif /* SECP256K1_ECMULT_CONST_IMPL_H */ diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h deleted file mode 100644 index 7564b7015f..0000000000 --- a/src/secp256k1/src/ecmult_gen.h +++ /dev/null @@ -1,43 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_ECMULT_GEN_H -#define SECP256K1_ECMULT_GEN_H - -#include "scalar.h" -#include "group.h" - -typedef struct { - /* For accelerating the computation of a*G: - * To harden against timing attacks, use the following mechanism: - * * Break up the multiplicand into groups of 4 bits, called n_0, n_1, n_2, ..., n_63. - * * Compute sum(n_i * 16^i * G + U_i, i=0..63), where: - * * U_i = U * 2^i (for i=0..62) - * * U_i = U * (1-2^63) (for i=63) - * where U is a point with no known corresponding scalar. Note that sum(U_i, i=0..63) = 0. - * For each i, and each of the 16 possible values of n_i, (n_i * 16^i * G + U_i) is - * precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63). - * None of the resulting prec group elements have a known scalar, and neither do any of - * the intermediate sums while computing a*G. - */ - secp256k1_ge_storage (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */ - secp256k1_scalar blind; - secp256k1_gej initial; -} secp256k1_ecmult_gen_context; - -static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx); -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb); -static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, - const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb); -static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx); -static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx); - -/** Multiply with the generator: R = a*G */ -static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a); - -static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32); - -#endif /* SECP256K1_ECMULT_GEN_H */ diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h deleted file mode 100644 index 9615b932dd..0000000000 --- a/src/secp256k1/src/ecmult_gen_impl.h +++ /dev/null @@ -1,210 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_ECMULT_GEN_IMPL_H -#define SECP256K1_ECMULT_GEN_IMPL_H - -#include "scalar.h" -#include "group.h" -#include "ecmult_gen.h" -#include "hash_impl.h" -#ifdef USE_ECMULT_STATIC_PRECOMPUTATION -#include "ecmult_static_context.h" -#endif -static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) { - ctx->prec = NULL; -} - -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) { -#ifndef USE_ECMULT_STATIC_PRECOMPUTATION - secp256k1_ge prec[1024]; - secp256k1_gej gj; - secp256k1_gej nums_gej; - int i, j; -#endif - - if (ctx->prec != NULL) { - return; - } -#ifndef USE_ECMULT_STATIC_PRECOMPUTATION - ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec)); - - /* get the generator */ - secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); - - /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ - { - static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; - secp256k1_fe nums_x; - secp256k1_ge nums_ge; - int r; - r = secp256k1_fe_set_b32(&nums_x, nums_b32); - (void)r; - VERIFY_CHECK(r); - r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0); - (void)r; - VERIFY_CHECK(r); - secp256k1_gej_set_ge(&nums_gej, &nums_ge); - /* Add G to make the bits in x uniformly distributed. */ - secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL); - } - - /* compute prec. */ - { - secp256k1_gej precj[1024]; /* Jacobian versions of prec. */ - secp256k1_gej gbase; - secp256k1_gej numsbase; - gbase = gj; /* 16^j * G */ - numsbase = nums_gej; /* 2^j * nums. */ - for (j = 0; j < 64; j++) { - /* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */ - precj[j*16] = numsbase; - for (i = 1; i < 16; i++) { - secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL); - } - /* Multiply gbase by 16. */ - for (i = 0; i < 4; i++) { - secp256k1_gej_double_var(&gbase, &gbase, NULL); - } - /* Multiply numbase by 2. */ - secp256k1_gej_double_var(&numsbase, &numsbase, NULL); - if (j == 62) { - /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ - secp256k1_gej_neg(&numsbase, &numsbase); - secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); - } - } - secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb); - } - for (j = 0; j < 64; j++) { - for (i = 0; i < 16; i++) { - secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]); - } - } -#else - (void)cb; - ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context; -#endif - secp256k1_ecmult_gen_blind(ctx, NULL); -} - -static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) { - return ctx->prec != NULL; -} - -static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, - const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) { - if (src->prec == NULL) { - dst->prec = NULL; - } else { -#ifndef USE_ECMULT_STATIC_PRECOMPUTATION - dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec)); - memcpy(dst->prec, src->prec, sizeof(*dst->prec)); -#else - (void)cb; - dst->prec = src->prec; -#endif - dst->initial = src->initial; - dst->blind = src->blind; - } -} - -static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) { -#ifndef USE_ECMULT_STATIC_PRECOMPUTATION - free(ctx->prec); -#endif - secp256k1_scalar_clear(&ctx->blind); - secp256k1_gej_clear(&ctx->initial); - ctx->prec = NULL; -} - -static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) { - secp256k1_ge add; - secp256k1_ge_storage adds; - secp256k1_scalar gnb; - int bits; - int i, j; - memset(&adds, 0, sizeof(adds)); - *r = ctx->initial; - /* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */ - secp256k1_scalar_add(&gnb, gn, &ctx->blind); - add.infinity = 0; - for (j = 0; j < 64; j++) { - bits = secp256k1_scalar_get_bits(&gnb, j * 4, 4); - for (i = 0; i < 16; i++) { - /** This uses a conditional move to avoid any secret data in array indexes. - * _Any_ use of secret indexes has been demonstrated to result in timing - * sidechannels, even when the cache-line access patterns are uniform. - * See also: - * "A word of warning", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe - * (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and - * "Cache Attacks and Countermeasures: the Case of AES", RSA 2006, - * by Dag Arne Osvik, Adi Shamir, and Eran Tromer - * (http://www.tau.ac.il/~tromer/papers/cache.pdf) - */ - secp256k1_ge_storage_cmov(&adds, &(*ctx->prec)[j][i], i == bits); - } - secp256k1_ge_from_storage(&add, &adds); - secp256k1_gej_add_ge(r, r, &add); - } - bits = 0; - secp256k1_ge_clear(&add); - secp256k1_scalar_clear(&gnb); -} - -/* Setup blinding values for secp256k1_ecmult_gen. */ -static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) { - secp256k1_scalar b; - secp256k1_gej gb; - secp256k1_fe s; - unsigned char nonce32[32]; - secp256k1_rfc6979_hmac_sha256_t rng; - int retry; - unsigned char keydata[64] = {0}; - if (seed32 == NULL) { - /* When seed is NULL, reset the initial point and blinding value. */ - secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g); - secp256k1_gej_neg(&ctx->initial, &ctx->initial); - secp256k1_scalar_set_int(&ctx->blind, 1); - } - /* The prior blinding value (if not reset) is chained forward by including it in the hash. */ - secp256k1_scalar_get_b32(nonce32, &ctx->blind); - /** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data, - * and guards against weak or adversarial seeds. This is a simpler and safer interface than - * asking the caller for blinding values directly and expecting them to retry on failure. - */ - memcpy(keydata, nonce32, 32); - if (seed32 != NULL) { - memcpy(keydata + 32, seed32, 32); - } - secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32); - memset(keydata, 0, sizeof(keydata)); - /* Retry for out of range results to achieve uniformity. */ - do { - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - retry = !secp256k1_fe_set_b32(&s, nonce32); - retry |= secp256k1_fe_is_zero(&s); - } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */ - /* Randomize the projection to defend against multiplier sidechannels. */ - secp256k1_gej_rescale(&ctx->initial, &s); - secp256k1_fe_clear(&s); - do { - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - secp256k1_scalar_set_b32(&b, nonce32, &retry); - /* A blinding value of 0 works, but would undermine the projection hardening. */ - retry |= secp256k1_scalar_is_zero(&b); - } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */ - secp256k1_rfc6979_hmac_sha256_finalize(&rng); - memset(nonce32, 0, 32); - secp256k1_ecmult_gen(ctx, &gb, &b); - secp256k1_scalar_negate(&b, &b); - ctx->blind = b; - ctx->initial = gb; - secp256k1_scalar_clear(&b); - secp256k1_gej_clear(&gb); -} - -#endif /* SECP256K1_ECMULT_GEN_IMPL_H */ diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h deleted file mode 100644 index 93d3794cb4..0000000000 --- a/src/secp256k1/src/ecmult_impl.h +++ /dev/null @@ -1,406 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_ECMULT_IMPL_H -#define SECP256K1_ECMULT_IMPL_H - -#include - -#include "group.h" -#include "scalar.h" -#include "ecmult.h" - -#if defined(EXHAUSTIVE_TEST_ORDER) -/* We need to lower these values for exhaustive tests because - * the tables cannot have infinities in them (this breaks the - * affine-isomorphism stuff which tracks z-ratios) */ -# if EXHAUSTIVE_TEST_ORDER > 128 -# define WINDOW_A 5 -# define WINDOW_G 8 -# elif EXHAUSTIVE_TEST_ORDER > 8 -# define WINDOW_A 4 -# define WINDOW_G 4 -# else -# define WINDOW_A 2 -# define WINDOW_G 2 -# endif -#else -/* optimal for 128-bit and 256-bit exponents. */ -#define WINDOW_A 5 -/** larger numbers may result in slightly better performance, at the cost of - exponentially larger precomputed tables. */ -#ifdef USE_ENDOMORPHISM -/** Two tables for window size 15: 1.375 MiB. */ -#define WINDOW_G 15 -#else -/** One table for window size 16: 1.375 MiB. */ -#define WINDOW_G 16 -#endif -#endif - -/** The number of entries a table with precomputed multiples needs to have. */ -#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2)) - -/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain - * the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will - * contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z. - * Prej's Z values are undefined, except for the last value. - */ -static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, secp256k1_fe *zr, const secp256k1_gej *a) { - secp256k1_gej d; - secp256k1_ge a_ge, d_ge; - int i; - - VERIFY_CHECK(!a->infinity); - - secp256k1_gej_double_var(&d, a, NULL); - - /* - * Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate - * of 'd', and scale the 1P starting value's x/y coordinates without changing its z. - */ - d_ge.x = d.x; - d_ge.y = d.y; - d_ge.infinity = 0; - - secp256k1_ge_set_gej_zinv(&a_ge, a, &d.z); - prej[0].x = a_ge.x; - prej[0].y = a_ge.y; - prej[0].z = a->z; - prej[0].infinity = 0; - - zr[0] = d.z; - for (i = 1; i < n; i++) { - secp256k1_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]); - } - - /* - * Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only - * the final point's z coordinate is actually used though, so just update that. - */ - secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z); -} - -/** Fill a table 'pre' with precomputed odd multiples of a. - * - * There are two versions of this function: - * - secp256k1_ecmult_odd_multiples_table_globalz_windowa which brings its - * resulting point set to a single constant Z denominator, stores the X and Y - * coordinates as ge_storage points in pre, and stores the global Z in rz. - * It only operates on tables sized for WINDOW_A wnaf multiples. - * - secp256k1_ecmult_odd_multiples_table_storage_var, which converts its - * resulting point set to actually affine points, and stores those in pre. - * It operates on tables of any size, but uses heap-allocated temporaries. - * - * To compute a*P + b*G, we compute a table for P using the first function, - * and for G using the second (which requires an inverse, but it only needs to - * happen once). - */ -static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) { - secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)]; - - /* Compute the odd multiples in Jacobian form. */ - secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a); - /* Bring them to the same Z denominator. */ - secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr); -} - -static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge_storage *pre, const secp256k1_gej *a, const secp256k1_callback *cb) { - secp256k1_gej *prej = (secp256k1_gej*)checked_malloc(cb, sizeof(secp256k1_gej) * n); - secp256k1_ge *prea = (secp256k1_ge*)checked_malloc(cb, sizeof(secp256k1_ge) * n); - secp256k1_fe *zr = (secp256k1_fe*)checked_malloc(cb, sizeof(secp256k1_fe) * n); - int i; - - /* Compute the odd multiples in Jacobian form. */ - secp256k1_ecmult_odd_multiples_table(n, prej, zr, a); - /* Convert them in batch to affine coordinates. */ - secp256k1_ge_set_table_gej_var(prea, prej, zr, n); - /* Convert them to compact storage form. */ - for (i = 0; i < n; i++) { - secp256k1_ge_to_storage(&pre[i], &prea[i]); - } - - free(prea); - free(prej); - free(zr); -} - -/** The following two macro retrieves a particular odd multiple from a table - * of precomputed multiples. */ -#define ECMULT_TABLE_GET_GE(r,pre,n,w) do { \ - VERIFY_CHECK(((n) & 1) == 1); \ - VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ - VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ - if ((n) > 0) { \ - *(r) = (pre)[((n)-1)/2]; \ - } else { \ - secp256k1_ge_neg((r), &(pre)[(-(n)-1)/2]); \ - } \ -} while(0) - -#define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \ - VERIFY_CHECK(((n) & 1) == 1); \ - VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ - VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ - if ((n) > 0) { \ - secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \ - } else { \ - secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \ - secp256k1_ge_neg((r), (r)); \ - } \ -} while(0) - -static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) { - ctx->pre_g = NULL; -#ifdef USE_ENDOMORPHISM - ctx->pre_g_128 = NULL; -#endif -} - -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) { - secp256k1_gej gj; - - if (ctx->pre_g != NULL) { - return; - } - - /* get the generator */ - secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); - - ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); - - /* precompute the tables with odd multiples */ - secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb); - -#ifdef USE_ENDOMORPHISM - { - secp256k1_gej g_128j; - int i; - - ctx->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); - - /* calculate 2^128*generator */ - g_128j = gj; - for (i = 0; i < 128; i++) { - secp256k1_gej_double_var(&g_128j, &g_128j, NULL); - } - secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j, cb); - } -#endif -} - -static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, - const secp256k1_ecmult_context *src, const secp256k1_callback *cb) { - if (src->pre_g == NULL) { - dst->pre_g = NULL; - } else { - size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); - dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); - memcpy(dst->pre_g, src->pre_g, size); - } -#ifdef USE_ENDOMORPHISM - if (src->pre_g_128 == NULL) { - dst->pre_g_128 = NULL; - } else { - size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); - dst->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); - memcpy(dst->pre_g_128, src->pre_g_128, size); - } -#endif -} - -static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx) { - return ctx->pre_g != NULL; -} - -static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) { - free(ctx->pre_g); -#ifdef USE_ENDOMORPHISM - free(ctx->pre_g_128); -#endif - secp256k1_ecmult_context_init(ctx); -} - -/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits), - * with the following guarantees: - * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) - * - two non-zero entries in wnaf are separated by at least w-1 zeroes. - * - the number of set values in wnaf is returned. This number is at most 256, and at most one more - * than the number of bits in the (absolute value) of the input. - */ -static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, int w) { - secp256k1_scalar s = *a; - int last_set_bit = -1; - int bit = 0; - int sign = 1; - int carry = 0; - - VERIFY_CHECK(wnaf != NULL); - VERIFY_CHECK(0 <= len && len <= 256); - VERIFY_CHECK(a != NULL); - VERIFY_CHECK(2 <= w && w <= 31); - - memset(wnaf, 0, len * sizeof(wnaf[0])); - - if (secp256k1_scalar_get_bits(&s, 255, 1)) { - secp256k1_scalar_negate(&s, &s); - sign = -1; - } - - while (bit < len) { - int now; - int word; - if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) { - bit++; - continue; - } - - now = w; - if (now > len - bit) { - now = len - bit; - } - - word = secp256k1_scalar_get_bits_var(&s, bit, now) + carry; - - carry = (word >> (w-1)) & 1; - word -= carry << w; - - wnaf[bit] = sign * word; - last_set_bit = bit; - - bit += now; - } -#ifdef VERIFY - CHECK(carry == 0); - while (bit < 256) { - CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0); - } -#endif - return last_set_bit + 1; -} - -static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { - secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_ge tmpa; - secp256k1_fe Z; -#ifdef USE_ENDOMORPHISM - secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_scalar na_1, na_lam; - /* Splitted G factors. */ - secp256k1_scalar ng_1, ng_128; - int wnaf_na_1[130]; - int wnaf_na_lam[130]; - int bits_na_1; - int bits_na_lam; - int wnaf_ng_1[129]; - int bits_ng_1; - int wnaf_ng_128[129]; - int bits_ng_128; -#else - int wnaf_na[256]; - int bits_na; - int wnaf_ng[256]; - int bits_ng; -#endif - int i; - int bits; - -#ifdef USE_ENDOMORPHISM - /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ - secp256k1_scalar_split_lambda(&na_1, &na_lam, na); - - /* build wnaf representation for na_1 and na_lam. */ - bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, 130, &na_1, WINDOW_A); - bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, 130, &na_lam, WINDOW_A); - VERIFY_CHECK(bits_na_1 <= 130); - VERIFY_CHECK(bits_na_lam <= 130); - bits = bits_na_1; - if (bits_na_lam > bits) { - bits = bits_na_lam; - } -#else - /* build wnaf representation for na. */ - bits_na = secp256k1_ecmult_wnaf(wnaf_na, 256, na, WINDOW_A); - bits = bits_na; -#endif - - /* Calculate odd multiples of a. - * All multiples are brought to the same Z 'denominator', which is stored - * in Z. Due to secp256k1' isomorphism we can do all operations pretending - * that the Z coordinate was 1, use affine addition formulae, and correct - * the Z coordinate of the result once at the end. - * The exception is the precomputed G table points, which are actually - * affine. Compared to the base used for other points, they have a Z ratio - * of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same - * isomorphism to efficiently add with a known Z inverse. - */ - secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, a); - -#ifdef USE_ENDOMORPHISM - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); - } - - /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ - secp256k1_scalar_split_128(&ng_1, &ng_128, ng); - - /* Build wnaf representation for ng_1 and ng_128 */ - bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G); - bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G); - if (bits_ng_1 > bits) { - bits = bits_ng_1; - } - if (bits_ng_128 > bits) { - bits = bits_ng_128; - } -#else - bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G); - if (bits_ng > bits) { - bits = bits_ng; - } -#endif - - secp256k1_gej_set_infinity(r); - - for (i = bits - 1; i >= 0; i--) { - int n; - secp256k1_gej_double_var(r, r, NULL); -#ifdef USE_ENDOMORPHISM - if (i < bits_na_1 && (n = wnaf_na_1[i])) { - ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); - secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); - } - if (i < bits_na_lam && (n = wnaf_na_lam[i])) { - ECMULT_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); - secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); - } - if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { - ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); - secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); - } - if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { - ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G); - secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); - } -#else - if (i < bits_na && (n = wnaf_na[i])) { - ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); - secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); - } - if (i < bits_ng && (n = wnaf_ng[i])) { - ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); - secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); - } -#endif - } - - if (!r->infinity) { - secp256k1_fe_mul(&r->z, &r->z, &Z); - } -} - -#endif /* SECP256K1_ECMULT_IMPL_H */ diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h deleted file mode 100644 index bb6692ad57..0000000000 --- a/src/secp256k1/src/field.h +++ /dev/null @@ -1,132 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_FIELD_H -#define SECP256K1_FIELD_H - -/** Field element module. - * - * Field elements can be represented in several ways, but code accessing - * it (and implementations) need to take certain properties into account: - * - Each field element can be normalized or not. - * - Each field element has a magnitude, which represents how far away - * its representation is away from normalization. Normalized elements - * always have a magnitude of 1, but a magnitude of 1 doesn't imply - * normality. - */ - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#if defined(USE_FIELD_10X26) -#include "field_10x26.h" -#elif defined(USE_FIELD_5X52) -#include "field_5x52.h" -#else -#error "Please select field implementation" -#endif - -#include "util.h" - -/** Normalize a field element. */ -static void secp256k1_fe_normalize(secp256k1_fe *r); - -/** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */ -static void secp256k1_fe_normalize_weak(secp256k1_fe *r); - -/** Normalize a field element, without constant-time guarantee. */ -static void secp256k1_fe_normalize_var(secp256k1_fe *r); - -/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field - * implementation may optionally normalize the input, but this should not be relied upon. */ -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r); - -/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field - * implementation may optionally normalize the input, but this should not be relied upon. */ -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r); - -/** Set a field element equal to a small integer. Resulting field element is normalized. */ -static void secp256k1_fe_set_int(secp256k1_fe *r, int a); - -/** Sets a field element equal to zero, initializing all fields. */ -static void secp256k1_fe_clear(secp256k1_fe *a); - -/** Verify whether a field element is zero. Requires the input to be normalized. */ -static int secp256k1_fe_is_zero(const secp256k1_fe *a); - -/** Check the "oddness" of a field element. Requires the input to be normalized. */ -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 */ -static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); - -/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */ -static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); - -/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); - -/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input - * as an argument. The magnitude of the output is one higher. */ -static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); - -/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that - * small integer. */ -static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); - -/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ -static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); - -/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. - * The output magnitude is 1 (but not guaranteed to be normalized). */ -static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); - -/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. - * The output magnitude is 1 (but not guaranteed to be normalized). */ -static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); - -/** If a has a square root, it is computed in r and 1 is returned. If a does not - * have a square root, the root of its negation is computed and 0 is returned. - * 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(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). */ -static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a); - -/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ -static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); - -/** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be - * at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and - * outputs must not overlap in memory. */ -static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len); - -/** Convert a field element to the storage type. */ -static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); - -/** Convert a field element back from the storage type. */ -static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ -static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag); - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ -static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); - -#endif /* SECP256K1_FIELD_H */ diff --git a/src/secp256k1/src/field_10x26.h b/src/secp256k1/src/field_10x26.h deleted file mode 100644 index 727c5267fb..0000000000 --- a/src/secp256k1/src/field_10x26.h +++ /dev/null @@ -1,48 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_FIELD_REPR_H -#define SECP256K1_FIELD_REPR_H - -#include - -typedef struct { - /* X = sum(i=0..9, elem[i]*2^26) mod n */ - uint32_t n[10]; -#ifdef VERIFY - int magnitude; - int normalized; -#endif -} secp256k1_fe; - -/* Unpacks a constant into a overlapping multi-limbed FE element. */ -#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ - (d0) & 0x3FFFFFFUL, \ - (((uint32_t)d0) >> 26) | (((uint32_t)(d1) & 0xFFFFFUL) << 6), \ - (((uint32_t)d1) >> 20) | (((uint32_t)(d2) & 0x3FFFUL) << 12), \ - (((uint32_t)d2) >> 14) | (((uint32_t)(d3) & 0xFFUL) << 18), \ - (((uint32_t)d3) >> 8) | (((uint32_t)(d4) & 0x3UL) << 24), \ - (((uint32_t)d4) >> 2) & 0x3FFFFFFUL, \ - (((uint32_t)d4) >> 28) | (((uint32_t)(d5) & 0x3FFFFFUL) << 4), \ - (((uint32_t)d5) >> 22) | (((uint32_t)(d6) & 0xFFFFUL) << 10), \ - (((uint32_t)d6) >> 16) | (((uint32_t)(d7) & 0x3FFUL) << 16), \ - (((uint32_t)d7) >> 10) \ -} - -#ifdef VERIFY -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} -#else -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} -#endif - -typedef struct { - uint32_t n[8]; -} secp256k1_fe_storage; - -#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }} -#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0] - -#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h deleted file mode 100644 index 94f8132fc8..0000000000 --- a/src/secp256k1/src/field_10x26_impl.h +++ /dev/null @@ -1,1161 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_FIELD_REPR_IMPL_H -#define SECP256K1_FIELD_REPR_IMPL_H - -#include "util.h" -#include "num.h" -#include "field.h" - -#ifdef VERIFY -static void secp256k1_fe_verify(const secp256k1_fe *a) { - const uint32_t *d = a->n; - int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; - r &= (d[0] <= 0x3FFFFFFUL * m); - r &= (d[1] <= 0x3FFFFFFUL * m); - r &= (d[2] <= 0x3FFFFFFUL * m); - r &= (d[3] <= 0x3FFFFFFUL * m); - r &= (d[4] <= 0x3FFFFFFUL * m); - r &= (d[5] <= 0x3FFFFFFUL * m); - r &= (d[6] <= 0x3FFFFFFUL * m); - r &= (d[7] <= 0x3FFFFFFUL * m); - r &= (d[8] <= 0x3FFFFFFUL * m); - r &= (d[9] <= 0x03FFFFFUL * m); - r &= (a->magnitude >= 0); - r &= (a->magnitude <= 32); - if (a->normalized) { - r &= (a->magnitude <= 1); - if (r && (d[9] == 0x03FFFFFUL)) { - uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2]; - if (mid == 0x3FFFFFFUL) { - r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); - } - } - } - VERIFY_CHECK(r == 1); -} -#endif - -static void secp256k1_fe_normalize(secp256k1_fe *r) { - uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], - t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; - - /* Reduce t9 at the start so there will be at most a single carry from the first pass */ - uint32_t m; - uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x3D1UL; t1 += (x << 6); - t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; m = t2; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; m &= t3; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; m &= t4; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; m &= t5; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; m &= t6; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; m &= t7; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; m &= t8; - - /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t9 >> 23 == 0); - - /* At most a single final reduction is needed; check if the value is >= the field characteristic */ - x = (t9 >> 22) | ((t9 == 0x03FFFFFUL) & (m == 0x3FFFFFFUL) - & ((t1 + 0x40UL + ((t0 + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); - - /* Apply the final reduction (for constant-time behaviour, we do it always) */ - t0 += x * 0x3D1UL; t1 += (x << 6); - t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; - - /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */ - VERIFY_CHECK(t9 >> 22 == x); - - /* Mask off the possible multiple of 2^256 from the final reduction */ - t9 &= 0x03FFFFFUL; - - r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif -} - -static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { - uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], - t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; - - /* Reduce t9 at the start so there will be at most a single carry from the first pass */ - uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x3D1UL; t1 += (x << 6); - t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; - - /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t9 >> 23 == 0); - - r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - secp256k1_fe_verify(r); -#endif -} - -static void secp256k1_fe_normalize_var(secp256k1_fe *r) { - uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], - t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; - - /* Reduce t9 at the start so there will be at most a single carry from the first pass */ - uint32_t m; - uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x3D1UL; t1 += (x << 6); - t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; m = t2; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; m &= t3; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; m &= t4; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; m &= t5; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; m &= t6; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; m &= t7; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; m &= t8; - - /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t9 >> 23 == 0); - - /* At most a single final reduction is needed; check if the value is >= the field characteristic */ - x = (t9 >> 22) | ((t9 == 0x03FFFFFUL) & (m == 0x3FFFFFFUL) - & ((t1 + 0x40UL + ((t0 + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); - - if (x) { - t0 += 0x3D1UL; t1 += (x << 6); - t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; - - /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */ - VERIFY_CHECK(t9 >> 22 == x); - - /* Mask off the possible multiple of 2^256 from the final reduction */ - t9 &= 0x03FFFFFUL; - } - - r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif -} - -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { - uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], - t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; - - /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ - uint32_t z0, z1; - - /* Reduce t9 at the start so there will be at most a single carry from the first pass */ - uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x3D1UL; t1 += (x << 6); - t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; z0 = t0; z1 = t0 ^ 0x3D0UL; - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; - z0 |= t9; z1 &= t9 ^ 0x3C00000UL; - - /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t9 >> 23 == 0); - - return (z0 == 0) | (z1 == 0x3FFFFFFUL); -} - -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { - uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; - uint32_t z0, z1; - uint32_t x; - - t0 = r->n[0]; - t9 = r->n[9]; - - /* Reduce t9 at the start so there will be at most a single carry from the first pass */ - x = t9 >> 22; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x3D1UL; - - /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ - z0 = t0 & 0x3FFFFFFUL; - z1 = z0 ^ 0x3D0UL; - - /* Fast return path should catch the majority of cases */ - if ((z0 != 0UL) & (z1 != 0x3FFFFFFUL)) { - return 0; - } - - t1 = r->n[1]; - t2 = r->n[2]; - t3 = r->n[3]; - t4 = r->n[4]; - t5 = r->n[5]; - t6 = r->n[6]; - t7 = r->n[7]; - t8 = r->n[8]; - - t9 &= 0x03FFFFFUL; - t1 += (x << 6); - - t1 += (t0 >> 26); - t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; - t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; - t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; - t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; - t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; - t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; - t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; - t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; - z0 |= t9; z1 &= t9 ^ 0x3C00000UL; - - /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t9 >> 23 == 0); - - return (z0 == 0) | (z1 == 0x3FFFFFFUL); -} - -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { - r->n[0] = a; - r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif -} - -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { - const uint32_t *t = a->n; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif - return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; -} - -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif - return a->n[0] & 1; -} - -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { - int i; -#ifdef VERIFY - a->magnitude = 0; - a->normalized = 1; -#endif - for (i=0; i<10; i++) { - a->n[i] = 0; - } -} - -static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { - int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); -#endif - for (i = 9; i >= 0; i--) { - if (a->n[i] > b->n[i]) { - return 1; - } - if (a->n[i] < b->n[i]) { - return -1; - } - } - return 0; -} - -static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { - r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24); - r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22); - r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20); - r->n[3] = (uint32_t)((a[22] >> 6) & 0x3) | ((uint32_t)a[21] << 2) | ((uint32_t)a[20] << 10) | ((uint32_t)a[19] << 18); - r->n[4] = (uint32_t)a[18] | ((uint32_t)a[17] << 8) | ((uint32_t)a[16] << 16) | ((uint32_t)(a[15] & 0x3) << 24); - r->n[5] = (uint32_t)((a[15] >> 2) & 0x3f) | ((uint32_t)a[14] << 6) | ((uint32_t)a[13] << 14) | ((uint32_t)(a[12] & 0xf) << 22); - r->n[6] = (uint32_t)((a[12] >> 4) & 0xf) | ((uint32_t)a[11] << 4) | ((uint32_t)a[10] << 12) | ((uint32_t)(a[9] & 0x3f) << 20); - r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18); - r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24); - r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14); - - if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) { - return 0; - } -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif - return 1; -} - -/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif - r[0] = (a->n[9] >> 14) & 0xff; - r[1] = (a->n[9] >> 6) & 0xff; - r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3); - r[3] = (a->n[8] >> 16) & 0xff; - r[4] = (a->n[8] >> 8) & 0xff; - r[5] = a->n[8] & 0xff; - r[6] = (a->n[7] >> 18) & 0xff; - r[7] = (a->n[7] >> 10) & 0xff; - r[8] = (a->n[7] >> 2) & 0xff; - r[9] = ((a->n[7] & 0x3) << 6) | ((a->n[6] >> 20) & 0x3f); - r[10] = (a->n[6] >> 12) & 0xff; - r[11] = (a->n[6] >> 4) & 0xff; - r[12] = ((a->n[6] & 0xf) << 4) | ((a->n[5] >> 22) & 0xf); - r[13] = (a->n[5] >> 14) & 0xff; - r[14] = (a->n[5] >> 6) & 0xff; - r[15] = ((a->n[5] & 0x3f) << 2) | ((a->n[4] >> 24) & 0x3); - r[16] = (a->n[4] >> 16) & 0xff; - r[17] = (a->n[4] >> 8) & 0xff; - r[18] = a->n[4] & 0xff; - r[19] = (a->n[3] >> 18) & 0xff; - r[20] = (a->n[3] >> 10) & 0xff; - r[21] = (a->n[3] >> 2) & 0xff; - r[22] = ((a->n[3] & 0x3) << 6) | ((a->n[2] >> 20) & 0x3f); - r[23] = (a->n[2] >> 12) & 0xff; - r[24] = (a->n[2] >> 4) & 0xff; - r[25] = ((a->n[2] & 0xf) << 4) | ((a->n[1] >> 22) & 0xf); - r[26] = (a->n[1] >> 14) & 0xff; - r[27] = (a->n[1] >> 6) & 0xff; - r[28] = ((a->n[1] & 0x3f) << 2) | ((a->n[0] >> 24) & 0x3); - r[29] = (a->n[0] >> 16) & 0xff; - r[30] = (a->n[0] >> 8) & 0xff; - r[31] = a->n[0] & 0xff; -} - -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= m); - secp256k1_fe_verify(a); -#endif - r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0]; - r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1]; - r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2]; - r->n[3] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[3]; - r->n[4] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[4]; - r->n[5] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[5]; - r->n[6] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[6]; - r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7]; - r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8]; - r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9]; -#ifdef VERIFY - r->magnitude = m + 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif -} - -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { - r->n[0] *= a; - r->n[1] *= a; - r->n[2] *= a; - r->n[3] *= a; - r->n[4] *= a; - r->n[5] *= a; - r->n[6] *= a; - r->n[7] *= a; - r->n[8] *= a; - r->n[9] *= a; -#ifdef VERIFY - r->magnitude *= a; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif -} - -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - secp256k1_fe_verify(a); -#endif - r->n[0] += a->n[0]; - r->n[1] += a->n[1]; - r->n[2] += a->n[2]; - r->n[3] += a->n[3]; - r->n[4] += a->n[4]; - r->n[5] += a->n[5]; - r->n[6] += a->n[6]; - r->n[7] += a->n[7]; - r->n[8] += a->n[8]; - r->n[9] += a->n[9]; -#ifdef VERIFY - r->magnitude += a->magnitude; - r->normalized = 0; - secp256k1_fe_verify(r); -#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 -#define VERIFY_BITS(x, n) do { } while(0) -#endif - -SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) { - uint64_t c, d; - uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; - uint32_t t9, t1, t0, t2, t3, t4, t5, t6, t7; - const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; - - VERIFY_BITS(a[0], 30); - VERIFY_BITS(a[1], 30); - VERIFY_BITS(a[2], 30); - VERIFY_BITS(a[3], 30); - VERIFY_BITS(a[4], 30); - VERIFY_BITS(a[5], 30); - VERIFY_BITS(a[6], 30); - VERIFY_BITS(a[7], 30); - VERIFY_BITS(a[8], 30); - VERIFY_BITS(a[9], 26); - VERIFY_BITS(b[0], 30); - VERIFY_BITS(b[1], 30); - VERIFY_BITS(b[2], 30); - VERIFY_BITS(b[3], 30); - VERIFY_BITS(b[4], 30); - VERIFY_BITS(b[5], 30); - VERIFY_BITS(b[6], 30); - VERIFY_BITS(b[7], 30); - VERIFY_BITS(b[8], 30); - VERIFY_BITS(b[9], 26); - - /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. - * px is a shorthand for sum(a[i]*b[x-i], i=0..x). - * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. - */ - - d = (uint64_t)a[0] * b[9] - + (uint64_t)a[1] * b[8] - + (uint64_t)a[2] * b[7] - + (uint64_t)a[3] * b[6] - + (uint64_t)a[4] * b[5] - + (uint64_t)a[5] * b[4] - + (uint64_t)a[6] * b[3] - + (uint64_t)a[7] * b[2] - + (uint64_t)a[8] * b[1] - + (uint64_t)a[9] * b[0]; - /* VERIFY_BITS(d, 64); */ - /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ - t9 = d & M; d >>= 26; - VERIFY_BITS(t9, 26); - VERIFY_BITS(d, 38); - /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ - - c = (uint64_t)a[0] * b[0]; - VERIFY_BITS(c, 60); - /* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */ - d += (uint64_t)a[1] * b[9] - + (uint64_t)a[2] * b[8] - + (uint64_t)a[3] * b[7] - + (uint64_t)a[4] * b[6] - + (uint64_t)a[5] * b[5] - + (uint64_t)a[6] * b[4] - + (uint64_t)a[7] * b[3] - + (uint64_t)a[8] * b[2] - + (uint64_t)a[9] * b[1]; - VERIFY_BITS(d, 63); - /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - u0 = d & M; d >>= 26; c += u0 * R0; - VERIFY_BITS(u0, 26); - VERIFY_BITS(d, 37); - VERIFY_BITS(c, 61); - /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - t0 = c & M; c >>= 26; c += u0 * R1; - VERIFY_BITS(t0, 26); - VERIFY_BITS(c, 37); - /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - - c += (uint64_t)a[0] * b[1] - + (uint64_t)a[1] * b[0]; - VERIFY_BITS(c, 62); - /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */ - d += (uint64_t)a[2] * b[9] - + (uint64_t)a[3] * b[8] - + (uint64_t)a[4] * b[7] - + (uint64_t)a[5] * b[6] - + (uint64_t)a[6] * b[5] - + (uint64_t)a[7] * b[4] - + (uint64_t)a[8] * b[3] - + (uint64_t)a[9] * b[2]; - VERIFY_BITS(d, 63); - /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - u1 = d & M; d >>= 26; c += u1 * R0; - VERIFY_BITS(u1, 26); - VERIFY_BITS(d, 37); - VERIFY_BITS(c, 63); - /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - t1 = c & M; c >>= 26; c += u1 * R1; - VERIFY_BITS(t1, 26); - VERIFY_BITS(c, 38); - /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - - c += (uint64_t)a[0] * b[2] - + (uint64_t)a[1] * b[1] - + (uint64_t)a[2] * b[0]; - VERIFY_BITS(c, 62); - /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - d += (uint64_t)a[3] * b[9] - + (uint64_t)a[4] * b[8] - + (uint64_t)a[5] * b[7] - + (uint64_t)a[6] * b[6] - + (uint64_t)a[7] * b[5] - + (uint64_t)a[8] * b[4] - + (uint64_t)a[9] * b[3]; - VERIFY_BITS(d, 63); - /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - u2 = d & M; d >>= 26; c += u2 * R0; - VERIFY_BITS(u2, 26); - VERIFY_BITS(d, 37); - VERIFY_BITS(c, 63); - /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - t2 = c & M; c >>= 26; c += u2 * R1; - VERIFY_BITS(t2, 26); - VERIFY_BITS(c, 38); - /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - - c += (uint64_t)a[0] * b[3] - + (uint64_t)a[1] * b[2] - + (uint64_t)a[2] * b[1] - + (uint64_t)a[3] * b[0]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - d += (uint64_t)a[4] * b[9] - + (uint64_t)a[5] * b[8] - + (uint64_t)a[6] * b[7] - + (uint64_t)a[7] * b[6] - + (uint64_t)a[8] * b[5] - + (uint64_t)a[9] * b[4]; - VERIFY_BITS(d, 63); - /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - u3 = d & M; d >>= 26; c += u3 * R0; - VERIFY_BITS(u3, 26); - VERIFY_BITS(d, 37); - /* VERIFY_BITS(c, 64); */ - /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - t3 = c & M; c >>= 26; c += u3 * R1; - VERIFY_BITS(t3, 26); - VERIFY_BITS(c, 39); - /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - - c += (uint64_t)a[0] * b[4] - + (uint64_t)a[1] * b[3] - + (uint64_t)a[2] * b[2] - + (uint64_t)a[3] * b[1] - + (uint64_t)a[4] * b[0]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - d += (uint64_t)a[5] * b[9] - + (uint64_t)a[6] * b[8] - + (uint64_t)a[7] * b[7] - + (uint64_t)a[8] * b[6] - + (uint64_t)a[9] * b[5]; - VERIFY_BITS(d, 62); - /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - u4 = d & M; d >>= 26; c += u4 * R0; - VERIFY_BITS(u4, 26); - VERIFY_BITS(d, 36); - /* VERIFY_BITS(c, 64); */ - /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - t4 = c & M; c >>= 26; c += u4 * R1; - VERIFY_BITS(t4, 26); - VERIFY_BITS(c, 39); - /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - - c += (uint64_t)a[0] * b[5] - + (uint64_t)a[1] * b[4] - + (uint64_t)a[2] * b[3] - + (uint64_t)a[3] * b[2] - + (uint64_t)a[4] * b[1] - + (uint64_t)a[5] * b[0]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)a[6] * b[9] - + (uint64_t)a[7] * b[8] - + (uint64_t)a[8] * b[7] - + (uint64_t)a[9] * b[6]; - VERIFY_BITS(d, 62); - /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - u5 = d & M; d >>= 26; c += u5 * R0; - VERIFY_BITS(u5, 26); - VERIFY_BITS(d, 36); - /* VERIFY_BITS(c, 64); */ - /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - t5 = c & M; c >>= 26; c += u5 * R1; - VERIFY_BITS(t5, 26); - VERIFY_BITS(c, 39); - /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - - c += (uint64_t)a[0] * b[6] - + (uint64_t)a[1] * b[5] - + (uint64_t)a[2] * b[4] - + (uint64_t)a[3] * b[3] - + (uint64_t)a[4] * b[2] - + (uint64_t)a[5] * b[1] - + (uint64_t)a[6] * b[0]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)a[7] * b[9] - + (uint64_t)a[8] * b[8] - + (uint64_t)a[9] * b[7]; - VERIFY_BITS(d, 61); - /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - u6 = d & M; d >>= 26; c += u6 * R0; - VERIFY_BITS(u6, 26); - VERIFY_BITS(d, 35); - /* VERIFY_BITS(c, 64); */ - /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - t6 = c & M; c >>= 26; c += u6 * R1; - VERIFY_BITS(t6, 26); - VERIFY_BITS(c, 39); - /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - - c += (uint64_t)a[0] * b[7] - + (uint64_t)a[1] * b[6] - + (uint64_t)a[2] * b[5] - + (uint64_t)a[3] * b[4] - + (uint64_t)a[4] * b[3] - + (uint64_t)a[5] * b[2] - + (uint64_t)a[6] * b[1] - + (uint64_t)a[7] * b[0]; - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x8000007C00000007ULL); - /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)a[8] * b[9] - + (uint64_t)a[9] * b[8]; - VERIFY_BITS(d, 58); - /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - u7 = d & M; d >>= 26; c += u7 * R0; - VERIFY_BITS(u7, 26); - VERIFY_BITS(d, 32); - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL); - /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - t7 = c & M; c >>= 26; c += u7 * R1; - VERIFY_BITS(t7, 26); - VERIFY_BITS(c, 38); - /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - - c += (uint64_t)a[0] * b[8] - + (uint64_t)a[1] * b[7] - + (uint64_t)a[2] * b[6] - + (uint64_t)a[3] * b[5] - + (uint64_t)a[4] * b[4] - + (uint64_t)a[5] * b[3] - + (uint64_t)a[6] * b[2] - + (uint64_t)a[7] * b[1] - + (uint64_t)a[8] * b[0]; - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x9000007B80000008ULL); - /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)a[9] * b[9]; - VERIFY_BITS(d, 57); - /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - u8 = d & M; d >>= 26; c += u8 * R0; - VERIFY_BITS(u8, 26); - VERIFY_BITS(d, 31); - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x9000016FBFFFC2F8ULL); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - r[3] = t3; - VERIFY_BITS(r[3], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = t4; - VERIFY_BITS(r[4], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[5] = t5; - VERIFY_BITS(r[5], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[6] = t6; - VERIFY_BITS(r[6], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[7] = t7; - VERIFY_BITS(r[7], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - r[8] = c & M; c >>= 26; c += u8 * R1; - VERIFY_BITS(r[8], 26); - VERIFY_BITS(c, 39); - /* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R0 + t9; - VERIFY_BITS(c, 45); - /* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[9] = c & (M >> 4); c >>= 22; c += d * (R1 << 4); - VERIFY_BITS(r[9], 22); - VERIFY_BITS(c, 46); - /* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - d = c * (R0 >> 4) + t0; - VERIFY_BITS(d, 56); - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[0] = d & M; d >>= 26; - VERIFY_BITS(r[0], 26); - VERIFY_BITS(d, 30); - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += c * (R1 >> 4) + t1; - VERIFY_BITS(d, 53); - VERIFY_CHECK(d <= 0x10000003FFFFBFULL); - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[1] = d & M; d >>= 26; - VERIFY_BITS(r[1], 26); - VERIFY_BITS(d, 27); - VERIFY_CHECK(d <= 0x4000000ULL); - /* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += t2; - VERIFY_BITS(d, 27); - /* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[2] = d; - 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] */ -} - -SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a) { - uint64_t c, d; - uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; - uint32_t t9, t0, t1, t2, t3, t4, t5, t6, t7; - const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; - - VERIFY_BITS(a[0], 30); - VERIFY_BITS(a[1], 30); - VERIFY_BITS(a[2], 30); - VERIFY_BITS(a[3], 30); - VERIFY_BITS(a[4], 30); - VERIFY_BITS(a[5], 30); - VERIFY_BITS(a[6], 30); - VERIFY_BITS(a[7], 30); - VERIFY_BITS(a[8], 30); - VERIFY_BITS(a[9], 26); - - /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. - * px is a shorthand for sum(a[i]*a[x-i], i=0..x). - * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. - */ - - d = (uint64_t)(a[0]*2) * a[9] - + (uint64_t)(a[1]*2) * a[8] - + (uint64_t)(a[2]*2) * a[7] - + (uint64_t)(a[3]*2) * a[6] - + (uint64_t)(a[4]*2) * a[5]; - /* VERIFY_BITS(d, 64); */ - /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ - t9 = d & M; d >>= 26; - VERIFY_BITS(t9, 26); - VERIFY_BITS(d, 38); - /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ - - c = (uint64_t)a[0] * a[0]; - VERIFY_BITS(c, 60); - /* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */ - d += (uint64_t)(a[1]*2) * a[9] - + (uint64_t)(a[2]*2) * a[8] - + (uint64_t)(a[3]*2) * a[7] - + (uint64_t)(a[4]*2) * a[6] - + (uint64_t)a[5] * a[5]; - VERIFY_BITS(d, 63); - /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - u0 = d & M; d >>= 26; c += u0 * R0; - VERIFY_BITS(u0, 26); - VERIFY_BITS(d, 37); - VERIFY_BITS(c, 61); - /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - t0 = c & M; c >>= 26; c += u0 * R1; - VERIFY_BITS(t0, 26); - VERIFY_BITS(c, 37); - /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ - - c += (uint64_t)(a[0]*2) * a[1]; - VERIFY_BITS(c, 62); - /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */ - d += (uint64_t)(a[2]*2) * a[9] - + (uint64_t)(a[3]*2) * a[8] - + (uint64_t)(a[4]*2) * a[7] - + (uint64_t)(a[5]*2) * a[6]; - VERIFY_BITS(d, 63); - /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - u1 = d & M; d >>= 26; c += u1 * R0; - VERIFY_BITS(u1, 26); - VERIFY_BITS(d, 37); - VERIFY_BITS(c, 63); - /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - t1 = c & M; c >>= 26; c += u1 * R1; - VERIFY_BITS(t1, 26); - VERIFY_BITS(c, 38); - /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[2] - + (uint64_t)a[1] * a[1]; - VERIFY_BITS(c, 62); - /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - d += (uint64_t)(a[3]*2) * a[9] - + (uint64_t)(a[4]*2) * a[8] - + (uint64_t)(a[5]*2) * a[7] - + (uint64_t)a[6] * a[6]; - VERIFY_BITS(d, 63); - /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - u2 = d & M; d >>= 26; c += u2 * R0; - VERIFY_BITS(u2, 26); - VERIFY_BITS(d, 37); - VERIFY_BITS(c, 63); - /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - t2 = c & M; c >>= 26; c += u2 * R1; - VERIFY_BITS(t2, 26); - VERIFY_BITS(c, 38); - /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[3] - + (uint64_t)(a[1]*2) * a[2]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - d += (uint64_t)(a[4]*2) * a[9] - + (uint64_t)(a[5]*2) * a[8] - + (uint64_t)(a[6]*2) * a[7]; - VERIFY_BITS(d, 63); - /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - u3 = d & M; d >>= 26; c += u3 * R0; - VERIFY_BITS(u3, 26); - VERIFY_BITS(d, 37); - /* VERIFY_BITS(c, 64); */ - /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - t3 = c & M; c >>= 26; c += u3 * R1; - VERIFY_BITS(t3, 26); - VERIFY_BITS(c, 39); - /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[4] - + (uint64_t)(a[1]*2) * a[3] - + (uint64_t)a[2] * a[2]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - d += (uint64_t)(a[5]*2) * a[9] - + (uint64_t)(a[6]*2) * a[8] - + (uint64_t)a[7] * a[7]; - VERIFY_BITS(d, 62); - /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - u4 = d & M; d >>= 26; c += u4 * R0; - VERIFY_BITS(u4, 26); - VERIFY_BITS(d, 36); - /* VERIFY_BITS(c, 64); */ - /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - t4 = c & M; c >>= 26; c += u4 * R1; - VERIFY_BITS(t4, 26); - VERIFY_BITS(c, 39); - /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[5] - + (uint64_t)(a[1]*2) * a[4] - + (uint64_t)(a[2]*2) * a[3]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)(a[6]*2) * a[9] - + (uint64_t)(a[7]*2) * a[8]; - VERIFY_BITS(d, 62); - /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - u5 = d & M; d >>= 26; c += u5 * R0; - VERIFY_BITS(u5, 26); - VERIFY_BITS(d, 36); - /* VERIFY_BITS(c, 64); */ - /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - t5 = c & M; c >>= 26; c += u5 * R1; - VERIFY_BITS(t5, 26); - VERIFY_BITS(c, 39); - /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[6] - + (uint64_t)(a[1]*2) * a[5] - + (uint64_t)(a[2]*2) * a[4] - + (uint64_t)a[3] * a[3]; - VERIFY_BITS(c, 63); - /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)(a[7]*2) * a[9] - + (uint64_t)a[8] * a[8]; - VERIFY_BITS(d, 61); - /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - u6 = d & M; d >>= 26; c += u6 * R0; - VERIFY_BITS(u6, 26); - VERIFY_BITS(d, 35); - /* VERIFY_BITS(c, 64); */ - /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - t6 = c & M; c >>= 26; c += u6 * R1; - VERIFY_BITS(t6, 26); - VERIFY_BITS(c, 39); - /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[7] - + (uint64_t)(a[1]*2) * a[6] - + (uint64_t)(a[2]*2) * a[5] - + (uint64_t)(a[3]*2) * a[4]; - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x8000007C00000007ULL); - /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)(a[8]*2) * a[9]; - VERIFY_BITS(d, 58); - /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - u7 = d & M; d >>= 26; c += u7 * R0; - VERIFY_BITS(u7, 26); - VERIFY_BITS(d, 32); - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL); - /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - t7 = c & M; c >>= 26; c += u7 * R1; - VERIFY_BITS(t7, 26); - VERIFY_BITS(c, 38); - /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ - - c += (uint64_t)(a[0]*2) * a[8] - + (uint64_t)(a[1]*2) * a[7] - + (uint64_t)(a[2]*2) * a[6] - + (uint64_t)(a[3]*2) * a[5] - + (uint64_t)a[4] * a[4]; - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x9000007B80000008ULL); - /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint64_t)a[9] * a[9]; - VERIFY_BITS(d, 57); - /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - u8 = d & M; d >>= 26; c += u8 * R0; - VERIFY_BITS(u8, 26); - VERIFY_BITS(d, 31); - /* VERIFY_BITS(c, 64); */ - VERIFY_CHECK(c <= 0x9000016FBFFFC2F8ULL); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - r[3] = t3; - VERIFY_BITS(r[3], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = t4; - VERIFY_BITS(r[4], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[5] = t5; - VERIFY_BITS(r[5], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[6] = t6; - VERIFY_BITS(r[6], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[7] = t7; - VERIFY_BITS(r[7], 26); - /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - r[8] = c & M; c >>= 26; c += u8 * R1; - VERIFY_BITS(r[8], 26); - VERIFY_BITS(c, 39); - /* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R0 + t9; - VERIFY_BITS(c, 45); - /* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[9] = c & (M >> 4); c >>= 22; c += d * (R1 << 4); - VERIFY_BITS(r[9], 22); - VERIFY_BITS(c, 46); - /* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - d = c * (R0 >> 4) + t0; - VERIFY_BITS(d, 56); - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[0] = d & M; d >>= 26; - VERIFY_BITS(r[0], 26); - VERIFY_BITS(d, 30); - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += c * (R1 >> 4) + t1; - VERIFY_BITS(d, 53); - VERIFY_CHECK(d <= 0x10000003FFFFBFULL); - /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - /* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[1] = d & M; d >>= 26; - VERIFY_BITS(r[1], 26); - VERIFY_BITS(d, 27); - VERIFY_CHECK(d <= 0x4000000ULL); - /* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - d += t2; - VERIFY_BITS(d, 27); - /* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[2] = d; - 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 - VERIFY_CHECK(a->magnitude <= 8); - VERIFY_CHECK(b->magnitude <= 8); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); - VERIFY_CHECK(r != b); -#endif - secp256k1_fe_mul_inner(r->n, a->n, b->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif -} - -static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - secp256k1_fe_verify(a); -#endif - secp256k1_fe_sqr_inner(r->n, a->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif -} - -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { - uint32_t mask0, mask1; - mask0 = flag + ~((uint32_t)0); - mask1 = ~mask0; - r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); - r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); - r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); - r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); - r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); - r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1); - r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1); - r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); - r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); - r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); -#ifdef VERIFY - if (a->magnitude > r->magnitude) { - r->magnitude = a->magnitude; - } - r->normalized &= a->normalized; -#endif -} - -static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { - uint32_t mask0, mask1; - mask0 = flag + ~((uint32_t)0); - mask1 = ~mask0; - r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); - r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); - r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); - r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); - r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); - r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1); - r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1); - r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); -} - -static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif - r->n[0] = a->n[0] | a->n[1] << 26; - r->n[1] = a->n[1] >> 6 | a->n[2] << 20; - r->n[2] = a->n[2] >> 12 | a->n[3] << 14; - r->n[3] = a->n[3] >> 18 | a->n[4] << 8; - r->n[4] = a->n[4] >> 24 | a->n[5] << 2 | a->n[6] << 28; - r->n[5] = a->n[6] >> 4 | a->n[7] << 22; - r->n[6] = a->n[7] >> 10 | a->n[8] << 16; - r->n[7] = a->n[8] >> 16 | a->n[9] << 10; -} - -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { - r->n[0] = a->n[0] & 0x3FFFFFFUL; - r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL); - r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL); - r->n[3] = a->n[2] >> 14 | ((a->n[3] << 18) & 0x3FFFFFFUL); - r->n[4] = a->n[3] >> 8 | ((a->n[4] << 24) & 0x3FFFFFFUL); - r->n[5] = (a->n[4] >> 2) & 0x3FFFFFFUL; - r->n[6] = a->n[4] >> 28 | ((a->n[5] << 4) & 0x3FFFFFFUL); - r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL); - r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL); - r->n[9] = a->n[7] >> 10; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; -#endif -} - -#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h deleted file mode 100644 index bccd8feb4d..0000000000 --- a/src/secp256k1/src/field_5x52.h +++ /dev/null @@ -1,47 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_FIELD_REPR_H -#define SECP256K1_FIELD_REPR_H - -#include - -typedef struct { - /* X = sum(i=0..4, elem[i]*2^52) mod n */ - uint64_t n[5]; -#ifdef VERIFY - int magnitude; - int normalized; -#endif -} secp256k1_fe; - -/* Unpacks a constant into a overlapping multi-limbed FE element. */ -#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ - (d0) | (((uint64_t)(d1) & 0xFFFFFUL) << 32), \ - ((uint64_t)(d1) >> 20) | (((uint64_t)(d2)) << 12) | (((uint64_t)(d3) & 0xFFUL) << 44), \ - ((uint64_t)(d3) >> 8) | (((uint64_t)(d4) & 0xFFFFFFFUL) << 24), \ - ((uint64_t)(d4) >> 28) | (((uint64_t)(d5)) << 4) | (((uint64_t)(d6) & 0xFFFFUL) << 36), \ - ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \ -} - -#ifdef VERIFY -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} -#else -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} -#endif - -typedef struct { - uint64_t n[4]; -} secp256k1_fe_storage; - -#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \ - (d0) | (((uint64_t)(d1)) << 32), \ - (d2) | (((uint64_t)(d3)) << 32), \ - (d4) | (((uint64_t)(d5)) << 32), \ - (d6) | (((uint64_t)(d7)) << 32) \ -}} - -#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/src/secp256k1/src/field_5x52_asm_impl.h b/src/secp256k1/src/field_5x52_asm_impl.h deleted file mode 100644 index 1fc3171f6b..0000000000 --- a/src/secp256k1/src/field_5x52_asm_impl.h +++ /dev/null @@ -1,502 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -/** - * Changelog: - * - March 2013, Diederik Huys: original version - * - November 2014, Pieter Wuille: updated to use Peter Dettman's parallel multiplication algorithm - * - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly - */ - -#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H -#define SECP256K1_FIELD_INNER5X52_IMPL_H - -SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { -/** - * Registers: rdx:rax = multiplication accumulator - * r9:r8 = c - * r15:rcx = d - * r10-r14 = a0-a4 - * rbx = b - * rdi = r - * rsi = a / t? - */ - uint64_t tmp1, tmp2, tmp3; -__asm__ __volatile__( - "movq 0(%%rsi),%%r10\n" - "movq 8(%%rsi),%%r11\n" - "movq 16(%%rsi),%%r12\n" - "movq 24(%%rsi),%%r13\n" - "movq 32(%%rsi),%%r14\n" - - /* d += a3 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r13\n" - "movq %%rax,%%rcx\n" - "movq %%rdx,%%r15\n" - /* d += a2 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a1 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d = a0 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c = a4 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r14\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += (c & M) * R */ - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* t3 (tmp1) = d & M */ - "movq %%rcx,%%rsi\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rsi\n" - "movq %%rsi,%q1\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* d += a4 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a2 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a1 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a0 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += c * R */ - "movq %%r8,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* t4 = d & M (%%rsi) */ - "movq %%rcx,%%rsi\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* tx = t4 >> 48 (tmp3) */ - "movq %%rsi,%%rax\n" - "shrq $48,%%rax\n" - "movq %%rax,%q3\n" - /* t4 &= (M >> 4) (tmp2) */ - "movq $0xffffffffffff,%%rax\n" - "andq %%rax,%%rsi\n" - "movq %%rsi,%q2\n" - /* c = a0 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r10\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += a4 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a2 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a1 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* u0 = d & M (%%rsi) */ - "movq %%rcx,%%rsi\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* u0 = (u0 << 4) | tx (%%rsi) */ - "shlq $4,%%rsi\n" - "movq %q3,%%rax\n" - "orq %%rax,%%rsi\n" - /* c += u0 * (R >> 4) */ - "movq $0x1000003d1,%%rax\n" - "mulq %%rsi\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[0] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,0(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += a1 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* c += a0 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d += a4 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a2 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c += (d & M) * R */ - "movq %%rcx,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* r[1] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,8(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += a2 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* c += a1 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* c += a0 * b2 (last use of %%r10 = a0) */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* fetch t3 (%%r10, overwrites a0), t4 (%%rsi) */ - "movq %q2,%%rsi\n" - "movq %q1,%%r10\n" - /* d += a4 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c += (d & M) * R */ - "movq %%rcx,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 (%%rcx only) */ - "shrdq $52,%%r15,%%rcx\n" - /* r[2] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,16(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += t3 */ - "addq %%r10,%%r8\n" - /* c += d * R */ - "movq %%rcx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[3] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,24(%%rdi)\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* c += t4 (%%r8 only) */ - "addq %%rsi,%%r8\n" - /* r[4] = c */ - "movq %%r8,32(%%rdi)\n" -: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) -: "b"(b), "D"(r) -: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" -); -} - -SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { -/** - * Registers: rdx:rax = multiplication accumulator - * r9:r8 = c - * rcx:rbx = d - * r10-r14 = a0-a4 - * r15 = M (0xfffffffffffff) - * rdi = r - * rsi = a / t? - */ - uint64_t tmp1, tmp2, tmp3; -__asm__ __volatile__( - "movq 0(%%rsi),%%r10\n" - "movq 8(%%rsi),%%r11\n" - "movq 16(%%rsi),%%r12\n" - "movq 24(%%rsi),%%r13\n" - "movq 32(%%rsi),%%r14\n" - "movq $0xfffffffffffff,%%r15\n" - - /* d = (a0*2) * a3 */ - "leaq (%%r10,%%r10,1),%%rax\n" - "mulq %%r13\n" - "movq %%rax,%%rbx\n" - "movq %%rdx,%%rcx\n" - /* d += (a1*2) * a2 */ - "leaq (%%r11,%%r11,1),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c = a4 * a4 */ - "movq %%r14,%%rax\n" - "mulq %%r14\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += (c & M) * R */ - "andq %%r15,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* t3 (tmp1) = d & M */ - "movq %%rbx,%%rsi\n" - "andq %%r15,%%rsi\n" - "movq %%rsi,%q1\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* a4 *= 2 */ - "addq %%r14,%%r14\n" - /* d += a0 * a4 */ - "movq %%r10,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d+= (a1*2) * a3 */ - "leaq (%%r11,%%r11,1),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += a2 * a2 */ - "movq %%r12,%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += c * R */ - "movq %%r8,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* t4 = d & M (%%rsi) */ - "movq %%rbx,%%rsi\n" - "andq %%r15,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* tx = t4 >> 48 (tmp3) */ - "movq %%rsi,%%rax\n" - "shrq $48,%%rax\n" - "movq %%rax,%q3\n" - /* t4 &= (M >> 4) (tmp2) */ - "movq $0xffffffffffff,%%rax\n" - "andq %%rax,%%rsi\n" - "movq %%rsi,%q2\n" - /* c = a0 * a0 */ - "movq %%r10,%%rax\n" - "mulq %%r10\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += a1 * a4 */ - "movq %%r11,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += (a2*2) * a3 */ - "leaq (%%r12,%%r12,1),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* u0 = d & M (%%rsi) */ - "movq %%rbx,%%rsi\n" - "andq %%r15,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* u0 = (u0 << 4) | tx (%%rsi) */ - "shlq $4,%%rsi\n" - "movq %q3,%%rax\n" - "orq %%rax,%%rsi\n" - /* c += u0 * (R >> 4) */ - "movq $0x1000003d1,%%rax\n" - "mulq %%rsi\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[0] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,0(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* a0 *= 2 */ - "addq %%r10,%%r10\n" - /* c += a0 * a1 */ - "movq %%r10,%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d += a2 * a4 */ - "movq %%r12,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += a3 * a3 */ - "movq %%r13,%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c += (d & M) * R */ - "movq %%rbx,%%rax\n" - "andq %%r15,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* r[1] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,8(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += a0 * a2 (last use of %%r10) */ - "movq %%r10,%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* fetch t3 (%%r10, overwrites a0),t4 (%%rsi) */ - "movq %q2,%%rsi\n" - "movq %q1,%%r10\n" - /* c += a1 * a1 */ - "movq %%r11,%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d += a3 * a4 */ - "movq %%r13,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c += (d & M) * R */ - "movq %%rbx,%%rax\n" - "andq %%r15,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 (%%rbx only) */ - "shrdq $52,%%rcx,%%rbx\n" - /* r[2] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,16(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += t3 */ - "addq %%r10,%%r8\n" - /* c += d * R */ - "movq %%rbx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[3] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,24(%%rdi)\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* c += t4 (%%r8 only) */ - "addq %%rsi,%%r8\n" - /* r[4] = c */ - "movq %%r8,32(%%rdi)\n" -: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) -: "D"(r) -: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" -); -} - -#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h deleted file mode 100644 index 957c61b014..0000000000 --- a/src/secp256k1/src/field_5x52_impl.h +++ /dev/null @@ -1,496 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_FIELD_REPR_IMPL_H -#define SECP256K1_FIELD_REPR_IMPL_H - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#include "util.h" -#include "num.h" -#include "field.h" - -#if defined(USE_ASM_X86_64) -#include "field_5x52_asm_impl.h" -#else -#include "field_5x52_int128_impl.h" -#endif - -/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, - * represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular, - * each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element - * is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations - * accept any input with magnitude at most M, and have different rules for propagating magnitude to their - * output. - */ - -#ifdef VERIFY -static void secp256k1_fe_verify(const secp256k1_fe *a) { - const uint64_t *d = a->n; - int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; - /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ - r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m); - r &= (a->magnitude >= 0); - r &= (a->magnitude <= 2048); - if (a->normalized) { - r &= (a->magnitude <= 1); - if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { - r &= (d[0] < 0xFFFFEFFFFFC2FULL); - } - } - VERIFY_CHECK(r == 1); -} -#endif - -static void secp256k1_fe_normalize(secp256k1_fe *r) { - uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; - - /* Reduce t4 at the start so there will be at most a single carry from the first pass */ - uint64_t m; - uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x1000003D1ULL; - t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3; - - /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t4 >> 49 == 0); - - /* At most a single final reduction is needed; check if the value is >= the field characteristic */ - x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL) - & (t0 >= 0xFFFFEFFFFFC2FULL)); - - /* Apply the final reduction (for constant-time behaviour, we do it always) */ - t0 += x * 0x1000003D1ULL; - t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; - - /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */ - VERIFY_CHECK(t4 >> 48 == x); - - /* Mask off the possible multiple of 2^256 from the final reduction */ - t4 &= 0x0FFFFFFFFFFFFULL; - - r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif -} - -static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { - uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; - - /* Reduce t4 at the start so there will be at most a single carry from the first pass */ - uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x1000003D1ULL; - t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; - - /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t4 >> 49 == 0); - - r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - secp256k1_fe_verify(r); -#endif -} - -static void secp256k1_fe_normalize_var(secp256k1_fe *r) { - uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; - - /* Reduce t4 at the start so there will be at most a single carry from the first pass */ - uint64_t m; - uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x1000003D1ULL; - t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3; - - /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t4 >> 49 == 0); - - /* At most a single final reduction is needed; check if the value is >= the field characteristic */ - x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL) - & (t0 >= 0xFFFFEFFFFFC2FULL)); - - if (x) { - t0 += 0x1000003D1ULL; - t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; - - /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */ - VERIFY_CHECK(t4 >> 48 == x); - - /* Mask off the possible multiple of 2^256 from the final reduction */ - t4 &= 0x0FFFFFFFFFFFFULL; - } - - r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif -} - -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { - uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; - - /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ - uint64_t z0, z1; - - /* Reduce t4 at the start so there will be at most a single carry from the first pass */ - uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x1000003D1ULL; - t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; z0 = t0; z1 = t0 ^ 0x1000003D0ULL; - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; - z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; - - /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t4 >> 49 == 0); - - return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); -} - -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { - uint64_t t0, t1, t2, t3, t4; - uint64_t z0, z1; - uint64_t x; - - t0 = r->n[0]; - t4 = r->n[4]; - - /* Reduce t4 at the start so there will be at most a single carry from the first pass */ - x = t4 >> 48; - - /* The first pass ensures the magnitude is 1, ... */ - t0 += x * 0x1000003D1ULL; - - /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ - z0 = t0 & 0xFFFFFFFFFFFFFULL; - z1 = z0 ^ 0x1000003D0ULL; - - /* Fast return path should catch the majority of cases */ - if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL)) { - return 0; - } - - t1 = r->n[1]; - t2 = r->n[2]; - t3 = r->n[3]; - - t4 &= 0x0FFFFFFFFFFFFULL; - - t1 += (t0 >> 52); - t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; - t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; - t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; - z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; - - /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ - VERIFY_CHECK(t4 >> 49 == 0); - - return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); -} - -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { - r->n[0] = a; - r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif -} - -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { - const uint64_t *t = a->n; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif - return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; -} - -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif - return a->n[0] & 1; -} - -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { - int i; -#ifdef VERIFY - a->magnitude = 0; - a->normalized = 1; -#endif - for (i=0; i<5; i++) { - a->n[i] = 0; - } -} - -static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { - int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); -#endif - for (i = 4; i >= 0; i--) { - if (a->n[i] > b->n[i]) { - return 1; - } - if (a->n[i] < b->n[i]) { - return -1; - } - } - return 0; -} - -static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { - r->n[0] = (uint64_t)a[31] - | ((uint64_t)a[30] << 8) - | ((uint64_t)a[29] << 16) - | ((uint64_t)a[28] << 24) - | ((uint64_t)a[27] << 32) - | ((uint64_t)a[26] << 40) - | ((uint64_t)(a[25] & 0xF) << 48); - r->n[1] = (uint64_t)((a[25] >> 4) & 0xF) - | ((uint64_t)a[24] << 4) - | ((uint64_t)a[23] << 12) - | ((uint64_t)a[22] << 20) - | ((uint64_t)a[21] << 28) - | ((uint64_t)a[20] << 36) - | ((uint64_t)a[19] << 44); - r->n[2] = (uint64_t)a[18] - | ((uint64_t)a[17] << 8) - | ((uint64_t)a[16] << 16) - | ((uint64_t)a[15] << 24) - | ((uint64_t)a[14] << 32) - | ((uint64_t)a[13] << 40) - | ((uint64_t)(a[12] & 0xF) << 48); - r->n[3] = (uint64_t)((a[12] >> 4) & 0xF) - | ((uint64_t)a[11] << 4) - | ((uint64_t)a[10] << 12) - | ((uint64_t)a[9] << 20) - | ((uint64_t)a[8] << 28) - | ((uint64_t)a[7] << 36) - | ((uint64_t)a[6] << 44); - r->n[4] = (uint64_t)a[5] - | ((uint64_t)a[4] << 8) - | ((uint64_t)a[3] << 16) - | ((uint64_t)a[2] << 24) - | ((uint64_t)a[1] << 32) - | ((uint64_t)a[0] << 40); - if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) { - return 0; - } -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif - return 1; -} - -/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif - r[0] = (a->n[4] >> 40) & 0xFF; - r[1] = (a->n[4] >> 32) & 0xFF; - r[2] = (a->n[4] >> 24) & 0xFF; - r[3] = (a->n[4] >> 16) & 0xFF; - r[4] = (a->n[4] >> 8) & 0xFF; - r[5] = a->n[4] & 0xFF; - r[6] = (a->n[3] >> 44) & 0xFF; - r[7] = (a->n[3] >> 36) & 0xFF; - r[8] = (a->n[3] >> 28) & 0xFF; - r[9] = (a->n[3] >> 20) & 0xFF; - r[10] = (a->n[3] >> 12) & 0xFF; - r[11] = (a->n[3] >> 4) & 0xFF; - r[12] = ((a->n[2] >> 48) & 0xF) | ((a->n[3] & 0xF) << 4); - r[13] = (a->n[2] >> 40) & 0xFF; - r[14] = (a->n[2] >> 32) & 0xFF; - r[15] = (a->n[2] >> 24) & 0xFF; - r[16] = (a->n[2] >> 16) & 0xFF; - r[17] = (a->n[2] >> 8) & 0xFF; - r[18] = a->n[2] & 0xFF; - r[19] = (a->n[1] >> 44) & 0xFF; - r[20] = (a->n[1] >> 36) & 0xFF; - r[21] = (a->n[1] >> 28) & 0xFF; - r[22] = (a->n[1] >> 20) & 0xFF; - r[23] = (a->n[1] >> 12) & 0xFF; - r[24] = (a->n[1] >> 4) & 0xFF; - r[25] = ((a->n[0] >> 48) & 0xF) | ((a->n[1] & 0xF) << 4); - r[26] = (a->n[0] >> 40) & 0xFF; - r[27] = (a->n[0] >> 32) & 0xFF; - r[28] = (a->n[0] >> 24) & 0xFF; - r[29] = (a->n[0] >> 16) & 0xFF; - r[30] = (a->n[0] >> 8) & 0xFF; - r[31] = a->n[0] & 0xFF; -} - -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= m); - secp256k1_fe_verify(a); -#endif - r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0]; - r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1]; - r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2]; - r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3]; - r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4]; -#ifdef VERIFY - r->magnitude = m + 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif -} - -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { - r->n[0] *= a; - r->n[1] *= a; - r->n[2] *= a; - r->n[3] *= a; - r->n[4] *= a; -#ifdef VERIFY - r->magnitude *= a; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif -} - -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - secp256k1_fe_verify(a); -#endif - r->n[0] += a->n[0]; - r->n[1] += a->n[1]; - r->n[2] += a->n[2]; - r->n[3] += a->n[3]; - r->n[4] += a->n[4]; -#ifdef VERIFY - r->magnitude += a->magnitude; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif -} - -static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - VERIFY_CHECK(b->magnitude <= 8); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); - VERIFY_CHECK(r != b); -#endif - secp256k1_fe_mul_inner(r->n, a->n, b->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif -} - -static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - secp256k1_fe_verify(a); -#endif - secp256k1_fe_sqr_inner(r->n, a->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif -} - -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { - uint64_t mask0, mask1; - mask0 = flag + ~((uint64_t)0); - mask1 = ~mask0; - r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); - r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); - r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); - r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); - r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); -#ifdef VERIFY - if (a->magnitude > r->magnitude) { - r->magnitude = a->magnitude; - } - r->normalized &= a->normalized; -#endif -} - -static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { - uint64_t mask0, mask1; - mask0 = flag + ~((uint64_t)0); - mask1 = ~mask0; - r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); - r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); - r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); - r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); -} - -static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif - r->n[0] = a->n[0] | a->n[1] << 52; - r->n[1] = a->n[1] >> 12 | a->n[2] << 40; - r->n[2] = a->n[2] >> 24 | a->n[3] << 28; - r->n[3] = a->n[3] >> 36 | a->n[4] << 16; -} - -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { - r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL; - r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL); - r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL); - r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL); - r->n[4] = a->n[3] >> 16; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; -#endif -} - -#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h deleted file mode 100644 index 95a0d1791c..0000000000 --- a/src/secp256k1/src/field_5x52_int128_impl.h +++ /dev/null @@ -1,277 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H -#define SECP256K1_FIELD_INNER5X52_IMPL_H - -#include - -#ifdef VERIFY -#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) -#else -#define VERIFY_BITS(x, n) do { } while(0) -#endif - -SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { - uint128_t c, d; - uint64_t t3, t4, tx, u0; - uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; - const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; - - VERIFY_BITS(a[0], 56); - VERIFY_BITS(a[1], 56); - VERIFY_BITS(a[2], 56); - VERIFY_BITS(a[3], 56); - VERIFY_BITS(a[4], 52); - VERIFY_BITS(b[0], 56); - VERIFY_BITS(b[1], 56); - VERIFY_BITS(b[2], 56); - VERIFY_BITS(b[3], 56); - VERIFY_BITS(b[4], 52); - VERIFY_CHECK(r != b); - - /* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. - * px is a shorthand for sum(a[i]*b[x-i], i=0..x). - * Note that [x 0 0 0 0 0] = [x*R]. - */ - - d = (uint128_t)a0 * b[3] - + (uint128_t)a1 * b[2] - + (uint128_t)a2 * b[1] - + (uint128_t)a3 * b[0]; - VERIFY_BITS(d, 114); - /* [d 0 0 0] = [p3 0 0 0] */ - c = (uint128_t)a4 * b[4]; - VERIFY_BITS(c, 112); - /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - d += (c & M) * R; c >>= 52; - VERIFY_BITS(d, 115); - VERIFY_BITS(c, 60); - /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - t3 = d & M; d >>= 52; - VERIFY_BITS(t3, 52); - VERIFY_BITS(d, 63); - /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - - d += (uint128_t)a0 * b[4] - + (uint128_t)a1 * b[3] - + (uint128_t)a2 * b[2] - + (uint128_t)a3 * b[1] - + (uint128_t)a4 * b[0]; - VERIFY_BITS(d, 115); - /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - d += c * R; - VERIFY_BITS(d, 116); - /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - t4 = d & M; d >>= 52; - VERIFY_BITS(t4, 52); - VERIFY_BITS(d, 64); - /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - tx = (t4 >> 48); t4 &= (M >> 4); - VERIFY_BITS(tx, 4); - VERIFY_BITS(t4, 48); - /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - - c = (uint128_t)a0 * b[0]; - VERIFY_BITS(c, 112); - /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ - d += (uint128_t)a1 * b[4] - + (uint128_t)a2 * b[3] - + (uint128_t)a3 * b[2] - + (uint128_t)a4 * b[1]; - VERIFY_BITS(d, 115); - /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = d & M; d >>= 52; - VERIFY_BITS(u0, 52); - VERIFY_BITS(d, 63); - /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = (u0 << 4) | tx; - VERIFY_BITS(u0, 56); - /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - c += (uint128_t)u0 * (R >> 4); - VERIFY_BITS(c, 115); - /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - r[0] = c & M; c >>= 52; - VERIFY_BITS(r[0], 52); - VERIFY_BITS(c, 61); - /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ - - c += (uint128_t)a0 * b[1] - + (uint128_t)a1 * b[0]; - VERIFY_BITS(c, 114); - /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ - d += (uint128_t)a2 * b[4] - + (uint128_t)a3 * b[3] - + (uint128_t)a4 * b[2]; - VERIFY_BITS(d, 114); - /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (d & M) * R; d >>= 52; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 62); - /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - r[1] = c & M; c >>= 52; - VERIFY_BITS(r[1], 52); - VERIFY_BITS(c, 63); - /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - - c += (uint128_t)a0 * b[2] - + (uint128_t)a1 * b[1] - + (uint128_t)a2 * b[0]; - VERIFY_BITS(c, 114); - /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint128_t)a3 * b[4] - + (uint128_t)a4 * b[3]; - VERIFY_BITS(d, 114); - /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += (d & M) * R; d >>= 52; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 62); - /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - - /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[2] = c & M; c >>= 52; - 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; - VERIFY_BITS(c, 100); - /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[3] = c & M; c >>= 52; - VERIFY_BITS(r[3], 52); - VERIFY_BITS(c, 48); - /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += t4; - VERIFY_BITS(c, 49); - /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = c; - VERIFY_BITS(r[4], 49); - /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ -} - -SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { - uint128_t c, d; - uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; - int64_t t3, t4, tx, u0; - const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; - - VERIFY_BITS(a[0], 56); - VERIFY_BITS(a[1], 56); - VERIFY_BITS(a[2], 56); - VERIFY_BITS(a[3], 56); - VERIFY_BITS(a[4], 52); - - /** [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. - * px is a shorthand for sum(a[i]*a[x-i], i=0..x). - * Note that [x 0 0 0 0 0] = [x*R]. - */ - - d = (uint128_t)(a0*2) * a3 - + (uint128_t)(a1*2) * a2; - VERIFY_BITS(d, 114); - /* [d 0 0 0] = [p3 0 0 0] */ - c = (uint128_t)a4 * a4; - VERIFY_BITS(c, 112); - /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - d += (c & M) * R; c >>= 52; - VERIFY_BITS(d, 115); - VERIFY_BITS(c, 60); - /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - t3 = d & M; d >>= 52; - VERIFY_BITS(t3, 52); - VERIFY_BITS(d, 63); - /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ - - a4 *= 2; - d += (uint128_t)a0 * a4 - + (uint128_t)(a1*2) * a3 - + (uint128_t)a2 * a2; - VERIFY_BITS(d, 115); - /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - d += c * R; - VERIFY_BITS(d, 116); - /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - t4 = d & M; d >>= 52; - VERIFY_BITS(t4, 52); - VERIFY_BITS(d, 64); - /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - tx = (t4 >> 48); t4 &= (M >> 4); - VERIFY_BITS(tx, 4); - VERIFY_BITS(t4, 48); - /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ - - c = (uint128_t)a0 * a0; - VERIFY_BITS(c, 112); - /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ - d += (uint128_t)a1 * a4 - + (uint128_t)(a2*2) * a3; - VERIFY_BITS(d, 114); - /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = d & M; d >>= 52; - VERIFY_BITS(u0, 52); - VERIFY_BITS(d, 62); - /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - u0 = (u0 << 4) | tx; - VERIFY_BITS(u0, 56); - /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - c += (uint128_t)u0 * (R >> 4); - VERIFY_BITS(c, 113); - /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ - r[0] = c & M; c >>= 52; - VERIFY_BITS(r[0], 52); - VERIFY_BITS(c, 61); - /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ - - a0 *= 2; - c += (uint128_t)a0 * a1; - VERIFY_BITS(c, 114); - /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ - d += (uint128_t)a2 * a4 - + (uint128_t)a3 * a3; - VERIFY_BITS(d, 114); - /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - c += (d & M) * R; d >>= 52; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 62); - /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - r[1] = c & M; c >>= 52; - VERIFY_BITS(r[1], 52); - VERIFY_BITS(c, 63); - /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ - - c += (uint128_t)a0 * a2 - + (uint128_t)a1 * a1; - VERIFY_BITS(c, 114); - /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ - d += (uint128_t)a3 * a4; - VERIFY_BITS(d, 114); - /* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += (d & M) * R; d >>= 52; - VERIFY_BITS(c, 115); - VERIFY_BITS(d, 62); - /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[2] = c & M; c >>= 52; - 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; - VERIFY_BITS(c, 100); - /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[3] = c & M; c >>= 52; - VERIFY_BITS(r[3], 52); - VERIFY_BITS(c, 48); - /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += t4; - VERIFY_BITS(c, 49); - /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - r[4] = c; - VERIFY_BITS(r[4], 49); - /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ -} - -#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h deleted file mode 100644 index 20428648af..0000000000 --- a/src/secp256k1/src/field_impl.h +++ /dev/null @@ -1,315 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_FIELD_IMPL_H -#define SECP256K1_FIELD_IMPL_H - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#include "util.h" - -#if defined(USE_FIELD_10X26) -#include "field_10x26_impl.h" -#elif defined(USE_FIELD_5X52) -#include "field_5x52_impl.h" -#else -#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); - secp256k1_fe_add(&na, b); - return secp256k1_fe_normalizes_to_zero_var(&na); -} - -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. - * - * As (p+1)/4 is an even number, it will have the same result for a and for - * (-a). Only one of these two numbers actually has a square root however, - * so we test at the end by squaring and comparing to the input. - * Also because (p+1)/4 is an even number, the computed square root is - * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). - */ - secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; - int j; - - /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in - * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: - * 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] - */ - - secp256k1_fe_sqr(&x2, a); - secp256k1_fe_mul(&x2, &x2, a); - - secp256k1_fe_sqr(&x3, &x2); - secp256k1_fe_mul(&x3, &x3, a); - - x6 = x3; - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&x6, &x6); - } - secp256k1_fe_mul(&x6, &x6, &x3); - - x9 = x6; - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&x9, &x9); - } - secp256k1_fe_mul(&x9, &x9, &x3); - - x11 = x9; - for (j=0; j<2; j++) { - secp256k1_fe_sqr(&x11, &x11); - } - secp256k1_fe_mul(&x11, &x11, &x2); - - x22 = x11; - for (j=0; j<11; j++) { - secp256k1_fe_sqr(&x22, &x22); - } - secp256k1_fe_mul(&x22, &x22, &x11); - - x44 = x22; - for (j=0; j<22; j++) { - secp256k1_fe_sqr(&x44, &x44); - } - secp256k1_fe_mul(&x44, &x44, &x22); - - x88 = x44; - for (j=0; j<44; j++) { - secp256k1_fe_sqr(&x88, &x88); - } - secp256k1_fe_mul(&x88, &x88, &x44); - - x176 = x88; - for (j=0; j<88; j++) { - secp256k1_fe_sqr(&x176, &x176); - } - secp256k1_fe_mul(&x176, &x176, &x88); - - x220 = x176; - for (j=0; j<44; j++) { - secp256k1_fe_sqr(&x220, &x220); - } - secp256k1_fe_mul(&x220, &x220, &x44); - - x223 = x220; - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&x223, &x223); - } - secp256k1_fe_mul(&x223, &x223, &x3); - - /* The final result is then assembled using a sliding window over the blocks. */ - - t1 = x223; - for (j=0; j<23; j++) { - secp256k1_fe_sqr(&t1, &t1); - } - secp256k1_fe_mul(&t1, &t1, &x22); - for (j=0; j<6; j++) { - secp256k1_fe_sqr(&t1, &t1); - } - secp256k1_fe_mul(&t1, &t1, &x2); - secp256k1_fe_sqr(&t1, &t1); - secp256k1_fe_sqr(r, &t1); - - /* Check that a square root was actually calculated */ - - secp256k1_fe_sqr(&t1, r); - return secp256k1_fe_equal(&t1, a); -} - -static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) { - secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; - int j; - - /** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in - * { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: - * [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] - */ - - secp256k1_fe_sqr(&x2, a); - secp256k1_fe_mul(&x2, &x2, a); - - secp256k1_fe_sqr(&x3, &x2); - secp256k1_fe_mul(&x3, &x3, a); - - x6 = x3; - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&x6, &x6); - } - secp256k1_fe_mul(&x6, &x6, &x3); - - x9 = x6; - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&x9, &x9); - } - secp256k1_fe_mul(&x9, &x9, &x3); - - x11 = x9; - for (j=0; j<2; j++) { - secp256k1_fe_sqr(&x11, &x11); - } - secp256k1_fe_mul(&x11, &x11, &x2); - - x22 = x11; - for (j=0; j<11; j++) { - secp256k1_fe_sqr(&x22, &x22); - } - secp256k1_fe_mul(&x22, &x22, &x11); - - x44 = x22; - for (j=0; j<22; j++) { - secp256k1_fe_sqr(&x44, &x44); - } - secp256k1_fe_mul(&x44, &x44, &x22); - - x88 = x44; - for (j=0; j<44; j++) { - secp256k1_fe_sqr(&x88, &x88); - } - secp256k1_fe_mul(&x88, &x88, &x44); - - x176 = x88; - for (j=0; j<88; j++) { - secp256k1_fe_sqr(&x176, &x176); - } - secp256k1_fe_mul(&x176, &x176, &x88); - - x220 = x176; - for (j=0; j<44; j++) { - secp256k1_fe_sqr(&x220, &x220); - } - secp256k1_fe_mul(&x220, &x220, &x44); - - x223 = x220; - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&x223, &x223); - } - secp256k1_fe_mul(&x223, &x223, &x3); - - /* The final result is then assembled using a sliding window over the blocks. */ - - t1 = x223; - for (j=0; j<23; j++) { - secp256k1_fe_sqr(&t1, &t1); - } - secp256k1_fe_mul(&t1, &t1, &x22); - for (j=0; j<5; j++) { - secp256k1_fe_sqr(&t1, &t1); - } - secp256k1_fe_mul(&t1, &t1, a); - for (j=0; j<3; j++) { - secp256k1_fe_sqr(&t1, &t1); - } - secp256k1_fe_mul(&t1, &t1, &x2); - for (j=0; j<2; j++) { - secp256k1_fe_sqr(&t1, &t1); - } - secp256k1_fe_mul(r, a, &t1); -} - -static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) { -#if defined(USE_FIELD_INV_BUILTIN) - secp256k1_fe_inv(r, a); -#elif defined(USE_FIELD_INV_NUM) - secp256k1_num n, m; - static const secp256k1_fe negone = SECP256K1_FE_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xFFFFFC2EUL - ); - /* 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 - }; - unsigned char b[32]; - int res; - 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); - secp256k1_num_mod_inverse(&n, &n, &m); - secp256k1_num_get_bin(b, 32, &n); - res = secp256k1_fe_set_b32(r, b); - (void)res; - VERIFY_CHECK(res); - /* Verify the result is the (unique) valid inverse using non-GMP code. */ - secp256k1_fe_mul(&c, &c, r); - secp256k1_fe_add(&c, &negone); - CHECK(secp256k1_fe_normalizes_to_zero_var(&c)); -#else -#error "Please select field inverse implementation" -#endif -} - -static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len) { - secp256k1_fe u; - size_t i; - if (len < 1) { - return; - } - - VERIFY_CHECK((r + len <= a) || (a + len <= r)); - - r[0] = a[0]; - - i = 0; - while (++i < len) { - secp256k1_fe_mul(&r[i], &r[i - 1], &a[i]); - } - - secp256k1_fe_inv_var(&u, &r[--i]); - - while (i > 0) { - size_t j = i--; - secp256k1_fe_mul(&r[j], &r[i], &u); - secp256k1_fe_mul(&u, &u, &a[j]); - } - - 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 /* SECP256K1_FIELD_IMPL_H */ diff --git a/src/secp256k1/src/gen_context.c b/src/secp256k1/src/gen_context.c deleted file mode 100644 index 1835fd491d..0000000000 --- a/src/secp256k1/src/gen_context.c +++ /dev/null @@ -1,74 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#define USE_BASIC_CONFIG 1 - -#include "basic-config.h" -#include "include/secp256k1.h" -#include "field_impl.h" -#include "scalar_impl.h" -#include "group_impl.h" -#include "ecmult_gen_impl.h" - -static void default_error_callback_fn(const char* str, void* data) { - (void)data; - fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); - abort(); -} - -static const secp256k1_callback default_error_callback = { - default_error_callback_fn, - NULL -}; - -int main(int argc, char **argv) { - secp256k1_ecmult_gen_context ctx; - int inner; - int outer; - FILE* fp; - - (void)argc; - (void)argv; - - fp = fopen("src/ecmult_static_context.h","w"); - if (fp == NULL) { - fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n"); - return -1; - } - - fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); - fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); - fprintf(fp, "#include \"group.h\"\n"); - fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n"); - fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n"); - - secp256k1_ecmult_gen_context_init(&ctx); - secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback); - for(outer = 0; outer != 64; outer++) { - fprintf(fp,"{\n"); - for(inner = 0; inner != 16; inner++) { - fprintf(fp," SC(%uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu)", SECP256K1_GE_STORAGE_CONST_GET((*ctx.prec)[outer][inner])); - if (inner != 15) { - fprintf(fp,",\n"); - } else { - fprintf(fp,"\n"); - } - } - if (outer != 63) { - fprintf(fp,"},\n"); - } else { - fprintf(fp,"}\n"); - } - } - fprintf(fp,"};\n"); - secp256k1_ecmult_gen_context_clear(&ctx); - - fprintf(fp, "#undef SC\n"); - fprintf(fp, "#endif\n"); - fclose(fp); - - return 0; -} diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h deleted file mode 100644 index ea1302deb8..0000000000 --- a/src/secp256k1/src/group.h +++ /dev/null @@ -1,144 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_GROUP_H -#define SECP256K1_GROUP_H - -#include "num.h" -#include "field.h" - -/** A group element of the secp256k1 curve, in affine coordinates. */ -typedef struct { - secp256k1_fe x; - secp256k1_fe y; - int infinity; /* whether this represents the point at infinity */ -} secp256k1_ge; - -#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0} -#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} - -/** A group element of the secp256k1 curve, in jacobian coordinates. */ -typedef struct { - secp256k1_fe x; /* actual X: x/z^2 */ - secp256k1_fe y; /* actual Y: y/z^3 */ - secp256k1_fe z; - int infinity; /* whether this represents the point at infinity */ -} secp256k1_gej; - -#define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0} -#define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} - -typedef struct { - secp256k1_fe_storage x; - secp256k1_fe_storage y; -} secp256k1_ge_storage; - -#define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))} - -#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) - -/** Set a group element equal to the point with given X and Y coordinates */ -static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y); - -/** Set a group element (affine) equal to the point with the given X coordinate - * 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(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. */ -static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd); - -/** Check whether a group element is the point at infinity. */ -static int secp256k1_ge_is_infinity(const secp256k1_ge *a); - -/** Check whether a group element is valid (i.e., on the curve). */ -static int secp256k1_ge_is_valid_var(const secp256k1_ge *a); - -static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a); - -/** Set a group element equal to another which is given in jacobian coordinates */ -static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a); - -/** Set a batch of group elements equal to the inputs given in jacobian coordinates */ -static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb); - -/** Set a batch of group elements equal to the inputs given in jacobian - * coordinates (with known z-ratios). zr must contain the known z-ratios such - * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */ -static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len); - -/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to - * the same global z "denominator". zr must contain the known z-ratios such - * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y - * coordinates of the result are stored in r, the common z coordinate is - * stored in globalz. */ -static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr); - -/** Set a group element (jacobian) equal to the point at infinity. */ -static void secp256k1_gej_set_infinity(secp256k1_gej *r); - -/** Set a group element (jacobian) equal to another which is given in affine coordinates. */ -static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a); - -/** Compare the X coordinate of a group element (jacobian). */ -static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a); - -/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ -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); - -/** 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). */ -static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); - -/** Set r equal to the sum of a and b. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */ -static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr); - -/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */ -static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b); - -/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient - than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time - guarantee, and b is allowed to be infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */ -static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr); - -/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */ -static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv); - -#ifdef USE_ENDOMORPHISM -/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ -static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a); -#endif - -/** Clear a secp256k1_gej to prevent leaking sensitive information. */ -static void secp256k1_gej_clear(secp256k1_gej *r); - -/** Clear a secp256k1_ge to prevent leaking sensitive information. */ -static void secp256k1_ge_clear(secp256k1_ge *r); - -/** Convert a group element to the storage type. */ -static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a); - -/** Convert a group element back from the storage type. */ -static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a); - -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ -static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag); - -/** Rescale a jacobian point by b which must be non-zero. Constant-time. */ -static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); - -#endif /* SECP256K1_GROUP_H */ diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h deleted file mode 100644 index b31b6c12ef..0000000000 --- a/src/secp256k1/src/group_impl.h +++ /dev/null @@ -1,700 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_GROUP_IMPL_H -#define SECP256K1_GROUP_IMPL_H - -#include "num.h" -#include "field.h" -#include "group.h" - -/* These points can be generated in sage as follows: - * - * 0. Setup a worksheet with the following parameters. - * b = 4 # whatever CURVE_B will be set to - * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) - * C = EllipticCurve ([F (0), F (b)]) - * - * 1. Determine all the small orders available to you. (If there are - * no satisfactory ones, go back and change b.) - * print C.order().factor(limit=1000) - * - * 2. Choose an order as one of the prime factors listed in the above step. - * (You can also multiply some to get a composite order, though the - * tests will crash trying to invert scalars during signing.) We take a - * random point and scale it to drop its order to the desired value. - * There is some probability this won't work; just try again. - * order = 199 - * P = C.random_point() - * P = (int(P.order()) / int(order)) * P - * assert(P.order() == order) - * - * 3. Print the values. You'll need to use a vim macro or something to - * split the hex output into 4-byte chunks. - * print "%x %x" % P.xy() - */ -#if defined(EXHAUSTIVE_TEST_ORDER) -# if EXHAUSTIVE_TEST_ORDER == 199 -const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( - 0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069, - 0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18, - 0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868, - 0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED -); - -const int CURVE_B = 4; -# elif EXHAUSTIVE_TEST_ORDER == 13 -const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( - 0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0, - 0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15, - 0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e, - 0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac -); -const int CURVE_B = 2; -# else -# error No known generator for the specified exhaustive test group order. -# endif -#else -/** Generator for secp256k1, value 'g' defined in - * "Standards for Efficient Cryptography" (SEC2) 2.7.1. - */ -static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( - 0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL, - 0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL, - 0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL, - 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL -); - -const int CURVE_B = 7; -#endif - -static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { - secp256k1_fe zi2; - secp256k1_fe zi3; - secp256k1_fe_sqr(&zi2, zi); - secp256k1_fe_mul(&zi3, &zi2, zi); - secp256k1_fe_mul(&r->x, &a->x, &zi2); - secp256k1_fe_mul(&r->y, &a->y, &zi3); - r->infinity = a->infinity; -} - -static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) { - r->infinity = 0; - r->x = *x; - r->y = *y; -} - -static int secp256k1_ge_is_infinity(const secp256k1_ge *a) { - return a->infinity; -} - -static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) { - *r = *a; - secp256k1_fe_normalize_weak(&r->y); - secp256k1_fe_negate(&r->y, &r->y, 1); -} - -static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { - secp256k1_fe z2, z3; - r->infinity = a->infinity; - secp256k1_fe_inv(&a->z, &a->z); - secp256k1_fe_sqr(&z2, &a->z); - secp256k1_fe_mul(&z3, &a->z, &z2); - secp256k1_fe_mul(&a->x, &a->x, &z2); - secp256k1_fe_mul(&a->y, &a->y, &z3); - secp256k1_fe_set_int(&a->z, 1); - r->x = a->x; - r->y = a->y; -} - -static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { - secp256k1_fe z2, z3; - r->infinity = a->infinity; - if (a->infinity) { - return; - } - secp256k1_fe_inv_var(&a->z, &a->z); - secp256k1_fe_sqr(&z2, &a->z); - secp256k1_fe_mul(&z3, &a->z, &z2); - secp256k1_fe_mul(&a->x, &a->x, &z2); - secp256k1_fe_mul(&a->y, &a->y, &z3); - secp256k1_fe_set_int(&a->z, 1); - r->x = a->x; - r->y = a->y; -} - -static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb) { - secp256k1_fe *az; - secp256k1_fe *azi; - size_t i; - size_t count = 0; - az = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * len); - for (i = 0; i < len; i++) { - if (!a[i].infinity) { - az[count++] = a[i].z; - } - } - - azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count); - secp256k1_fe_inv_all_var(azi, az, count); - free(az); - - count = 0; - for (i = 0; i < len; i++) { - r[i].infinity = a[i].infinity; - if (!a[i].infinity) { - secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]); - } - } - free(azi); -} - -static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len) { - size_t i = len - 1; - secp256k1_fe zi; - - if (len > 0) { - /* Compute the inverse of the last z coordinate, and use it to compute the last affine output. */ - secp256k1_fe_inv(&zi, &a[i].z); - secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi); - - /* Work out way backwards, using the z-ratios to scale the x/y values. */ - while (i > 0) { - secp256k1_fe_mul(&zi, &zi, &zr[i]); - i--; - secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi); - } - } -} - -static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr) { - size_t i = len - 1; - secp256k1_fe zs; - - if (len > 0) { - /* The z of the final point gives us the "global Z" for the table. */ - r[i].x = a[i].x; - r[i].y = a[i].y; - *globalz = a[i].z; - r[i].infinity = 0; - zs = zr[i]; - - /* Work our way backwards, using the z-ratios to scale the x/y values. */ - while (i > 0) { - if (i != len - 1) { - secp256k1_fe_mul(&zs, &zs, &zr[i]); - } - i--; - secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zs); - } - } -} - -static void secp256k1_gej_set_infinity(secp256k1_gej *r) { - r->infinity = 1; - secp256k1_fe_clear(&r->x); - secp256k1_fe_clear(&r->y); - secp256k1_fe_clear(&r->z); -} - -static void secp256k1_gej_clear(secp256k1_gej *r) { - r->infinity = 0; - secp256k1_fe_clear(&r->x); - secp256k1_fe_clear(&r->y); - secp256k1_fe_clear(&r->z); -} - -static void secp256k1_ge_clear(secp256k1_ge *r) { - r->infinity = 0; - secp256k1_fe_clear(&r->x); - secp256k1_fe_clear(&r->y); -} - -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); - secp256k1_fe_mul(&x3, x, &x2); - r->infinity = 0; - secp256k1_fe_set_int(&c, CURVE_B); - secp256k1_fe_add(&c, &x3); - 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(r, x)) { - return 0; - } - secp256k1_fe_normalize_var(&r->y); - if (secp256k1_fe_is_odd(&r->y) != odd) { - secp256k1_fe_negate(&r->y, &r->y, 1); - } - return 1; - -} - -static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { - r->infinity = a->infinity; - r->x = a->x; - r->y = a->y; - secp256k1_fe_set_int(&r->z, 1); -} - -static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) { - secp256k1_fe r, r2; - VERIFY_CHECK(!a->infinity); - secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); - r2 = a->x; secp256k1_fe_normalize_weak(&r2); - return secp256k1_fe_equal_var(&r, &r2); -} - -static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) { - r->infinity = a->infinity; - r->x = a->x; - r->y = a->y; - r->z = a->z; - secp256k1_fe_normalize_weak(&r->y); - secp256k1_fe_negate(&r->y, &r->y, 1); -} - -static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { - return a->infinity; -} - -static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) { - secp256k1_fe y2, x3, z2, z6; - if (a->infinity) { - return 0; - } - /** y^2 = x^3 + 7 - * (Y/Z^3)^2 = (X/Z^2)^3 + 7 - * Y^2 / Z^6 = X^3 / Z^6 + 7 - * Y^2 = X^3 + 7*Z^6 - */ - secp256k1_fe_sqr(&y2, &a->y); - secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); - secp256k1_fe_sqr(&z2, &a->z); - secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2); - secp256k1_fe_mul_int(&z6, CURVE_B); - secp256k1_fe_add(&x3, &z6); - secp256k1_fe_normalize_weak(&x3); - return secp256k1_fe_equal_var(&y2, &x3); -} - -static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { - secp256k1_fe y2, x3, c; - if (a->infinity) { - return 0; - } - /* y^2 = x^3 + 7 */ - secp256k1_fe_sqr(&y2, &a->y); - secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); - secp256k1_fe_set_int(&c, CURVE_B); - secp256k1_fe_add(&x3, &c); - secp256k1_fe_normalize_weak(&x3); - return secp256k1_fe_equal_var(&y2, &x3); -} - -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. - * - * 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) { - if (rzr != NULL) { - secp256k1_fe_set_int(rzr, 1); - } - return; - } - - if (rzr != NULL) { - *rzr = a->y; - secp256k1_fe_normalize_weak(rzr); - secp256k1_fe_mul_int(rzr, 2); - } - - secp256k1_fe_mul(&r->z, &a->z, &a->y); - secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */ - secp256k1_fe_sqr(&t1, &a->x); - secp256k1_fe_mul_int(&t1, 3); /* T1 = 3*X^2 (3) */ - secp256k1_fe_sqr(&t2, &t1); /* T2 = 9*X^4 (1) */ - secp256k1_fe_sqr(&t3, &a->y); - secp256k1_fe_mul_int(&t3, 2); /* T3 = 2*Y^2 (2) */ - secp256k1_fe_sqr(&t4, &t3); - secp256k1_fe_mul_int(&t4, 2); /* T4 = 8*Y^4 (2) */ - secp256k1_fe_mul(&t3, &t3, &a->x); /* T3 = 2*X*Y^2 (1) */ - r->x = t3; - secp256k1_fe_mul_int(&r->x, 4); /* X' = 8*X*Y^2 (4) */ - secp256k1_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */ - secp256k1_fe_add(&r->x, &t2); /* X' = 9*X^4 - 8*X*Y^2 (6) */ - secp256k1_fe_negate(&t2, &t2, 1); /* T2 = -9*X^4 (2) */ - secp256k1_fe_mul_int(&t3, 6); /* T3 = 12*X*Y^2 (6) */ - secp256k1_fe_add(&t3, &t2); /* T3 = 12*X*Y^2 - 9*X^4 (8) */ - secp256k1_fe_mul(&r->y, &t1, &t3); /* Y' = 36*X^3*Y^2 - 27*X^6 (1) */ - secp256k1_fe_negate(&t2, &t4, 2); /* T2 = -8*Y^4 (3) */ - secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */ -} - -static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { - VERIFY_CHECK(!secp256k1_gej_is_infinity(a)); - secp256k1_gej_double_var(r, a, rzr); -} - -static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) { - /* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */ - secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; - - if (a->infinity) { - VERIFY_CHECK(rzr == NULL); - *r = *b; - return; - } - - if (b->infinity) { - if (rzr != NULL) { - secp256k1_fe_set_int(rzr, 1); - } - *r = *a; - return; - } - - r->infinity = 0; - secp256k1_fe_sqr(&z22, &b->z); - secp256k1_fe_sqr(&z12, &a->z); - secp256k1_fe_mul(&u1, &a->x, &z22); - secp256k1_fe_mul(&u2, &b->x, &z12); - secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z); - secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); - secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); - secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); - if (secp256k1_fe_normalizes_to_zero_var(&h)) { - if (secp256k1_fe_normalizes_to_zero_var(&i)) { - secp256k1_gej_double_var(r, a, rzr); - } else { - if (rzr != NULL) { - secp256k1_fe_set_int(rzr, 0); - } - r->infinity = 1; - } - return; - } - secp256k1_fe_sqr(&i2, &i); - secp256k1_fe_sqr(&h2, &h); - secp256k1_fe_mul(&h3, &h, &h2); - secp256k1_fe_mul(&h, &h, &b->z); - if (rzr != NULL) { - *rzr = h; - } - secp256k1_fe_mul(&r->z, &a->z, &h); - secp256k1_fe_mul(&t, &u1, &h2); - r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); - secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); - secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); - secp256k1_fe_add(&r->y, &h3); -} - -static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) { - /* 8 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ - secp256k1_fe z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; - if (a->infinity) { - VERIFY_CHECK(rzr == NULL); - secp256k1_gej_set_ge(r, b); - return; - } - if (b->infinity) { - if (rzr != NULL) { - secp256k1_fe_set_int(rzr, 1); - } - *r = *a; - return; - } - r->infinity = 0; - - secp256k1_fe_sqr(&z12, &a->z); - u1 = a->x; secp256k1_fe_normalize_weak(&u1); - secp256k1_fe_mul(&u2, &b->x, &z12); - s1 = a->y; secp256k1_fe_normalize_weak(&s1); - secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); - secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); - secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); - if (secp256k1_fe_normalizes_to_zero_var(&h)) { - if (secp256k1_fe_normalizes_to_zero_var(&i)) { - secp256k1_gej_double_var(r, a, rzr); - } else { - if (rzr != NULL) { - secp256k1_fe_set_int(rzr, 0); - } - r->infinity = 1; - } - return; - } - secp256k1_fe_sqr(&i2, &i); - secp256k1_fe_sqr(&h2, &h); - secp256k1_fe_mul(&h3, &h, &h2); - if (rzr != NULL) { - *rzr = h; - } - secp256k1_fe_mul(&r->z, &a->z, &h); - secp256k1_fe_mul(&t, &u1, &h2); - r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); - secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); - secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); - secp256k1_fe_add(&r->y, &h3); -} - -static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) { - /* 9 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ - secp256k1_fe az, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; - - if (b->infinity) { - *r = *a; - return; - } - if (a->infinity) { - secp256k1_fe bzinv2, bzinv3; - r->infinity = b->infinity; - secp256k1_fe_sqr(&bzinv2, bzinv); - secp256k1_fe_mul(&bzinv3, &bzinv2, bzinv); - secp256k1_fe_mul(&r->x, &b->x, &bzinv2); - secp256k1_fe_mul(&r->y, &b->y, &bzinv3); - secp256k1_fe_set_int(&r->z, 1); - return; - } - r->infinity = 0; - - /** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to - * secp256k1's isomorphism we can multiply the Z coordinates on both sides - * by bzinv, and get: (rx,ry,rz*bzinv) = (ax,ay,az*bzinv) + (bx,by,1). - * This means that (rx,ry,rz) can be calculated as - * (ax,ay,az*bzinv) + (bx,by,1), when not applying the bzinv factor to rz. - * The variable az below holds the modified Z coordinate for a, which is used - * for the computation of rx and ry, but not for rz. - */ - secp256k1_fe_mul(&az, &a->z, bzinv); - - secp256k1_fe_sqr(&z12, &az); - u1 = a->x; secp256k1_fe_normalize_weak(&u1); - secp256k1_fe_mul(&u2, &b->x, &z12); - s1 = a->y; secp256k1_fe_normalize_weak(&s1); - secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az); - secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); - secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); - if (secp256k1_fe_normalizes_to_zero_var(&h)) { - if (secp256k1_fe_normalizes_to_zero_var(&i)) { - secp256k1_gej_double_var(r, a, NULL); - } else { - r->infinity = 1; - } - return; - } - secp256k1_fe_sqr(&i2, &i); - secp256k1_fe_sqr(&h2, &h); - secp256k1_fe_mul(&h3, &h, &h2); - r->z = a->z; secp256k1_fe_mul(&r->z, &r->z, &h); - secp256k1_fe_mul(&t, &u1, &h2); - r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); - secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); - secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); - secp256k1_fe_add(&r->y, &h3); -} - - -static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) { - /* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */ - static const secp256k1_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; - secp256k1_fe m_alt, rr_alt; - int infinity, degenerate; - VERIFY_CHECK(!b->infinity); - VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); - - /** In: - * Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks. - * In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002. - * we find as solution for a unified addition/doubling formula: - * lambda = ((x1 + x2)^2 - x1 * x2 + a) / (y1 + y2), with a = 0 for secp256k1's curve equation. - * x3 = lambda^2 - (x1 + x2) - * 2*y3 = lambda * (x1 + x2 - 2 * x3) - (y1 + y2). - * - * Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives: - * U1 = X1*Z2^2, U2 = X2*Z1^2 - * S1 = Y1*Z2^3, S2 = Y2*Z1^3 - * Z = Z1*Z2 - * T = U1+U2 - * M = S1+S2 - * Q = T*M^2 - * R = T^2-U1*U2 - * X3 = 4*(R^2-Q) - * Y3 = 4*(R*(3*Q-2*R^2)-M^4) - * Z3 = 2*M*Z - * (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.) - * - * This formula has the benefit of being the same for both addition - * of distinct points and doubling. However, it breaks down in the - * case that either point is infinity, or that y1 = -y2. We handle - * these cases in the following ways: - * - * - If b is infinity we simply bail by means of a VERIFY_CHECK. - * - * - If a is infinity, we detect this, and at the end of the - * computation replace the result (which will be meaningless, - * but we compute to be constant-time) with b.x : b.y : 1. - * - * - If a = -b, we have y1 = -y2, which is a degenerate case. - * But here the answer is infinity, so we simply set the - * infinity flag of the result, overriding the computed values - * without even needing to cmov. - * - * - If y1 = -y2 but x1 != x2, which does occur thanks to certain - * properties of our curve (specifically, 1 has nontrivial cube - * roots in our field, and the curve equation has no x coefficient) - * then the answer is not infinity but also not given by the above - * equation. In this case, we cmov in place an alternate expression - * for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these - * expressions for lambda are defined, they are equal, and can be - * obtained from each other by multiplication by (y1 + y2)/(y1 + y2) - * then substitution of x^3 + 7 for y^2 (using the curve equation). - * For all pairs of nonzero points (a, b) at least one is defined, - * so this covers everything. - */ - - secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */ - u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */ - secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ - s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ - secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */ - secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ - t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */ - m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */ - secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */ - secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */ - secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */ - secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */ - /** If lambda = R/M = 0/0 we have a problem (except in the "trivial" - * case that Z = z1z2 = 0, and this is special-cased later on). */ - degenerate = secp256k1_fe_normalizes_to_zero(&m) & - secp256k1_fe_normalizes_to_zero(&rr); - /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. - * This means either x1 == beta*x2 or beta*x1 == x2, where beta is - * a nontrivial cube root of one. In either case, an alternate - * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2), - * so we set R/M equal to this. */ - rr_alt = s1; - secp256k1_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */ - secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */ - - secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); - secp256k1_fe_cmov(&m_alt, &m, !degenerate); - /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0. - * From here on out Ralt and Malt represent the numerator - * and denominator of lambda; R and M represent the explicit - * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ - secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */ - secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*Malt^2 (1) */ - /* These two lines use the observation that either M == Malt or M == 0, - * so M^3 * Malt is either Malt^4 (which is computed by squaring), or - * zero (which is "computed" by cmov). So the cost is one squaring - * versus two multiplications. */ - secp256k1_fe_sqr(&n, &n); - secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */ - secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ - secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */ - infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity); - secp256k1_fe_mul_int(&r->z, 2); /* r->z = Z3 = 2*Malt*Z (2) */ - secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */ - secp256k1_fe_add(&t, &q); /* t = Ralt^2-Q (3) */ - secp256k1_fe_normalize_weak(&t); - r->x = t; /* r->x = Ralt^2-Q (1) */ - secp256k1_fe_mul_int(&t, 2); /* t = 2*x3 (2) */ - secp256k1_fe_add(&t, &q); /* t = 2*x3 - Q: (4) */ - secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*x3 - Q) (1) */ - secp256k1_fe_add(&t, &n); /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */ - secp256k1_fe_negate(&r->y, &t, 3); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */ - secp256k1_fe_normalize_weak(&r->y); - secp256k1_fe_mul_int(&r->x, 4); /* r->x = X3 = 4*(Ralt^2-Q) */ - secp256k1_fe_mul_int(&r->y, 4); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */ - - /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */ - secp256k1_fe_cmov(&r->x, &b->x, a->infinity); - secp256k1_fe_cmov(&r->y, &b->y, a->infinity); - secp256k1_fe_cmov(&r->z, &fe_1, a->infinity); - r->infinity = infinity; -} - -static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { - /* Operations: 4 mul, 1 sqr */ - secp256k1_fe zz; - VERIFY_CHECK(!secp256k1_fe_is_zero(s)); - secp256k1_fe_sqr(&zz, s); - secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ - secp256k1_fe_mul(&r->y, &r->y, &zz); - secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ - secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ -} - -static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) { - secp256k1_fe x, y; - VERIFY_CHECK(!a->infinity); - x = a->x; - secp256k1_fe_normalize(&x); - y = a->y; - secp256k1_fe_normalize(&y); - secp256k1_fe_to_storage(&r->x, &x); - secp256k1_fe_to_storage(&r->y, &y); -} - -static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a) { - secp256k1_fe_from_storage(&r->x, &a->x); - secp256k1_fe_from_storage(&r->y, &a->y); - r->infinity = 0; -} - -static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) { - secp256k1_fe_storage_cmov(&r->x, &a->x, flag); - secp256k1_fe_storage_cmov(&r->y, &a->y, flag); -} - -#ifdef USE_ENDOMORPHISM -static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { - static const secp256k1_fe beta = SECP256K1_FE_CONST( - 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, - 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul - ); - *r = *a; - secp256k1_fe_mul(&r->x, &r->x, &beta); -} -#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 /* SECP256K1_GROUP_IMPL_H */ diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h deleted file mode 100644 index e08d25d225..0000000000 --- a/src/secp256k1/src/hash.h +++ /dev/null @@ -1,41 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_HASH_H -#define SECP256K1_HASH_H - -#include -#include - -typedef struct { - uint32_t s[8]; - uint32_t buf[16]; /* In big endian */ - size_t bytes; -} secp256k1_sha256_t; - -static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash); -static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t size); -static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32); - -typedef struct { - secp256k1_sha256_t inner, outer; -} secp256k1_hmac_sha256_t; - -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t size); -static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size); -static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32); - -typedef struct { - unsigned char v[32]; - unsigned char k[32]; - int retry; -} secp256k1_rfc6979_hmac_sha256_t; - -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen); -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen); -static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng); - -#endif /* SECP256K1_HASH_H */ diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h deleted file mode 100644 index 4c9964ee06..0000000000 --- a/src/secp256k1/src/hash_impl.h +++ /dev/null @@ -1,281 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_HASH_IMPL_H -#define SECP256K1_HASH_IMPL_H - -#include "hash.h" - -#include -#include -#include - -#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) -#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) -#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10)) -#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7)) -#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3)) -#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10)) - -#define Round(a,b,c,d,e,f,g,h,k,w) do { \ - uint32_t t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \ - uint32_t t2 = Sigma0(a) + Maj((a), (b), (c)); \ - (d) += t1; \ - (h) = t1 + t2; \ -} while(0) - -#ifdef WORDS_BIGENDIAN -#define BE32(x) (x) -#else -#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) -#endif - -static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) { - hash->s[0] = 0x6a09e667ul; - hash->s[1] = 0xbb67ae85ul; - hash->s[2] = 0x3c6ef372ul; - hash->s[3] = 0xa54ff53aul; - hash->s[4] = 0x510e527ful; - hash->s[5] = 0x9b05688cul; - hash->s[6] = 0x1f83d9abul; - hash->s[7] = 0x5be0cd19ul; - hash->bytes = 0; -} - -/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */ -static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) { - uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; - uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; - - Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = BE32(chunk[0])); - Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1])); - Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2])); - Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3])); - Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4])); - Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5])); - Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6])); - Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7])); - Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8])); - Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9])); - Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10])); - Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11])); - Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12])); - Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13])); - Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14])); - Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15])); - - Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); - Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); - Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3)); - Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4)); - Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5)); - Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6)); - Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7)); - Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8)); - Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9)); - Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0)); - - Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1)); - Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2)); - Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3)); - Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4)); - Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5)); - Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6)); - Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7)); - Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8)); - Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9)); - Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0)); - - Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1)); - Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2)); - Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3)); - Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4)); - Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5)); - Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6)); - Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7)); - Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8)); - Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9)); - Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0)); - - s[0] += a; - s[1] += b; - s[2] += c; - s[3] += d; - s[4] += e; - s[5] += f; - s[6] += g; - s[7] += h; -} - -static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t len) { - size_t bufsize = hash->bytes & 0x3F; - hash->bytes += len; - while (bufsize + len >= 64) { - /* Fill the buffer, and process it. */ - memcpy(((unsigned char*)hash->buf) + bufsize, data, 64 - bufsize); - data += 64 - bufsize; - len -= 64 - bufsize; - secp256k1_sha256_transform(hash->s, hash->buf); - bufsize = 0; - } - if (len) { - /* Fill the buffer with what remains. */ - memcpy(((unsigned char*)hash->buf) + bufsize, data, len); - } -} - -static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32) { - static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t sizedesc[2]; - uint32_t out[8]; - int i = 0; - sizedesc[0] = BE32(hash->bytes >> 29); - sizedesc[1] = BE32(hash->bytes << 3); - secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64)); - secp256k1_sha256_write(hash, (const unsigned char*)sizedesc, 8); - for (i = 0; i < 8; i++) { - out[i] = BE32(hash->s[i]); - hash->s[i] = 0; - } - memcpy(out32, (const unsigned char*)out, 32); -} - -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t keylen) { - int n; - unsigned char rkey[64]; - if (keylen <= 64) { - memcpy(rkey, key, keylen); - memset(rkey + keylen, 0, 64 - keylen); - } else { - secp256k1_sha256_t sha256; - secp256k1_sha256_initialize(&sha256); - secp256k1_sha256_write(&sha256, key, keylen); - secp256k1_sha256_finalize(&sha256, rkey); - memset(rkey + 32, 0, 32); - } - - secp256k1_sha256_initialize(&hash->outer); - for (n = 0; n < 64; n++) { - rkey[n] ^= 0x5c; - } - secp256k1_sha256_write(&hash->outer, rkey, 64); - - secp256k1_sha256_initialize(&hash->inner); - for (n = 0; n < 64; n++) { - rkey[n] ^= 0x5c ^ 0x36; - } - secp256k1_sha256_write(&hash->inner, rkey, 64); - memset(rkey, 0, 64); -} - -static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size) { - secp256k1_sha256_write(&hash->inner, data, size); -} - -static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32) { - unsigned char temp[32]; - secp256k1_sha256_finalize(&hash->inner, temp); - secp256k1_sha256_write(&hash->outer, temp, 32); - memset(temp, 0, 32); - secp256k1_sha256_finalize(&hash->outer, out32); -} - - -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen) { - secp256k1_hmac_sha256_t hmac; - static const unsigned char zero[1] = {0x00}; - static const unsigned char one[1] = {0x01}; - - memset(rng->v, 0x01, 32); /* RFC6979 3.2.b. */ - memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */ - - /* RFC6979 3.2.d. */ - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_write(&hmac, zero, 1); - secp256k1_hmac_sha256_write(&hmac, key, keylen); - secp256k1_hmac_sha256_finalize(&hmac, rng->k); - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_finalize(&hmac, rng->v); - - /* RFC6979 3.2.f. */ - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_write(&hmac, one, 1); - secp256k1_hmac_sha256_write(&hmac, key, keylen); - secp256k1_hmac_sha256_finalize(&hmac, rng->k); - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_finalize(&hmac, rng->v); - rng->retry = 0; -} - -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen) { - /* RFC6979 3.2.h. */ - static const unsigned char zero[1] = {0x00}; - if (rng->retry) { - secp256k1_hmac_sha256_t hmac; - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_write(&hmac, zero, 1); - secp256k1_hmac_sha256_finalize(&hmac, rng->k); - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_finalize(&hmac, rng->v); - } - - while (outlen > 0) { - secp256k1_hmac_sha256_t hmac; - int now = outlen; - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_finalize(&hmac, rng->v); - if (now > 32) { - now = 32; - } - memcpy(out, rng->v, now); - out += now; - outlen -= now; - } - - rng->retry = 1; -} - -static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng) { - memset(rng->k, 0, 32); - memset(rng->v, 0, 32); - rng->retry = 0; -} - -#undef BE32 -#undef Round -#undef sigma1 -#undef sigma0 -#undef Sigma1 -#undef Sigma0 -#undef Maj -#undef Ch - -#endif /* SECP256K1_HASH_IMPL_H */ diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java deleted file mode 100644 index 1c67802fba..0000000000 --- a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java +++ /dev/null @@ -1,446 +0,0 @@ -/* - * 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/bitcoin/secp256k1

- * - *

To build secp256k1 for use with bitcoinj, run - * `./configure --enable-jni --enable-experimental --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 - *

- */ -public class NativeSecp256k1 { - - private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); - private static final Lock r = rwl.readLock(); - private static final Lock w = rwl.writeLock(); - private static ThreadLocal nativeECDSABuffer = new ThreadLocal(); - /** - * 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) throws AssertFailException{ - Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); - - ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null || byteBuff.capacity() < 520) { - byteBuff = ByteBuffer.allocateDirect(520); - byteBuff.order(ByteOrder.nativeOrder()); - nativeECDSABuffer.set(byteBuff); - } - byteBuff.rewind(); - byteBuff.put(data); - byteBuff.put(signature); - byteBuff.put(pub); - - byte[][] retByteArray; - - r.lock(); - try { - return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1; - } finally { - r.unlock(); - } - } - - /** - * 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 - */ - 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(); - } - } - - 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_ecdh(ByteBuffer byteBuff, long context, int inputLen); - -} diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java deleted file mode 100644 index c00d08899b..0000000000 --- a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java +++ /dev/null @@ -1,226 +0,0 @@ -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"); - } - - 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 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." ); - - } -} diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java deleted file mode 100644 index 04732ba044..0000000000 --- a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 ); - } - } -} diff --git a/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java b/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java deleted file mode 100644 index 216c986a8b..0000000000 --- a/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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(); -} diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c deleted file mode 100644 index bcef7b32ce..0000000000 --- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c +++ /dev/null @@ -1,377 +0,0 @@ -#include -#include -#include -#include "org_bitcoin_NativeSecp256k1.h" -#include "include/secp256k1.h" -#include "include/secp256k1_ecdh.h" -#include "include/secp256k1_recovery.h" - - -SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone - (JNIEnv* env, jclass classObject, jlong ctx_l) -{ - 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; - -} - -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); - -} - -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_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; -} diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h deleted file mode 100644 index fe613c9e9e..0000000000 --- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h +++ /dev/null @@ -1,119 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -#include "include/secp256k1.h" -/* Header for class org_bitcoin_NativeSecp256k1 */ - -#ifndef _Included_org_bitcoin_NativeSecp256k1 -#define _Included_org_bitcoin_NativeSecp256k1 -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ctx_clone - * Signature: (J)J - */ -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_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 -} -#endif -#endif diff --git a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c deleted file mode 100644 index a52939e7e7..0000000000 --- a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include -#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; -} - diff --git a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h deleted file mode 100644 index 0d2bc84b7f..0000000000 --- a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h +++ /dev/null @@ -1,22 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -#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 diff --git a/src/secp256k1/src/libsecp256k1-config.h.cmake.in b/src/secp256k1/src/libsecp256k1-config.h.cmake.in deleted file mode 100644 index 51ccd04be4..0000000000 --- a/src/secp256k1/src/libsecp256k1-config.h.cmake.in +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (c) 2017 The Bitcoin developers */ - -#ifndef LIBSECP256K1_CONFIG_H -#define LIBSECP256K1_CONFIG_H - -#cmakedefine HAVE___INT128 - -#cmakedefine USE_NUM_GMP -#cmakedefine USE_FIELD_INV_NUM -#cmakedefine USE_SCALAR_INV_NUM - -#cmakedefine USE_NUM_NONE -#cmakedefine USE_FIELD_INV_BUILTIN -#cmakedefine USE_SCALAR_INV_BUILTIN - -#cmakedefine USE_SCALAR_4X64 -#cmakedefine USE_FIELD_5X52 - -#cmakedefine USE_SCALAR_8X32 -#cmakedefine USE_FIELD_10X26 - -#cmakedefine USE_ASM_X86_64 - -#cmakedefine USE_ECMULT_STATIC_PRECOMPUTATION - -#cmakedefine ENABLE_MODULE_ECDH -#cmakedefine ENABLE_MODULE_MULTISET -#cmakedefine ENABLE_MODULE_RECOVERY -#cmakedefine ENABLE_MODULE_SCHNORR - -#endif /* LIBSECP256K1_CONFIG_H */ diff --git a/src/secp256k1/src/modules/ecdh/Makefile.am.include b/src/secp256k1/src/modules/ecdh/Makefile.am.include deleted file mode 100644 index e3088b4697..0000000000 --- a/src/secp256k1/src/modules/ecdh/Makefile.am.include +++ /dev/null @@ -1,8 +0,0 @@ -include_HEADERS += include/secp256k1_ecdh.h -noinst_HEADERS += src/modules/ecdh/main_impl.h -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) $(COMMON_LIB) -endif diff --git a/src/secp256k1/src/modules/ecdh/main_impl.h b/src/secp256k1/src/modules/ecdh/main_impl.h deleted file mode 100644 index 01ecba4d53..0000000000 --- a/src/secp256k1/src/modules/ecdh/main_impl.h +++ /dev/null @@ -1,54 +0,0 @@ -/********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_ECDH_MAIN_H -#define SECP256K1_MODULE_ECDH_MAIN_H - -#include "include/secp256k1_ecdh.h" -#include "ecmult_const_impl.h" - -int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) { - int ret = 0; - int overflow = 0; - secp256k1_gej res; - secp256k1_ge pt; - secp256k1_scalar s; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(result != NULL); - ARG_CHECK(point != NULL); - ARG_CHECK(scalar != NULL); - - secp256k1_pubkey_load(ctx, &pt, point); - secp256k1_scalar_set_b32(&s, scalar, &overflow); - if (overflow || secp256k1_scalar_is_zero(&s)) { - ret = 0; - } else { - unsigned char x[32]; - unsigned char y[1]; - secp256k1_sha256_t sha; - - secp256k1_ecmult_const(&res, &pt, &s); - secp256k1_ge_set_gej(&pt, &res); - /* Compute a hash of the point in compressed form - * Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not - * expect its output to be secret and has a timing sidechannel. */ - secp256k1_fe_normalize(&pt.x); - secp256k1_fe_normalize(&pt.y); - secp256k1_fe_get_b32(x, &pt.x); - y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y); - - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, y, sizeof(y)); - secp256k1_sha256_write(&sha, x, sizeof(x)); - secp256k1_sha256_finalize(&sha, result); - ret = 1; - } - - secp256k1_scalar_clear(&s); - return ret; -} - -#endif /* SECP256K1_MODULE_ECDH_MAIN_H */ diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h deleted file mode 100644 index cec30b67c6..0000000000 --- a/src/secp256k1/src/modules/ecdh/tests_impl.h +++ /dev/null @@ -1,105 +0,0 @@ -/********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_ECDH_TESTS_H -#define SECP256K1_MODULE_ECDH_TESTS_H - -void test_ecdh_api(void) { - /* Setup context that just counts errors */ - secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - secp256k1_pubkey point; - unsigned char res[32]; - unsigned char s_one[32] = { 0 }; - int32_t ecount = 0; - s_one[31] = 1; - - secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount); - CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1); - - /* Check all NULLs are detected */ - CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1); - CHECK(ecount == 3); - - /* Cleanup */ - secp256k1_context_destroy(tctx); -} - -void test_ecdh_generator_basepoint(void) { - unsigned char s_one[32] = { 0 }; - secp256k1_pubkey point[2]; - int i; - - s_one[31] = 1; - /* Check against pubkey creation when the basepoint is the generator */ - for (i = 0; i < 100; ++i) { - secp256k1_sha256_t sha; - unsigned char s_b32[32]; - unsigned char output_ecdh[32]; - unsigned char output_ser[32]; - unsigned char point_ser[33]; - size_t point_ser_len = sizeof(point_ser); - secp256k1_scalar s; - - random_scalar_order(&s); - secp256k1_scalar_get_b32(s_b32, &s); - - /* compute using ECDH function */ - CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1); - CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1); - /* compute "explicitly" */ - CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1); - CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); - CHECK(point_ser_len == sizeof(point_ser)); - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, point_ser, point_ser_len); - secp256k1_sha256_finalize(&sha, output_ser); - /* compare */ - CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0); - } -} - -void test_bad_scalar(void) { - unsigned char s_zero[32] = { 0 }; - unsigned char s_overflow[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, 0x41 - }; - unsigned char s_rand[32] = { 0 }; - unsigned char output[32]; - secp256k1_scalar rand; - secp256k1_pubkey point; - - /* Create random point */ - random_scalar_order(&rand); - secp256k1_scalar_get_b32(s_rand, &rand); - CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1); - - /* Try to multiply it by bad values */ - CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0); - CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0); - /* ...and a good one */ - s_overflow[31] -= 1; - CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1); -} - -void run_ecdh_tests(void) { - test_ecdh_api(); - test_ecdh_generator_basepoint(); - test_bad_scalar(); -} - -#endif /* SECP256K1_MODULE_ECDH_TESTS_H */ diff --git a/src/secp256k1/src/modules/recovery/Makefile.am.include b/src/secp256k1/src/modules/recovery/Makefile.am.include deleted file mode 100644 index bf23c26e71..0000000000 --- a/src/secp256k1/src/modules/recovery/Makefile.am.include +++ /dev/null @@ -1,8 +0,0 @@ -include_HEADERS += include/secp256k1_recovery.h -noinst_HEADERS += src/modules/recovery/main_impl.h -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) $(COMMON_LIB) -endif diff --git a/src/secp256k1/src/modules/recovery/main_impl.h b/src/secp256k1/src/modules/recovery/main_impl.h deleted file mode 100755 index 2f6691c5a1..0000000000 --- a/src/secp256k1/src/modules/recovery/main_impl.h +++ /dev/null @@ -1,193 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H -#define SECP256K1_MODULE_RECOVERY_MAIN_H - -#include "include/secp256k1_recovery.h" - -static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) { - (void)ctx; - if (sizeof(secp256k1_scalar) == 32) { - /* When the secp256k1_scalar type is exactly 32 byte, use its - * representation inside secp256k1_ecdsa_signature, as conversion is very fast. - * Note that secp256k1_ecdsa_signature_save must use the same representation. */ - memcpy(r, &sig->data[0], 32); - memcpy(s, &sig->data[32], 32); - } else { - secp256k1_scalar_set_b32(r, &sig->data[0], NULL); - secp256k1_scalar_set_b32(s, &sig->data[32], NULL); - } - *recid = sig->data[64]; -} - -static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s, int recid) { - if (sizeof(secp256k1_scalar) == 32) { - memcpy(&sig->data[0], r, 32); - memcpy(&sig->data[32], s, 32); - } else { - secp256k1_scalar_get_b32(&sig->data[0], r); - secp256k1_scalar_get_b32(&sig->data[32], s); - } - sig->data[64] = recid; -} - -int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) { - secp256k1_scalar r, s; - int ret = 1; - int overflow = 0; - - (void)ctx; - ARG_CHECK(sig != NULL); - ARG_CHECK(input64 != NULL); - ARG_CHECK(recid >= 0 && recid <= 3); - - secp256k1_scalar_set_b32(&r, &input64[0], &overflow); - ret &= !overflow; - secp256k1_scalar_set_b32(&s, &input64[32], &overflow); - ret &= !overflow; - if (ret) { - secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid); - } else { - memset(sig, 0, sizeof(*sig)); - } - return ret; -} - -int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig) { - secp256k1_scalar r, s; - - (void)ctx; - ARG_CHECK(output64 != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(recid != NULL); - - secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig); - secp256k1_scalar_get_b32(&output64[0], &r); - secp256k1_scalar_get_b32(&output64[32], &s); - return 1; -} - -int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const secp256k1_ecdsa_recoverable_signature* sigin) { - secp256k1_scalar r, s; - int recid; - - (void)ctx; - ARG_CHECK(sig != NULL); - ARG_CHECK(sigin != NULL); - - secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin); - secp256k1_ecdsa_signature_save(sig, &r, &s); - return 1; -} - -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) { - unsigned char brx[32]; - secp256k1_fe fx; - secp256k1_ge x; - secp256k1_gej xj; - secp256k1_scalar rn, u1, u2; - secp256k1_gej qj; - int r; - - if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { - return 0; - } - - secp256k1_scalar_get_b32(brx, sigr); - r = secp256k1_fe_set_b32(&fx, brx); - (void)r; - VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */ - if (recid & 2) { - if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { - return 0; - } - secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe); - } - if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) { - return 0; - } - secp256k1_gej_set_ge(&xj, &x); - secp256k1_scalar_inverse_var(&rn, sigr); - secp256k1_scalar_mul(&u1, &rn, message); - secp256k1_scalar_negate(&u1, &u1); - secp256k1_scalar_mul(&u2, &rn, sigs); - secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); - secp256k1_ge_set_gej_var(pubkey, &qj); - return !secp256k1_gej_is_infinity(&qj); -} - -int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { - secp256k1_scalar r, s; - secp256k1_scalar sec, non, msg; - int recid; - int ret = 0; - int overflow = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(signature != NULL); - ARG_CHECK(seckey != NULL); - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; - } - - secp256k1_scalar_set_b32(&sec, seckey, &overflow); - /* Fail if the secret key is invalid. */ - if (!overflow && !secp256k1_scalar_is_zero(&sec)) { - unsigned char nonce32[32]; - unsigned int count = 0; - secp256k1_scalar_set_b32(&msg, msg32, NULL); - while (1) { - ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); - if (!ret) { - break; - } - secp256k1_scalar_set_b32(&non, nonce32, &overflow); - if (!secp256k1_scalar_is_zero(&non) && !overflow) { - if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) { - break; - } - } - count++; - } - memset(nonce32, 0, 32); - secp256k1_scalar_clear(&msg); - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); - } - if (ret) { - secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid); - } else { - memset(signature, 0, sizeof(*signature)); - } - return ret; -} - -int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32) { - secp256k1_ge q; - secp256k1_scalar r, s; - secp256k1_scalar m; - int recid; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(signature != NULL); - ARG_CHECK(pubkey != NULL); - - secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature); - VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */ - secp256k1_scalar_set_b32(&m, msg32, NULL); - if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) { - secp256k1_pubkey_save(pubkey, &q); - return 1; - } else { - memset(pubkey, 0, sizeof(*pubkey)); - return 0; - } -} - -#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */ diff --git a/src/secp256k1/src/modules/recovery/tests_impl.h b/src/secp256k1/src/modules/recovery/tests_impl.h deleted file mode 100644 index 5c9bbe8610..0000000000 --- a/src/secp256k1/src/modules/recovery/tests_impl.h +++ /dev/null @@ -1,393 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H -#define SECP256K1_MODULE_RECOVERY_TESTS_H - -static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { - (void) msg32; - (void) key32; - (void) algo16; - (void) data; - - /* On the first run, return 0 to force a second run */ - if (counter == 0) { - memset(nonce32, 0, 32); - return 1; - } - /* On the second run, return an overflow to force a third run */ - if (counter == 1) { - memset(nonce32, 0xff, 32); - return 1; - } - /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */ - memset(nonce32, 1, 32); - return secp256k1_rand_bits(1); -} - -void test_ecdsa_recovery_api(void) { - /* Setup contexts that just count errors */ - secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - secp256k1_pubkey pubkey; - secp256k1_pubkey recpubkey; - secp256k1_ecdsa_signature normal_sig; - secp256k1_ecdsa_recoverable_signature recsig; - unsigned char privkey[32] = { 1 }; - unsigned char message[32] = { 2 }; - int32_t ecount = 0; - int recid = 0; - unsigned char sig[74]; - unsigned char zero_privkey[32] = { 0 }; - unsigned char over_privkey[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, 0xff, 0xff, 0xff, 0xff, 0xff }; - - secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); - - /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); - - /* Check bad contexts and NULLs for signing */ - ecount = 0; - CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0); - CHECK(ecount == 5); - /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */ - secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL); - CHECK(ecount == 5); - /* These will all fail, but not in ARG_CHECK way */ - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0); - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0); - /* This one will succeed. */ - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 5); - - /* Check signing with a goofy nonce function */ - - /* Check bad contexts and NULLs for recovery */ - ecount = 0; - CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0); - CHECK(ecount == 5); - - /* Check NULLs for conversion */ - CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1); - ecount = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1); - - /* Check NULLs for de/serialization */ - CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); - ecount = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1); - - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0); - CHECK(ecount == 6); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0); - CHECK(ecount == 7); - /* overflow in signature will fail but not affect ecount */ - memcpy(sig, over_privkey, 32); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0); - CHECK(ecount == 7); - - /* cleanup */ - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(vrfy); - secp256k1_context_destroy(both); -} - -void test_ecdsa_recovery_end_to_end(void) { - unsigned char extra[32] = {0x00}; - unsigned char privkey[32]; - unsigned char message[32]; - secp256k1_ecdsa_signature signature[5]; - secp256k1_ecdsa_recoverable_signature rsignature[5]; - unsigned char sig[74]; - secp256k1_pubkey pubkey; - secp256k1_pubkey recpubkey; - int recid = 0; - - /* Generate a random key and message. */ - { - secp256k1_scalar msg, key; - random_scalar_order_test(&msg); - random_scalar_order_test(&key); - secp256k1_scalar_get_b32(privkey, &key); - secp256k1_scalar_get_b32(message, &msg); - } - - /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); - - /* Serialize/parse compact and verify/recover. */ - extra[0] = 0; - CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1); - extra[31] = 1; - CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1); - extra[31] = 0; - extra[0] = 1; - CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); - CHECK(memcmp(&signature[4], &signature[0], 64) == 0); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); - memset(&rsignature[4], 0, sizeof(rsignature[4])); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); - /* Parse compact (with recovery id) and recover. */ - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); - CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1); - CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); - /* Serialize/destroy/parse signature and verify again. */ - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); - sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0); - /* Recover again */ - CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 || - memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); -} - -/* Tests several edge cases. */ -void test_ecdsa_recovery_edge_cases(void) { - const unsigned char msg32[32] = { - 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', - 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', - 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', - 's', 's', 'a', 'g', 'e', '.', '.', '.' - }; - const unsigned char sig64[64] = { - /* Generated by signing the above message with nonce 'This is the nonce we will use...' - * and secret key 0 (which is not valid), resulting in recid 0. */ - 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, - 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, - 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, - 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, - 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, - 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, - 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, - 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 - }; - secp256k1_pubkey pubkey; - /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ - const unsigned char sigb64[64] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - }; - secp256k1_pubkey pubkeyb; - secp256k1_ecdsa_recoverable_signature rsig; - secp256k1_ecdsa_signature sig; - int recid; - - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0)); - CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1)); - CHECK(secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2)); - CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3)); - CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); - - for (recid = 0; recid < 4; recid++) { - int i; - int recid2; - /* (4,4) encoded in DER. */ - unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; - unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; - unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; - unsigned char sigbderalt1[39] = { - 0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, - }; - unsigned char sigbderalt2[39] = { - 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - }; - unsigned char sigbderalt3[40] = { - 0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, - }; - unsigned char sigbderalt4[40] = { - 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - }; - /* (order + r,4) encoded in DER. */ - unsigned char sigbderlong[40] = { - 0x30, 0x26, 0x02, 0x21, 0x00, 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, 0x45, 0x02, 0x01, 0x04 - }; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1); - CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); - for (recid2 = 0; recid2 < 4; recid2++) { - secp256k1_pubkey pubkey2b; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1); - CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1); - /* Verifying with (order + r,4) should always fail. */ - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); - } - /* DER parsing tests. */ - /* Zero length r/s. */ - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); - /* Leading zeros. */ - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); - sigbderalt3[4] = 1; - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); - sigbderalt4[7] = 1; - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); - /* Damage signature. */ - sigbder[7]++; - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); - sigbder[7]--; - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0); - for(i = 0; i < 8; i++) { - int c; - unsigned char orig = sigbder[i]; - /*Try every single-byte change.*/ - for (c = 0; c < 256; c++) { - if (c == orig ) { - continue; - } - sigbder[i] = c; - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); - } - sigbder[i] = orig; - } - } - - /* Test r/s equal to zero */ - { - /* (1,1) encoded in DER. */ - unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; - unsigned char sigc64[64] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }; - secp256k1_pubkey pubkeyc; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); - CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1); - sigcder[4] = 0; - sigc64[31] = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); - CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); - sigcder[4] = 1; - sigcder[7] = 0; - sigc64[31] = 1; - sigc64[63] = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); - CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); - } -} - -void run_recovery_tests(void) { - int i; - for (i = 0; i < count; i++) { - test_ecdsa_recovery_api(); - } - for (i = 0; i < 64*count; i++) { - test_ecdsa_recovery_end_to_end(); - } - test_ecdsa_recovery_edge_cases(); -} - -#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */ diff --git a/src/secp256k1/src/modules/schnorr/Makefile.am.include b/src/secp256k1/src/modules/schnorr/Makefile.am.include deleted file mode 100644 index dc8e8aae32..0000000000 --- a/src/secp256k1/src/modules/schnorr/Makefile.am.include +++ /dev/null @@ -1,3 +0,0 @@ -include_HEADERS += include/secp256k1_schnorr.h -noinst_HEADERS += src/modules/schnorr/main_impl.h -noinst_HEADERS += src/modules/schnorr/tests_impl.h diff --git a/src/secp256k1/src/modules/schnorr/main_impl.h b/src/secp256k1/src/modules/schnorr/main_impl.h deleted file mode 100755 index fa9bfd64cb..0000000000 --- a/src/secp256k1/src/modules/schnorr/main_impl.h +++ /dev/null @@ -1,235 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2017 Amaury SÉCHET * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php. * - ***********************************************************************/ - -#ifndef _SECP256K1_SCHNORR_IMPL_H_ -#define _SECP256K1_SCHNORR_IMPL_H_ - -#include - -#include "include/secp256k1_schnorr.h" -#include "field.h" -#include "group.h" -#include "hash.h" -#include "ecmult.h" -#include "ecmult_gen.h" - -/** - * Custom Schnorr-based signature scheme. - */ - -/* Helper function to compute e */ -static int secp256k1_schnorr_compute_e( - secp256k1_scalar* e, - const unsigned char *r, - secp256k1_ge *p, - const unsigned char *msg32 -) { - int overflow = 0; - size_t size; - secp256k1_sha256_t sha; - unsigned char buf[33]; - secp256k1_sha256_initialize(&sha); - - /* R.x */ - secp256k1_sha256_write(&sha, r, 32); - - /* compressed P */ - secp256k1_eckey_pubkey_serialize(p, buf, &size, 1); - VERIFY_CHECK(size == 33); - secp256k1_sha256_write(&sha, buf, 33); - - /* msg */ - secp256k1_sha256_write(&sha, msg32, 32); - - /* compute e */ - secp256k1_sha256_finalize(&sha, buf); - secp256k1_scalar_set_b32(e, buf, &overflow); - return !overflow & !secp256k1_scalar_is_zero(e); -} - -/* Helper function to compute deterministic nonce, k */ -static int secp256k1_schnorr_sig_generate_k( - secp256k1_scalar *k, - const unsigned char *msg32, - const unsigned char *seckey, - secp256k1_nonce_function noncefp, - const void *ndata -) { - int overflow = 0; - int ret = 0; - unsigned int count = 0; - unsigned char nonce32[32]; - - /* Seed used to make sure we generate different values of k for schnorr */ - const unsigned char secp256k1_schnorr_algo16[17] = "SCHNORR + SHA256"; - - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; - } - - while (1) { - ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, (void*)ndata, count++); - if (!ret) { - break; - } - - secp256k1_scalar_set_b32(k, nonce32, &overflow); - if (!overflow && !secp256k1_scalar_is_zero(k)) { - break; - } - } - - memset(nonce32, 0, 32); - return ret; -} - - /* Verification: - * Inputs: - * 32-byte message m, - * public key point P, - * signature: (32-byte r, scalar s) - * - * Signature is invalid if s >= order or r >= p. - * Compute scalar e = Hash(r || compressed(P) || m) mod n. - * Option 1 (faster for single verification): - * Compute point R = s * G - e * P. - * Reject if R is infinity or R.y is not a quadratic residue. - * Signature is valid if the serialization of R.x equals r. - * Option 2 (allows batch validation): - * Decompress x coordinate r into point R, with R.y a quadratic residue. - * Reject if R is not on the curve. - * Signature is valid if R + e * P - s * G == 0. - */ -int secp256k1_schnorr_verify( - const secp256k1_context* ctx, - const unsigned char *sig64, - const unsigned char *msg32, - const secp256k1_pubkey *pubkey -) { - secp256k1_ge q; - secp256k1_gej Pj, Rj; - secp256k1_fe Rx; - secp256k1_scalar e, s; - int overflow; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(pubkey != NULL); - - secp256k1_pubkey_load(ctx, &q, pubkey); - - if (secp256k1_ge_is_infinity(&q)) { - return 0; - } - - /* Extract s */ - overflow = 0; - secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); - if (overflow) { - return 0; - } - - /* Extract R.x */ - if (!secp256k1_fe_set_b32(&Rx, sig64)) { - return 0; - } - - /* Compute e */ - secp256k1_schnorr_compute_e(&e, sig64, &q, msg32); - - /* Verify the signature */ - secp256k1_scalar_negate(&e, &e); - secp256k1_gej_set_ge(&Pj, &q); - secp256k1_ecmult(&ctx->ecmult_ctx, &Rj, &Pj, &e, &s); - if (secp256k1_gej_is_infinity(&Rj)) { - return 0; - } - - /* Check that R.x is what we expect */ - if (!secp256k1_gej_eq_x_var(&Rx, &Rj)) { - return 0; - } - - /* Check that jacobi(R.y) is 1 */ - if (!secp256k1_gej_has_quad_y_var(&Rj)) { - return 0; - } - - /* All good, we have a valid signature. */ - return 1; -} - - /* Signing: - * Inputs: - * 32-byte message m, - * 32-byte scalar key x (!=0) - * public key point P, - * 32-byte scalar nonce k (!=0) - * - * Compute point R = k * G. Negate nonce if R.y is not a quadratic residue. - * Compute scalar e = Hash(R.x || compressed(P) || m) mod n. - * Compute scalar s = k + e * x. - * The signature is (R.x, s). - */ -int secp256k1_schnorr_sign( - const secp256k1_context *ctx, - unsigned char *sig64, - const unsigned char *msg32, - const unsigned char *seckey, - secp256k1_nonce_function noncefp, - const void *ndata -) { - secp256k1_scalar privkey, e, s, k; - secp256k1_pubkey pubkey; - secp256k1_ge p, Ra; - secp256k1_gej Rj; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(seckey != NULL); - - if (!secp256k1_ec_pubkey_create(ctx, &pubkey, seckey)) { - return 0; - } - - if (!secp256k1_schnorr_sig_generate_k(&k, msg32, seckey, noncefp, ndata)) { - secp256k1_scalar_clear(&k); - return 0; - } - - secp256k1_pubkey_load(ctx, &p, &pubkey); - secp256k1_scalar_set_b32(&privkey, seckey, NULL); - - if (secp256k1_scalar_is_zero(&privkey) || secp256k1_scalar_is_zero(&k)) { - return 0; - } - - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Rj, &k); - secp256k1_ge_set_gej(&Ra, &Rj); - if (!secp256k1_fe_is_quad_var(&Ra.y)) { - /** - * R's y coordinate is not a quadratic residue, which is not allowed. - * Negate the nonce to ensure it is. - */ - secp256k1_scalar_negate(&k, &k); - } - - secp256k1_fe_normalize(&Ra.x); - secp256k1_fe_get_b32(sig64, &Ra.x); - secp256k1_schnorr_compute_e(&e, sig64, &p, msg32); - secp256k1_scalar_mul(&s, &e, &privkey); - secp256k1_scalar_add(&s, &s, &k); - secp256k1_scalar_clear(&k); - secp256k1_scalar_get_b32(sig64 + 32, &s); - return 1; -} - - -#endif diff --git a/src/secp256k1/src/modules/schnorr/tests_impl.h b/src/secp256k1/src/modules/schnorr/tests_impl.h deleted file mode 100644 index 56f972a480..0000000000 --- a/src/secp256k1/src/modules/schnorr/tests_impl.h +++ /dev/null @@ -1,680 +0,0 @@ -/********************************************************************** - * Copyright (c) 2017 Amaury SÉCHET, - * Copyright (c) 2018 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_SCHNORR_TESTS -#define SECP256K1_MODULE_SCHNORR_TESTS - -#include "include/secp256k1_schnorr.h" -#include "modules/schnorr/main_impl.h" - -void test_schnorr_api() { - unsigned char sk1[32]; - unsigned char sk2[32]; - unsigned char sk3[32]; - unsigned char msg[32]; - unsigned char sig64[64]; - secp256k1_pubkey pk[3]; - unsigned char *sig = &sig64; - const unsigned char *msgptr = msg; - - /** setup **/ - secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - int ecount; - - secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); - - secp256k1_rand256(sk1); - secp256k1_rand256(sk2); - secp256k1_rand256(sk3); - secp256k1_rand256(msg); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk1) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk2) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pk[2], sk3) == 1); - - /** main test body **/ - ecount = 0; - CHECK(secp256k1_schnorr_sign(none, sig, msg, sk1, NULL, NULL) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_schnorr_sign(vrfy, sig, msg, sk1, NULL, NULL) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_schnorr_sign(sign, sig, msg, sk1, NULL, NULL) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_schnorr_sign(sign, NULL, msg, sk1, NULL, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_schnorr_sign(sign, sig, NULL, sk1, NULL, NULL) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_schnorr_sign(sign, sig, msg, NULL, NULL, NULL) == 0); - CHECK(ecount == 5); - - ecount = 0; - CHECK(secp256k1_schnorr_verify(none, sig, msg, &pk[0]) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_schnorr_verify(sign, sig, msg, &pk[0]) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_schnorr_verify(vrfy, sig, msg, &pk[0]) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_schnorr_verify(vrfy, NULL, msg, &pk[0]) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_schnorr_verify(vrfy, sig, NULL, &pk[0]) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_schnorr_verify(vrfy, sig, msg, NULL) == 0); - CHECK(ecount == 5); - - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(vrfy); - secp256k1_context_destroy(both); -} - -void test_schnorr_end_to_end(void) { - unsigned char privkey[32]; - unsigned char message[32]; - unsigned char schnorr_signature[64]; - secp256k1_pubkey pubkey; - - /* Generate a random key and message. */ - { - secp256k1_scalar key; - random_scalar_order_test(&key); - secp256k1_scalar_get_b32(privkey, &key); - secp256k1_rand256_test(message); - } - - /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); - - /* Schnorr sign. */ - CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1); - /* Destroy signature and verify again. */ - schnorr_signature[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255); - CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 0); -} - -void run_schnorr_compact_test(void) { - { - /* Test vector 1 */ - static const unsigned char pkbuf[33] = { - 0x02, - 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, - 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, - 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, - 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, - }; - - static const unsigned char msg[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - - static const unsigned char sig[64] = { - 0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28, - 0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2, - 0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB, - 0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6, - 0x70, 0x31, 0xA9, 0x88, 0x31, 0x85, 0x9D, 0xC3, - 0x4D, 0xFF, 0xEE, 0xDD, 0xA8, 0x68, 0x31, 0x84, - 0x2C, 0xCD, 0x00, 0x79, 0xE1, 0xF9, 0x2A, 0xF1, - 0x77, 0xF7, 0xF2, 0x2C, 0xC1, 0xDC, 0xED, 0x05, - }; - - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey)); - } - - { - /* Test vector 2 */ - static const unsigned char pkbuf[33] = { - 0x02, - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59, - }; - - static const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89, - }; - - static const unsigned char sig[64] = { - 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, - 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, - 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, - 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, - 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, - 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, - 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, - 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD, - }; - - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey)); - } - - { - /* Test vector 3 */ - static const unsigned char pkbuf[33] = { - 0x03, - 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, 0x15, - 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, 0x80, - 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, 0x3C, - 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, 0x4B, - }; - - static const unsigned char msg[32] = { - 0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, - 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, - 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, - 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C, - }; - - static const unsigned char sig[64] = { - 0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F, - 0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D, - 0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53, - 0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE, - 0x00, 0x88, 0x03, 0x71, 0xD0, 0x17, 0x66, 0x93, - 0x5B, 0x92, 0xD2, 0xAB, 0x4C, 0xD5, 0xC8, 0xA2, - 0xA5, 0x83, 0x7E, 0xC5, 0x7F, 0xED, 0x76, 0x60, - 0x77, 0x3A, 0x05, 0xF0, 0xDE, 0x14, 0x23, 0x80, - }; - - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey)); - } - - { - /* Test vector 4 */ - static const unsigned char pkbuf[33] = { - 0x03, - 0xDE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, 0x50, - 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, 0x21, - 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, 0x87, - 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, 0x34, - }; - - static const unsigned char msg[32] = { - 0x4D, 0xF3, 0xC3, 0xF6, 0x8F, 0xCC, 0x83, 0xB2, - 0x7E, 0x9D, 0x42, 0xC9, 0x04, 0x31, 0xA7, 0x24, - 0x99, 0xF1, 0x78, 0x75, 0xC8, 0x1A, 0x59, 0x9B, - 0x56, 0x6C, 0x98, 0x89, 0xB9, 0x69, 0x67, 0x03, - }; - - static const unsigned char sig[64] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3B, 0x78, 0xCE, 0x56, 0x3F, - 0x89, 0xA0, 0xED, 0x94, 0x14, 0xF5, 0xAA, 0x28, - 0xAD, 0x0D, 0x96, 0xD6, 0x79, 0x5F, 0x9C, 0x63, - 0x02, 0xA8, 0xDC, 0x32, 0xE6, 0x4E, 0x86, 0xA3, - 0x33, 0xF2, 0x0E, 0xF5, 0x6E, 0xAC, 0x9B, 0xA3, - 0x0B, 0x72, 0x46, 0xD6, 0xD2, 0x5E, 0x22, 0xAD, - 0xB8, 0xC6, 0xBE, 0x1A, 0xEB, 0x08, 0xD4, 0x9D, - }; - - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey)); - } - - { - /* Test vector 4b */ - static const unsigned char pkbuf[33] = { - 0x03, - 0x1B, 0x84, 0xC5, 0x56, 0x7B, 0x12, 0x64, 0x40, - 0x99, 0x5D, 0x3E, 0xD5, 0xAA, 0xBA, 0x05, 0x65, - 0xD7, 0x1E, 0x18, 0x34, 0x60, 0x48, 0x19, 0xFF, - 0x9C, 0x17, 0xF5, 0xE9, 0xD5, 0xDD, 0x07, 0x8F, - }; - - static const unsigned char msg[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - - static const unsigned char sig[64] = { - 0x52, 0x81, 0x85, 0x79, 0xAC, 0xA5, 0x97, 0x67, - 0xE3, 0x29, 0x1D, 0x91, 0xB7, 0x6B, 0x63, 0x7B, - 0xEF, 0x06, 0x20, 0x83, 0x28, 0x49, 0x92, 0xF2, - 0xD9, 0x5F, 0x56, 0x4C, 0xA6, 0xCB, 0x4E, 0x35, - 0x30, 0xB1, 0xDA, 0x84, 0x9C, 0x8E, 0x83, 0x04, - 0xAD, 0xC0, 0xCF, 0xE8, 0x70, 0x66, 0x03, 0x34, - 0xB3, 0xCF, 0xC1, 0x8E, 0x82, 0x5E, 0xF1, 0xDB, - 0x34, 0xCF, 0xAE, 0x3D, 0xFC, 0x5D, 0x81, 0x87, - }; - - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey)); - } - - { - /* Test vector 6: R.y is not a quadratic residue */ - static const unsigned char pkbuf[33] = { - 0x02, - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59, - }; - - static const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89, - }; - - static const unsigned char sig[64] = { - 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, - 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, - 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, - 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, - 0xFA, 0x16, 0xAE, 0xE0, 0x66, 0x09, 0x28, 0x0A, - 0x19, 0xB6, 0x7A, 0x24, 0xE1, 0x97, 0x7E, 0x46, - 0x97, 0x71, 0x2B, 0x5F, 0xD2, 0x94, 0x39, 0x14, - 0xEC, 0xD5, 0xF7, 0x30, 0x90, 0x1B, 0x4A, 0xB7, - }; - - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey) == 0); - } - { - /* Test vector 6 */ - const unsigned char pkbuf[33] = { - 0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, - 0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, - 0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, - 0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, - 0x4B - }; - const unsigned char msg[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, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF - }; - const unsigned char sig[64] = { - 0x57, 0x0D, 0xD4, 0xCA, 0x83, 0xD4, 0xE6, 0x31, - 0x7B, 0x8E, 0xE6, 0xBA, 0xE8, 0x34, 0x67, 0xA1, - 0xBF, 0x41, 0x9D, 0x07, 0x67, 0x12, 0x2D, 0xE4, - 0x09, 0x39, 0x44, 0x14, 0xB0, 0x50, 0x80, 0xDC, - 0xE9, 0xEE, 0x5F, 0x23, 0x7C, 0xBD, 0x10, 0x8E, - 0xAB, 0xAE, 0x1E, 0x37, 0x75, 0x9A, 0xE4, 0x7F, - 0x8E, 0x42, 0x03, 0xDA, 0x35, 0x32, 0xEB, 0x28, - 0xDB, 0x86, 0x0F, 0x33, 0xD6, 0x2D, 0x49, 0xBD - }; - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey)); - } - { - /* Test vector 7 */ - const unsigned char pkbuf[33] = { - 0x03, 0xEE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, - 0x50, 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, - 0x21, 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, - 0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, - 0x34 - }; - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33) == 0); - } - { - /* Test vector 8 */ - const unsigned char pkbuf[33] = { - 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, - 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, - 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, - 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, - 0x59 - }; - const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 - }; - const unsigned char sig[64] = { - 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, - 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, - 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, - 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, - 0xFA, 0x16, 0xAE, 0xE0, 0x66, 0x09, 0x28, 0x0A, - 0x19, 0xB6, 0x7A, 0x24, 0xE1, 0x97, 0x7E, 0x46, - 0x97, 0x71, 0x2B, 0x5F, 0xD2, 0x94, 0x39, 0x14, - 0xEC, 0xD5, 0xF7, 0x30, 0x90, 0x1B, 0x4A, 0xB7 - }; - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey) == 0); - } - { - /* Test vector 7: Negated message hash, R.x mismatch */ - static const unsigned char pkbuf[33] = { - 0x03, - 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, 0x15, - 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, 0x80, - 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, 0x3C, - 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, 0x4B, - }; - - static const unsigned char msg[32] = { - 0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, - 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, - 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, - 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C, - }; - - static const unsigned char sig[64] = { - 0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F, - 0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D, - 0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53, - 0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE, - 0xD0, 0x92, 0xF9, 0xD8, 0x60, 0xF1, 0x77, 0x6A, - 0x1F, 0x74, 0x12, 0xAD, 0x8A, 0x1E, 0xB5, 0x0D, - 0xAC, 0xCC, 0x22, 0x2B, 0xC8, 0xC0, 0xE2, 0x6B, - 0x20, 0x56, 0xDF, 0x2F, 0x27, 0x3E, 0xFD, 0xEC, - }; - - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey) == 0); - } - - { - /* Test vector 8: Negated s, R.x mismatch */ - static const unsigned char pkbuf[33] = { - 0x02, - 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, - 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, - 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, - 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, - }; - - static const unsigned char msg[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - - static const unsigned char sig[64] = { - 0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28, - 0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2, - 0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB, - 0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6, - 0x8F, 0xCE, 0x56, 0x77, 0xCE, 0x7A, 0x62, 0x3C, - 0xB2, 0x00, 0x11, 0x22, 0x57, 0x97, 0xCE, 0x7A, - 0x8D, 0xE1, 0xDC, 0x6C, 0xCD, 0x4F, 0x75, 0x4A, - 0x47, 0xDA, 0x6C, 0x60, 0x0E, 0x59, 0x54, 0x3C, - }; - - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey) == 0); - } - - { - /* Test vector 9: Negated P, R.x mismatch */ - static const unsigned char pkbuf[33] = { - 0x03, - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59, - }; - - static const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89, - }; - - static const unsigned char sig[64] = { - 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, - 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, - 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, - 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, - 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, - 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, - 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, - 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD, - }; - - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey) == 0); - } - - { - /* Test vector 10: s * G = e * P, R = 0 */ - static const unsigned char pkbuf[33] = { - 0x02, - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59, - }; - - static const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89, - }; - - static const unsigned char sig[64] = { - 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, - 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, - 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, - 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, - 0x8C, 0x34, 0x28, 0x86, 0x9A, 0x66, 0x3E, 0xD1, - 0xE9, 0x54, 0x70, 0x5B, 0x02, 0x0C, 0xBB, 0x3E, - 0x7B, 0xB6, 0xAC, 0x31, 0x96, 0x5B, 0x9E, 0xA4, - 0xC7, 0x3E, 0x22, 0x7B, 0x17, 0xC5, 0xAF, 0x5A, - }; - - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey) == 0); - } - - { - /* Test vector 11: R.x not on the curve, R.x mismatch */ - static const unsigned char pkbuf[33] = { - 0x02, - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59, - }; - - static const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89, - }; - - static const unsigned char sig[64] = { - 0x4A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, - 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, - 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, - 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, - 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, - 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, - 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, - 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD, - }; - - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey) == 0); - } - - { - /* Test vector 12: r = p */ - static const unsigned char pkbuf[33] = { - 0x02, - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59, - }; - - static const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89, - }; - - static const unsigned char sig[64] = { - 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, 0xFF, 0xFF, 0xFF, 0xFC, 0x2F, - 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, - 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, - 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, - 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD, - }; - - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey) == 0); - } - - { - /* Test vector 13: s = n */ - static const unsigned char pkbuf[33] = { - 0x02, - 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, - 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, - 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, - 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59, - }; - - static const unsigned char msg[32] = { - 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, - 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, - 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, - 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89, - }; - - static const unsigned char sig[64] = { - 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, - 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, - 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, - 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, - 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, 0x41, - }; - - secp256k1_pubkey pubkey; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pkbuf, 33)); - CHECK(secp256k1_schnorr_verify(ctx, sig, msg, &pubkey) == 0); - } -} - -void test_ecdsa_schnorr_nonce() -{ - /* Verify that Schnorr signature and ECDSA do not use the same nonce as nonce_function_rfc6979 - * Compute 'r' using nonce_function_rfc6979 and using ecdsa and schnorr signatures. - * Verify that the 'r' values are different from nonce_function_rfc6979 - * Recover the private key : x = (±ss'-z)/(r±s'e) mod n. - */ - - unsigned char message[32] = "10000000000000000000000000000000" ; - unsigned char privkey[32]; - unsigned char schnorr_signature[64]; - secp256k1_ecdsa_signature ecdsa_signature; - unsigned char nonce1[32], nonce2[32]; - secp256k1_pubkey pubkey; - - secp256k1_scalar k1, k2; - secp256k1_gej Rj; - secp256k1_ge Ra1, Ra2; - - /* Generate a random key */ - { - secp256k1_scalar key; - random_scalar_order_test(&key); - secp256k1_scalar_get_b32(privkey, &key); - } - - /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); - - /* default R */ - nonce_function_rfc6979(nonce1, message, privkey, NULL, NULL, 0); - secp256k1_scalar_set_b32(&k1, nonce1, NULL); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Rj, &k1); - secp256k1_ge_set_gej(&Ra1, &Rj); - - /* recompute R */ - nonce_function_rfc6979(nonce2, message, privkey, NULL, NULL, 0); - secp256k1_scalar_set_b32(&k2, nonce2, NULL); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Rj, &k2); - secp256k1_ge_set_gej(&Ra2, &Rj); - - /* both are equal */ - CHECK(memcmp(&k1, &k2, 32) == 0); - CHECK(memcmp(&Ra1.x, &Ra2.x, 32) == 0); - - /* Schnorr sign. */ - CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1); - - /* ECDSA sign */ - CHECK(secp256k1_ecdsa_sign(ctx, &ecdsa_signature, message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &ecdsa_signature, message, &pubkey) == 1); - - /* verify R is not the default */ - CHECK(memcmp(&Ra1.x, schnorr_signature, 32) != 0); - CHECK(memcmp(&Ra1.x, (void*)&ecdsa_signature, 32) != 0); - CHECK(memcmp(schnorr_signature, (void*)&ecdsa_signature, 32) != 0); -} - -void run_schnorr_tests(void) { - int i; - for (i = 0; i < 32 * count; i++) { - test_schnorr_end_to_end(); - } - - test_schnorr_api(); - run_schnorr_compact_test(); - test_ecdsa_schnorr_nonce(); -} - -#endif diff --git a/src/secp256k1/src/num.h b/src/secp256k1/src/num.h deleted file mode 100644 index 49f2dd791d..0000000000 --- a/src/secp256k1/src/num.h +++ /dev/null @@ -1,74 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_NUM_H -#define SECP256K1_NUM_H - -#ifndef USE_NUM_NONE - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#if defined(USE_NUM_GMP) -#include "num_gmp.h" -#else -#error "Please select num implementation" -#endif - -/** Copy a number. */ -static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a); - -/** Convert a number's absolute value to a binary big-endian string. - * There must be enough place. */ -static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a); - -/** Set a number to the value of a binary big-endian string. */ -static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen); - -/** 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); - -/** Test whether two number are equal (including sign). */ -static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b); - -/** Add two (signed) numbers. */ -static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); - -/** Subtract two (signed) numbers. */ -static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); - -/** Multiply two (signed) numbers. */ -static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); - -/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1, - even if r was negative. */ -static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m); - -/** Right-shift the passed number by bits bits. */ -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); - -/** Change a number's sign. */ -static void secp256k1_num_negate(secp256k1_num *r); - -#endif - -#endif /* SECP256K1_NUM_H */ diff --git a/src/secp256k1/src/num_gmp.h b/src/secp256k1/src/num_gmp.h deleted file mode 100644 index 3619844bd5..0000000000 --- a/src/secp256k1/src/num_gmp.h +++ /dev/null @@ -1,20 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_NUM_REPR_H -#define SECP256K1_NUM_REPR_H - -#include - -#define NUM_LIMBS ((256+GMP_NUMB_BITS-1)/GMP_NUMB_BITS) - -typedef struct { - mp_limb_t data[2*NUM_LIMBS]; - int neg; - int limbs; -} secp256k1_num; - -#endif /* SECP256K1_NUM_REPR_H */ diff --git a/src/secp256k1/src/num_gmp_impl.h b/src/secp256k1/src/num_gmp_impl.h deleted file mode 100644 index 0ae2a8ba0e..0000000000 --- a/src/secp256k1/src/num_gmp_impl.h +++ /dev/null @@ -1,288 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_NUM_REPR_IMPL_H -#define SECP256K1_NUM_REPR_IMPL_H - -#include -#include -#include - -#include "util.h" -#include "num.h" - -#ifdef VERIFY -static void secp256k1_num_sanity(const secp256k1_num *a) { - VERIFY_CHECK(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0)); -} -#else -#define secp256k1_num_sanity(a) do { } while(0) -#endif - -static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a) { - *r = *a; -} - -static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a) { - unsigned char tmp[65]; - int len = 0; - int shift = 0; - if (a->limbs>1 || a->data[0] != 0) { - len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs); - } - while (shift < len && tmp[shift] == 0) shift++; - VERIFY_CHECK(len-shift <= (int)rlen); - memset(r, 0, rlen - len + shift); - if (len > shift) { - memcpy(r + rlen - len + shift, tmp + shift, len - shift); - } - memset(tmp, 0, sizeof(tmp)); -} - -static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen) { - int len; - VERIFY_CHECK(alen > 0); - VERIFY_CHECK(alen <= 64); - len = mpn_set_str(r->data, a, alen, 256); - if (len == 0) { - r->data[0] = 0; - len = 1; - } - VERIFY_CHECK(len <= NUM_LIMBS*2); - r->limbs = len; - r->neg = 0; - while (r->limbs > 1 && r->data[r->limbs-1]==0) { - r->limbs--; - } -} - -static void secp256k1_num_add_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { - mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs); - r->limbs = a->limbs; - if (c != 0) { - VERIFY_CHECK(r->limbs < 2*NUM_LIMBS); - r->data[r->limbs++] = c; - } -} - -static void secp256k1_num_sub_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { - mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs); - (void)c; - VERIFY_CHECK(c == 0); - r->limbs = a->limbs; - while (r->limbs > 1 && r->data[r->limbs-1]==0) { - r->limbs--; - } -} - -static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m) { - secp256k1_num_sanity(r); - secp256k1_num_sanity(m); - - if (r->limbs >= m->limbs) { - mp_limb_t t[2*NUM_LIMBS]; - mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs); - memset(t, 0, sizeof(t)); - r->limbs = m->limbs; - while (r->limbs > 1 && r->data[r->limbs-1]==0) { - r->limbs--; - } - } - - if (r->neg && (r->limbs > 1 || r->data[0] != 0)) { - secp256k1_num_sub_abs(r, m, r); - r->neg = 0; - } -} - -static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m) { - int i; - mp_limb_t g[NUM_LIMBS+1]; - mp_limb_t u[NUM_LIMBS+1]; - mp_limb_t v[NUM_LIMBS+1]; - mp_size_t sn; - mp_size_t gn; - secp256k1_num_sanity(a); - secp256k1_num_sanity(m); - - /** mpn_gcdext computes: (G,S) = gcdext(U,V), where - * * G = gcd(U,V) - * * G = U*S + V*T - * * U has equal or more limbs than V, and V has no padding - * If we set U to be (a padded version of) a, and V = m: - * G = a*S + m*T - * G = a*S mod m - * Assuming G=1: - * S = 1/a mod m - */ - VERIFY_CHECK(m->limbs <= NUM_LIMBS); - VERIFY_CHECK(m->data[m->limbs-1] != 0); - for (i = 0; i < m->limbs; i++) { - u[i] = (i < a->limbs) ? a->data[i] : 0; - v[i] = m->data[i]; - } - sn = NUM_LIMBS+1; - gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs); - (void)gn; - VERIFY_CHECK(gn == 1); - VERIFY_CHECK(g[0] == 1); - r->neg = a->neg ^ m->neg; - if (sn < 0) { - mpn_sub(r->data, m->data, m->limbs, r->data, -sn); - r->limbs = m->limbs; - while (r->limbs > 1 && r->data[r->limbs-1]==0) { - r->limbs--; - } - } else { - r->limbs = sn; - } - memset(g, 0, sizeof(g)); - memset(u, 0, sizeof(u)); - 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); -} - -static int secp256k1_num_is_neg(const secp256k1_num *a) { - return (a->limbs > 1 || a->data[0] != 0) && a->neg; -} - -static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b) { - if (a->limbs > b->limbs) { - return 1; - } - if (a->limbs < b->limbs) { - return -1; - } - return mpn_cmp(a->data, b->data, a->limbs); -} - -static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b) { - if (a->limbs > b->limbs) { - return 0; - } - if (a->limbs < b->limbs) { - return 0; - } - if ((a->neg && !secp256k1_num_is_zero(a)) != (b->neg && !secp256k1_num_is_zero(b))) { - return 0; - } - return mpn_cmp(a->data, b->data, a->limbs) == 0; -} - -static void secp256k1_num_subadd(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b, int bneg) { - if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */ - r->neg = a->neg; - if (a->limbs >= b->limbs) { - secp256k1_num_add_abs(r, a, b); - } else { - secp256k1_num_add_abs(r, b, a); - } - } else { - if (secp256k1_num_cmp(a, b) > 0) { - r->neg = a->neg; - secp256k1_num_sub_abs(r, a, b); - } else { - r->neg = b->neg ^ bneg; - secp256k1_num_sub_abs(r, b, a); - } - } -} - -static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { - secp256k1_num_sanity(a); - secp256k1_num_sanity(b); - secp256k1_num_subadd(r, a, b, 0); -} - -static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { - secp256k1_num_sanity(a); - secp256k1_num_sanity(b); - secp256k1_num_subadd(r, a, b, 1); -} - -static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { - mp_limb_t tmp[2*NUM_LIMBS+1]; - secp256k1_num_sanity(a); - secp256k1_num_sanity(b); - - VERIFY_CHECK(a->limbs + b->limbs <= 2*NUM_LIMBS+1); - if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) { - r->limbs = 1; - r->neg = 0; - r->data[0] = 0; - return; - } - if (a->limbs >= b->limbs) { - mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs); - } else { - mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs); - } - r->limbs = a->limbs + b->limbs; - if (r->limbs > 1 && tmp[r->limbs - 1]==0) { - r->limbs--; - } - VERIFY_CHECK(r->limbs <= 2*NUM_LIMBS); - mpn_copyi(r->data, tmp, r->limbs); - r->neg = a->neg ^ b->neg; - memset(tmp, 0, sizeof(tmp)); -} - -static void secp256k1_num_shift(secp256k1_num *r, int bits) { - if (bits % GMP_NUMB_BITS) { - /* Shift within limbs. */ - mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS); - } - if (bits >= GMP_NUMB_BITS) { - int i; - /* Shift full limbs. */ - for (i = 0; i < r->limbs; i++) { - int index = i + (bits / GMP_NUMB_BITS); - if (index < r->limbs && index < 2*NUM_LIMBS) { - r->data[i] = r->data[index]; - } else { - r->data[i] = 0; - } - } - } - while (r->limbs>1 && r->data[r->limbs-1]==0) { - r->limbs--; - } -} - -static void secp256k1_num_negate(secp256k1_num *r) { - r->neg ^= 1; -} - -#endif /* SECP256K1_NUM_REPR_IMPL_H */ diff --git a/src/secp256k1/src/num_impl.h b/src/secp256k1/src/num_impl.h deleted file mode 100644 index c45193b033..0000000000 --- a/src/secp256k1/src/num_impl.h +++ /dev/null @@ -1,24 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_NUM_IMPL_H -#define SECP256K1_NUM_IMPL_H - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#include "num.h" - -#if defined(USE_NUM_GMP) -#include "num_gmp_impl.h" -#elif defined(USE_NUM_NONE) -/* Nothing. */ -#else -#error "Please select num implementation" -#endif - -#endif /* SECP256K1_NUM_IMPL_H */ diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h deleted file mode 100644 index 59304cb66e..0000000000 --- a/src/secp256k1/src/scalar.h +++ /dev/null @@ -1,106 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_SCALAR_H -#define SECP256K1_SCALAR_H - -#include "num.h" - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#if defined(EXHAUSTIVE_TEST_ORDER) -#include "scalar_low.h" -#elif defined(USE_SCALAR_4X64) -#include "scalar_4x64.h" -#elif defined(USE_SCALAR_8X32) -#include "scalar_8x32.h" -#else -#error "Please select scalar implementation" -#endif - -/** Clear a scalar to prevent the leak of sensitive data. */ -static void secp256k1_scalar_clear(secp256k1_scalar *r); - -/** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */ -static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count); - -/** Access bits from a scalar. Not constant time. */ -static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count); - -/** Set a scalar from a big endian byte array. */ -static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *bin, int *overflow); - -/** Set a scalar to an unsigned integer. */ -static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v); - -/** Convert a scalar to a byte array. */ -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a); - -/** Add two scalars together (modulo the group order). Returns whether it overflowed. */ -static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); - -/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */ -static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag); - -/** Multiply two scalars (modulo the group order). */ -static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); - -/** Shift a scalar right by some amount strictly between 0 and 16, returning - * the low bits that were shifted off */ -static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n); - -/** Compute the square of a scalar (modulo the group order). */ -static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a); - -/** Compute the inverse of a scalar (modulo the group order). */ -static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a); - -/** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */ -static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *a); - -/** Compute the complement of a scalar (modulo the group order). */ -static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a); - -/** Check whether a scalar equals zero. */ -static int secp256k1_scalar_is_zero(const secp256k1_scalar *a); - -/** Check whether a scalar equals one. */ -static int secp256k1_scalar_is_one(const secp256k1_scalar *a); - -/** Check whether a scalar, considered as an nonnegative integer, is even. */ -static int secp256k1_scalar_is_even(const secp256k1_scalar *a); - -/** Check whether a scalar is higher than the group order divided by 2. */ -static int secp256k1_scalar_is_high(const secp256k1_scalar *a); - -/** Conditionally negate a number, in constant time. - * Returns -1 if the number was negated, 1 otherwise */ -static int secp256k1_scalar_cond_negate(secp256k1_scalar *a, int flag); - -#ifndef USE_NUM_NONE -/** Convert a scalar to a number. */ -static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a); - -/** Get the order of the group as a number. */ -static void secp256k1_scalar_order_get_num(secp256k1_num *r); -#endif - -/** Compare two scalars. */ -static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b); - -#ifdef USE_ENDOMORPHISM -/** Find r1 and r2 such that r1+r2*2^128 = a. */ -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); -/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */ -static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); -#endif - -/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ -static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); - -#endif /* SECP256K1_SCALAR_H */ diff --git a/src/secp256k1/src/scalar_4x64.h b/src/secp256k1/src/scalar_4x64.h deleted file mode 100644 index 19c7495d1c..0000000000 --- a/src/secp256k1/src/scalar_4x64.h +++ /dev/null @@ -1,19 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_H -#define SECP256K1_SCALAR_REPR_H - -#include - -/** A scalar modulo the group order of the secp256k1 curve. */ -typedef struct { - uint64_t d[4]; -} secp256k1_scalar; - -#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}} - -#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h deleted file mode 100644 index db1ebf94be..0000000000 --- a/src/secp256k1/src/scalar_4x64_impl.h +++ /dev/null @@ -1,949 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_IMPL_H -#define SECP256K1_SCALAR_REPR_IMPL_H - -/* Limbs of the secp256k1 order. */ -#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) -#define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL) -#define SECP256K1_N_2 ((uint64_t)0xFFFFFFFFFFFFFFFEULL) -#define SECP256K1_N_3 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) - -/* Limbs of 2^256 minus the secp256k1 order. */ -#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) -#define SECP256K1_N_C_1 (~SECP256K1_N_1) -#define SECP256K1_N_C_2 (1) - -/* Limbs of half the secp256k1 order. */ -#define SECP256K1_N_H_0 ((uint64_t)0xDFE92F46681B20A0ULL) -#define SECP256K1_N_H_1 ((uint64_t)0x5D576E7357A4501DULL) -#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) -#define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL) - -SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { - r->d[0] = 0; - r->d[1] = 0; - r->d[2] = 0; - r->d[3] = 0; -} - -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { - r->d[0] = v; - r->d[1] = 0; - r->d[2] = 0; - r->d[3] = 0; -} - -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); - return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1); -} - -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - VERIFY_CHECK(count < 32); - VERIFY_CHECK(offset + count <= 256); - if ((offset + count - 1) >> 6 == offset >> 6) { - return secp256k1_scalar_get_bits(a, offset, count); - } else { - VERIFY_CHECK((offset >> 6) + 1 < 4); - return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & ((((uint64_t)1) << count) - 1); - } -} - -SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { - int yes = 0; - int no = 0; - no |= (a->d[3] < SECP256K1_N_3); /* No need for a > check. */ - no |= (a->d[2] < SECP256K1_N_2); - yes |= (a->d[2] > SECP256K1_N_2) & ~no; - no |= (a->d[1] < SECP256K1_N_1); - yes |= (a->d[1] > SECP256K1_N_1) & ~no; - yes |= (a->d[0] >= SECP256K1_N_0) & ~no; - return yes; -} - -SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) { - uint128_t t; - VERIFY_CHECK(overflow <= 1); - t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1; - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[2] + overflow * SECP256K1_N_C_2; - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint64_t)r->d[3]; - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; - return overflow; -} - -static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { - int overflow; - uint128_t t = (uint128_t)a->d[0] + b->d[0]; - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[1] + b->d[1]; - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[2] + b->d[2]; - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[3] + b->d[3]; - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - overflow = t + secp256k1_scalar_check_overflow(r); - VERIFY_CHECK(overflow == 0 || overflow == 1); - secp256k1_scalar_reduce(r, overflow); - return overflow; -} - -static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { - uint128_t t; - VERIFY_CHECK(bit < 256); - bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ - t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[2] + (((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F)); - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[3] + (((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F)); - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; -#ifdef VERIFY - VERIFY_CHECK((t >> 64) == 0); - VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); -#endif -} - -static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { - int over; - r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56; - r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56; - r->d[2] = (uint64_t)b32[15] | (uint64_t)b32[14] << 8 | (uint64_t)b32[13] << 16 | (uint64_t)b32[12] << 24 | (uint64_t)b32[11] << 32 | (uint64_t)b32[10] << 40 | (uint64_t)b32[9] << 48 | (uint64_t)b32[8] << 56; - r->d[3] = (uint64_t)b32[7] | (uint64_t)b32[6] << 8 | (uint64_t)b32[5] << 16 | (uint64_t)b32[4] << 24 | (uint64_t)b32[3] << 32 | (uint64_t)b32[2] << 40 | (uint64_t)b32[1] << 48 | (uint64_t)b32[0] << 56; - over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); - if (overflow) { - *overflow = over; - } -} - -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { - bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3]; - bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2]; - bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1]; - bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; -} - -SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { - return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; -} - -static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { - uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0); - uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1; - r->d[0] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[1]) + SECP256K1_N_1; - r->d[1] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[2]) + SECP256K1_N_2; - r->d[2] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[3]) + SECP256K1_N_3; - r->d[3] = t & nonzero; -} - -SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { - return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; -} - -static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { - int yes = 0; - int no = 0; - no |= (a->d[3] < SECP256K1_N_H_3); - yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; - no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; /* No need for a > check. */ - no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; - yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; - yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; - return yes; -} - -static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { - /* If we are flag = 0, mask = 00...00 and this is a no-op; - * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ - uint64_t mask = !flag - 1; - uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; - uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); - r->d[0] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); - r->d[1] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); - r->d[2] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); - r->d[3] = t & nonzero; - return 2 * (mask == 0) - 1; -} - -/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ - -/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define muladd(a,b) { \ - uint64_t tl, th; \ - { \ - uint128_t t = (uint128_t)a * b; \ - th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ - tl = t; \ - } \ - c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ - c1 += th; /* overflow is handled on the next line */ \ - c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \ - VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ -} - -/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ -#define muladd_fast(a,b) { \ - uint64_t tl, th; \ - { \ - uint128_t t = (uint128_t)a * b; \ - th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ - tl = t; \ - } \ - c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ - c1 += th; /* never overflows by contract (verified in the next line) */ \ - VERIFY_CHECK(c1 >= th); \ -} - -/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define muladd2(a,b) { \ - uint64_t tl, th, th2, tl2; \ - { \ - uint128_t t = (uint128_t)a * b; \ - th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ - tl = t; \ - } \ - th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \ - c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ - tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \ - th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ - c0 += tl2; /* overflow is handled on the next line */ \ - th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ - c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ - c1 += th2; /* overflow is handled on the next line */ \ - c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ -} - -/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define sumadd(a) { \ - unsigned int over; \ - c0 += (a); /* overflow is handled on the next line */ \ - over = (c0 < (a)) ? 1 : 0; \ - c1 += over; /* overflow is handled on the next line */ \ - c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ -} - -/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ -#define sumadd_fast(a) { \ - c0 += (a); /* overflow is handled on the next line */ \ - c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ - VERIFY_CHECK(c2 == 0); \ -} - -/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. */ -#define extract(n) { \ - (n) = c0; \ - c0 = c1; \ - c1 = c2; \ - c2 = 0; \ -} - -/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. c2 is required to be zero. */ -#define extract_fast(n) { \ - (n) = c0; \ - c0 = c1; \ - c1 = 0; \ - VERIFY_CHECK(c2 == 0); \ -} - -static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) { -#ifdef USE_ASM_X86_64 - /* Reduce 512 bits into 385. */ - uint64_t m0, m1, m2, m3, m4, m5, m6; - uint64_t p0, p1, p2, p3, p4; - uint64_t c; - - __asm__ __volatile__( - /* Preload. */ - "movq 32(%%rsi), %%r11\n" - "movq 40(%%rsi), %%r12\n" - "movq 48(%%rsi), %%r13\n" - "movq 56(%%rsi), %%r14\n" - /* Initialize r8,r9,r10 */ - "movq 0(%%rsi), %%r8\n" - "xorq %%r9, %%r9\n" - "xorq %%r10, %%r10\n" - /* (r8,r9) += n0 * c0 */ - "movq %8, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - /* extract m0 */ - "movq %%r8, %q0\n" - "xorq %%r8, %%r8\n" - /* (r9,r10) += l1 */ - "addq 8(%%rsi), %%r9\n" - "adcq $0, %%r10\n" - /* (r9,r10,r8) += n1 * c0 */ - "movq %8, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += n0 * c1 */ - "movq %9, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* extract m1 */ - "movq %%r9, %q1\n" - "xorq %%r9, %%r9\n" - /* (r10,r8,r9) += l2 */ - "addq 16(%%rsi), %%r10\n" - "adcq $0, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += n2 * c0 */ - "movq %8, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += n1 * c1 */ - "movq %9, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += n0 */ - "addq %%r11, %%r10\n" - "adcq $0, %%r8\n" - "adcq $0, %%r9\n" - /* extract m2 */ - "movq %%r10, %q2\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += l3 */ - "addq 24(%%rsi), %%r8\n" - "adcq $0, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += n3 * c0 */ - "movq %8, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += n2 * c1 */ - "movq %9, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += n1 */ - "addq %%r12, %%r8\n" - "adcq $0, %%r9\n" - "adcq $0, %%r10\n" - /* extract m3 */ - "movq %%r8, %q3\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += n3 * c1 */ - "movq %9, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += n2 */ - "addq %%r13, %%r9\n" - "adcq $0, %%r10\n" - "adcq $0, %%r8\n" - /* extract m4 */ - "movq %%r9, %q4\n" - /* (r10,r8) += n3 */ - "addq %%r14, %%r10\n" - "adcq $0, %%r8\n" - /* extract m5 */ - "movq %%r10, %q5\n" - /* extract m6 */ - "movq %%r8, %q6\n" - : "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6) - : "S"(l), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) - : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc"); - - /* Reduce 385 bits into 258. */ - __asm__ __volatile__( - /* Preload */ - "movq %q9, %%r11\n" - "movq %q10, %%r12\n" - "movq %q11, %%r13\n" - /* Initialize (r8,r9,r10) */ - "movq %q5, %%r8\n" - "xorq %%r9, %%r9\n" - "xorq %%r10, %%r10\n" - /* (r8,r9) += m4 * c0 */ - "movq %12, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - /* extract p0 */ - "movq %%r8, %q0\n" - "xorq %%r8, %%r8\n" - /* (r9,r10) += m1 */ - "addq %q6, %%r9\n" - "adcq $0, %%r10\n" - /* (r9,r10,r8) += m5 * c0 */ - "movq %12, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += m4 * c1 */ - "movq %13, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* extract p1 */ - "movq %%r9, %q1\n" - "xorq %%r9, %%r9\n" - /* (r10,r8,r9) += m2 */ - "addq %q7, %%r10\n" - "adcq $0, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += m6 * c0 */ - "movq %12, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += m5 * c1 */ - "movq %13, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += m4 */ - "addq %%r11, %%r10\n" - "adcq $0, %%r8\n" - "adcq $0, %%r9\n" - /* extract p2 */ - "movq %%r10, %q2\n" - /* (r8,r9) += m3 */ - "addq %q8, %%r8\n" - "adcq $0, %%r9\n" - /* (r8,r9) += m6 * c1 */ - "movq %13, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - /* (r8,r9) += m5 */ - "addq %%r12, %%r8\n" - "adcq $0, %%r9\n" - /* extract p3 */ - "movq %%r8, %q3\n" - /* (r9) += m6 */ - "addq %%r13, %%r9\n" - /* extract p4 */ - "movq %%r9, %q4\n" - : "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4) - : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) - : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc"); - - /* Reduce 258 bits into 256. */ - __asm__ __volatile__( - /* Preload */ - "movq %q5, %%r10\n" - /* (rax,rdx) = p4 * c0 */ - "movq %7, %%rax\n" - "mulq %%r10\n" - /* (rax,rdx) += p0 */ - "addq %q1, %%rax\n" - "adcq $0, %%rdx\n" - /* extract r0 */ - "movq %%rax, 0(%q6)\n" - /* Move to (r8,r9) */ - "movq %%rdx, %%r8\n" - "xorq %%r9, %%r9\n" - /* (r8,r9) += p1 */ - "addq %q2, %%r8\n" - "adcq $0, %%r9\n" - /* (r8,r9) += p4 * c1 */ - "movq %8, %%rax\n" - "mulq %%r10\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - /* Extract r1 */ - "movq %%r8, 8(%q6)\n" - "xorq %%r8, %%r8\n" - /* (r9,r8) += p4 */ - "addq %%r10, %%r9\n" - "adcq $0, %%r8\n" - /* (r9,r8) += p2 */ - "addq %q3, %%r9\n" - "adcq $0, %%r8\n" - /* Extract r2 */ - "movq %%r9, 16(%q6)\n" - "xorq %%r9, %%r9\n" - /* (r8,r9) += p3 */ - "addq %q4, %%r8\n" - "adcq $0, %%r9\n" - /* Extract r3 */ - "movq %%r8, 24(%q6)\n" - /* Extract c */ - "movq %%r9, %q0\n" - : "=g"(c) - : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) - : "rax", "rdx", "r8", "r9", "r10", "cc", "memory"); -#else - uint128_t c; - uint64_t c0, c1, c2; - uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7]; - uint64_t m0, m1, m2, m3, m4, m5; - uint32_t m6; - uint64_t p0, p1, p2, p3; - uint32_t p4; - - /* Reduce 512 bits into 385. */ - /* m[0..6] = l[0..3] + n[0..3] * SECP256K1_N_C. */ - c0 = l[0]; c1 = 0; c2 = 0; - muladd_fast(n0, SECP256K1_N_C_0); - extract_fast(m0); - sumadd_fast(l[1]); - muladd(n1, SECP256K1_N_C_0); - muladd(n0, SECP256K1_N_C_1); - extract(m1); - sumadd(l[2]); - muladd(n2, SECP256K1_N_C_0); - muladd(n1, SECP256K1_N_C_1); - sumadd(n0); - extract(m2); - sumadd(l[3]); - muladd(n3, SECP256K1_N_C_0); - muladd(n2, SECP256K1_N_C_1); - sumadd(n1); - extract(m3); - muladd(n3, SECP256K1_N_C_1); - sumadd(n2); - extract(m4); - sumadd_fast(n3); - extract_fast(m5); - VERIFY_CHECK(c0 <= 1); - m6 = c0; - - /* Reduce 385 bits into 258. */ - /* p[0..4] = m[0..3] + m[4..6] * SECP256K1_N_C. */ - c0 = m0; c1 = 0; c2 = 0; - muladd_fast(m4, SECP256K1_N_C_0); - extract_fast(p0); - sumadd_fast(m1); - muladd(m5, SECP256K1_N_C_0); - muladd(m4, SECP256K1_N_C_1); - extract(p1); - sumadd(m2); - muladd(m6, SECP256K1_N_C_0); - muladd(m5, SECP256K1_N_C_1); - sumadd(m4); - extract(p2); - sumadd_fast(m3); - muladd_fast(m6, SECP256K1_N_C_1); - sumadd_fast(m5); - extract_fast(p3); - p4 = c0 + m6; - VERIFY_CHECK(p4 <= 2); - - /* Reduce 258 bits into 256. */ - /* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */ - c = p0 + (uint128_t)SECP256K1_N_C_0 * p4; - r->d[0] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; - c += p1 + (uint128_t)SECP256K1_N_C_1 * p4; - r->d[1] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; - c += p2 + (uint128_t)p4; - r->d[2] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; - c += p3; - r->d[3] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; -#endif - - /* Final reduction of r. */ - secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); -} - -static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, const secp256k1_scalar *b) { -#ifdef USE_ASM_X86_64 - const uint64_t *pb = b->d; - __asm__ __volatile__( - /* Preload */ - "movq 0(%%rdi), %%r15\n" - "movq 8(%%rdi), %%rbx\n" - "movq 16(%%rdi), %%rcx\n" - "movq 0(%%rdx), %%r11\n" - "movq 8(%%rdx), %%r12\n" - "movq 16(%%rdx), %%r13\n" - "movq 24(%%rdx), %%r14\n" - /* (rax,rdx) = a0 * b0 */ - "movq %%r15, %%rax\n" - "mulq %%r11\n" - /* Extract l0 */ - "movq %%rax, 0(%%rsi)\n" - /* (r8,r9,r10) = (rdx) */ - "movq %%rdx, %%r8\n" - "xorq %%r9, %%r9\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += a0 * b1 */ - "movq %%r15, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += a1 * b0 */ - "movq %%rbx, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* Extract l1 */ - "movq %%r8, 8(%%rsi)\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += a0 * b2 */ - "movq %%r15, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += a1 * b1 */ - "movq %%rbx, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += a2 * b0 */ - "movq %%rcx, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* Extract l2 */ - "movq %%r9, 16(%%rsi)\n" - "xorq %%r9, %%r9\n" - /* (r10,r8,r9) += a0 * b3 */ - "movq %%r15, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* Preload a3 */ - "movq 24(%%rdi), %%r15\n" - /* (r10,r8,r9) += a1 * b2 */ - "movq %%rbx, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += a2 * b1 */ - "movq %%rcx, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += a3 * b0 */ - "movq %%r15, %%rax\n" - "mulq %%r11\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* Extract l3 */ - "movq %%r10, 24(%%rsi)\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += a1 * b3 */ - "movq %%rbx, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += a2 * b2 */ - "movq %%rcx, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += a3 * b1 */ - "movq %%r15, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* Extract l4 */ - "movq %%r8, 32(%%rsi)\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += a2 * b3 */ - "movq %%rcx, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += a3 * b2 */ - "movq %%r15, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* Extract l5 */ - "movq %%r9, 40(%%rsi)\n" - /* (r10,r8) += a3 * b3 */ - "movq %%r15, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - /* Extract l6 */ - "movq %%r10, 48(%%rsi)\n" - /* Extract l7 */ - "movq %%r8, 56(%%rsi)\n" - : "+d"(pb) - : "S"(l), "D"(a->d) - : "rax", "rbx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "cc", "memory"); -#else - /* 160 bit accumulator. */ - uint64_t c0 = 0, c1 = 0; - uint32_t c2 = 0; - - /* l[0..7] = a[0..3] * b[0..3]. */ - muladd_fast(a->d[0], b->d[0]); - extract_fast(l[0]); - muladd(a->d[0], b->d[1]); - muladd(a->d[1], b->d[0]); - extract(l[1]); - muladd(a->d[0], b->d[2]); - muladd(a->d[1], b->d[1]); - muladd(a->d[2], b->d[0]); - extract(l[2]); - muladd(a->d[0], b->d[3]); - muladd(a->d[1], b->d[2]); - muladd(a->d[2], b->d[1]); - muladd(a->d[3], b->d[0]); - extract(l[3]); - muladd(a->d[1], b->d[3]); - muladd(a->d[2], b->d[2]); - muladd(a->d[3], b->d[1]); - extract(l[4]); - muladd(a->d[2], b->d[3]); - muladd(a->d[3], b->d[2]); - extract(l[5]); - muladd_fast(a->d[3], b->d[3]); - extract_fast(l[6]); - VERIFY_CHECK(c1 == 0); - l[7] = c0; -#endif -} - -static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar *a) { -#ifdef USE_ASM_X86_64 - __asm__ __volatile__( - /* Preload */ - "movq 0(%%rdi), %%r11\n" - "movq 8(%%rdi), %%r12\n" - "movq 16(%%rdi), %%r13\n" - "movq 24(%%rdi), %%r14\n" - /* (rax,rdx) = a0 * a0 */ - "movq %%r11, %%rax\n" - "mulq %%r11\n" - /* Extract l0 */ - "movq %%rax, 0(%%rsi)\n" - /* (r8,r9,r10) = (rdx,0) */ - "movq %%rdx, %%r8\n" - "xorq %%r9, %%r9\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += 2 * a0 * a1 */ - "movq %%r11, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* Extract l1 */ - "movq %%r8, 8(%%rsi)\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += 2 * a0 * a2 */ - "movq %%r11, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* (r9,r10,r8) += a1 * a1 */ - "movq %%r12, %%rax\n" - "mulq %%r12\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* Extract l2 */ - "movq %%r9, 16(%%rsi)\n" - "xorq %%r9, %%r9\n" - /* (r10,r8,r9) += 2 * a0 * a3 */ - "movq %%r11, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* (r10,r8,r9) += 2 * a1 * a2 */ - "movq %%r12, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - "adcq $0, %%r9\n" - /* Extract l3 */ - "movq %%r10, 24(%%rsi)\n" - "xorq %%r10, %%r10\n" - /* (r8,r9,r10) += 2 * a1 * a3 */ - "movq %%r12, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* (r8,r9,r10) += a2 * a2 */ - "movq %%r13, %%rax\n" - "mulq %%r13\n" - "addq %%rax, %%r8\n" - "adcq %%rdx, %%r9\n" - "adcq $0, %%r10\n" - /* Extract l4 */ - "movq %%r8, 32(%%rsi)\n" - "xorq %%r8, %%r8\n" - /* (r9,r10,r8) += 2 * a2 * a3 */ - "movq %%r13, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - "addq %%rax, %%r9\n" - "adcq %%rdx, %%r10\n" - "adcq $0, %%r8\n" - /* Extract l5 */ - "movq %%r9, 40(%%rsi)\n" - /* (r10,r8) += a3 * a3 */ - "movq %%r14, %%rax\n" - "mulq %%r14\n" - "addq %%rax, %%r10\n" - "adcq %%rdx, %%r8\n" - /* Extract l6 */ - "movq %%r10, 48(%%rsi)\n" - /* Extract l7 */ - "movq %%r8, 56(%%rsi)\n" - : - : "S"(l), "D"(a->d) - : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc", "memory"); -#else - /* 160 bit accumulator. */ - uint64_t c0 = 0, c1 = 0; - uint32_t c2 = 0; - - /* l[0..7] = a[0..3] * b[0..3]. */ - muladd_fast(a->d[0], a->d[0]); - extract_fast(l[0]); - muladd2(a->d[0], a->d[1]); - extract(l[1]); - muladd2(a->d[0], a->d[2]); - muladd(a->d[1], a->d[1]); - extract(l[2]); - muladd2(a->d[0], a->d[3]); - muladd2(a->d[1], a->d[2]); - extract(l[3]); - muladd2(a->d[1], a->d[3]); - muladd(a->d[2], a->d[2]); - extract(l[4]); - muladd2(a->d[2], a->d[3]); - extract(l[5]); - muladd_fast(a->d[3], a->d[3]); - extract_fast(l[6]); - VERIFY_CHECK(c1 == 0); - l[7] = c0; -#endif -} - -#undef sumadd -#undef sumadd_fast -#undef muladd -#undef muladd_fast -#undef muladd2 -#undef extract -#undef extract_fast - -static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { - uint64_t l[8]; - secp256k1_scalar_mul_512(l, a, b); - secp256k1_scalar_reduce_512(r, l); -} - -static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { - int ret; - VERIFY_CHECK(n > 0); - VERIFY_CHECK(n < 16); - ret = r->d[0] & ((1 << n) - 1); - r->d[0] = (r->d[0] >> n) + (r->d[1] << (64 - n)); - r->d[1] = (r->d[1] >> n) + (r->d[2] << (64 - n)); - r->d[2] = (r->d[2] >> n) + (r->d[3] << (64 - n)); - r->d[3] = (r->d[3] >> n); - return ret; -} - -static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { - uint64_t l[8]; - secp256k1_scalar_sqr_512(l, a); - secp256k1_scalar_reduce_512(r, l); -} - -#ifdef USE_ENDOMORPHISM -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { - r1->d[0] = a->d[0]; - r1->d[1] = a->d[1]; - r1->d[2] = 0; - r1->d[3] = 0; - r2->d[0] = a->d[2]; - r2->d[1] = a->d[3]; - r2->d[2] = 0; - r2->d[3] = 0; -} -#endif - -SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { - return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; -} - -SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { - uint64_t l[8]; - unsigned int shiftlimbs; - unsigned int shiftlow; - unsigned int shifthigh; - VERIFY_CHECK(shift >= 256); - secp256k1_scalar_mul_512(l, a, b); - shiftlimbs = shift >> 6; - shiftlow = shift & 0x3F; - shifthigh = 64 - shiftlow; - r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; - secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); -} - -#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/secp256k1/src/scalar_8x32.h b/src/secp256k1/src/scalar_8x32.h deleted file mode 100644 index 2c9a348e24..0000000000 --- a/src/secp256k1/src/scalar_8x32.h +++ /dev/null @@ -1,19 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_H -#define SECP256K1_SCALAR_REPR_H - -#include - -/** A scalar modulo the group order of the secp256k1 curve. */ -typedef struct { - uint32_t d[8]; -} secp256k1_scalar; - -#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} - -#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h deleted file mode 100644 index 4f9ed61fea..0000000000 --- a/src/secp256k1/src/scalar_8x32_impl.h +++ /dev/null @@ -1,721 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_IMPL_H -#define SECP256K1_SCALAR_REPR_IMPL_H - -/* Limbs of the secp256k1 order. */ -#define SECP256K1_N_0 ((uint32_t)0xD0364141UL) -#define SECP256K1_N_1 ((uint32_t)0xBFD25E8CUL) -#define SECP256K1_N_2 ((uint32_t)0xAF48A03BUL) -#define SECP256K1_N_3 ((uint32_t)0xBAAEDCE6UL) -#define SECP256K1_N_4 ((uint32_t)0xFFFFFFFEUL) -#define SECP256K1_N_5 ((uint32_t)0xFFFFFFFFUL) -#define SECP256K1_N_6 ((uint32_t)0xFFFFFFFFUL) -#define SECP256K1_N_7 ((uint32_t)0xFFFFFFFFUL) - -/* Limbs of 2^256 minus the secp256k1 order. */ -#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) -#define SECP256K1_N_C_1 (~SECP256K1_N_1) -#define SECP256K1_N_C_2 (~SECP256K1_N_2) -#define SECP256K1_N_C_3 (~SECP256K1_N_3) -#define SECP256K1_N_C_4 (1) - -/* Limbs of half the secp256k1 order. */ -#define SECP256K1_N_H_0 ((uint32_t)0x681B20A0UL) -#define SECP256K1_N_H_1 ((uint32_t)0xDFE92F46UL) -#define SECP256K1_N_H_2 ((uint32_t)0x57A4501DUL) -#define SECP256K1_N_H_3 ((uint32_t)0x5D576E73UL) -#define SECP256K1_N_H_4 ((uint32_t)0xFFFFFFFFUL) -#define SECP256K1_N_H_5 ((uint32_t)0xFFFFFFFFUL) -#define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL) -#define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL) - -SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { - r->d[0] = 0; - r->d[1] = 0; - r->d[2] = 0; - r->d[3] = 0; - r->d[4] = 0; - r->d[5] = 0; - r->d[6] = 0; - r->d[7] = 0; -} - -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { - r->d[0] = v; - r->d[1] = 0; - r->d[2] = 0; - r->d[3] = 0; - r->d[4] = 0; - r->d[5] = 0; - r->d[6] = 0; - r->d[7] = 0; -} - -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); - return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1); -} - -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - VERIFY_CHECK(count < 32); - VERIFY_CHECK(offset + count <= 256); - if ((offset + count - 1) >> 5 == offset >> 5) { - return secp256k1_scalar_get_bits(a, offset, count); - } else { - VERIFY_CHECK((offset >> 5) + 1 < 8); - return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & ((((uint32_t)1) << count) - 1); - } -} - -SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { - int yes = 0; - int no = 0; - no |= (a->d[7] < SECP256K1_N_7); /* No need for a > check. */ - no |= (a->d[6] < SECP256K1_N_6); /* No need for a > check. */ - no |= (a->d[5] < SECP256K1_N_5); /* No need for a > check. */ - no |= (a->d[4] < SECP256K1_N_4); - yes |= (a->d[4] > SECP256K1_N_4) & ~no; - no |= (a->d[3] < SECP256K1_N_3) & ~yes; - yes |= (a->d[3] > SECP256K1_N_3) & ~no; - no |= (a->d[2] < SECP256K1_N_2) & ~yes; - yes |= (a->d[2] > SECP256K1_N_2) & ~no; - no |= (a->d[1] < SECP256K1_N_1) & ~yes; - yes |= (a->d[1] > SECP256K1_N_1) & ~no; - yes |= (a->d[0] >= SECP256K1_N_0) & ~no; - return yes; -} - -SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_t overflow) { - uint64_t t; - VERIFY_CHECK(overflow <= 1); - t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; - r->d[0] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1; - r->d[1] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[2] + overflow * SECP256K1_N_C_2; - r->d[2] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[3] + overflow * SECP256K1_N_C_3; - r->d[3] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[4] + overflow * SECP256K1_N_C_4; - r->d[4] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[5]; - r->d[5] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[6]; - r->d[6] = t & 0xFFFFFFFFUL; t >>= 32; - t += (uint64_t)r->d[7]; - r->d[7] = t & 0xFFFFFFFFUL; - return overflow; -} - -static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { - int overflow; - uint64_t t = (uint64_t)a->d[0] + b->d[0]; - r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[1] + b->d[1]; - r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[2] + b->d[2]; - r->d[2] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[3] + b->d[3]; - r->d[3] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[4] + b->d[4]; - r->d[4] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[5] + b->d[5]; - r->d[5] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[6] + b->d[6]; - r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)a->d[7] + b->d[7]; - r->d[7] = t & 0xFFFFFFFFULL; t >>= 32; - overflow = t + secp256k1_scalar_check_overflow(r); - VERIFY_CHECK(overflow == 0 || overflow == 1); - secp256k1_scalar_reduce(r, overflow); - return overflow; -} - -static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { - uint64_t t; - VERIFY_CHECK(bit < 256); - bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ - t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); - r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F)); - r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[2] + (((uint32_t)((bit >> 5) == 2)) << (bit & 0x1F)); - r->d[2] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[3] + (((uint32_t)((bit >> 5) == 3)) << (bit & 0x1F)); - r->d[3] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[4] + (((uint32_t)((bit >> 5) == 4)) << (bit & 0x1F)); - r->d[4] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[5] + (((uint32_t)((bit >> 5) == 5)) << (bit & 0x1F)); - r->d[5] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[6] + (((uint32_t)((bit >> 5) == 6)) << (bit & 0x1F)); - r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; - t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F)); - r->d[7] = t & 0xFFFFFFFFULL; -#ifdef VERIFY - VERIFY_CHECK((t >> 32) == 0); - VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); -#endif -} - -static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { - int over; - r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24; - r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24; - r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24; - r->d[3] = (uint32_t)b32[19] | (uint32_t)b32[18] << 8 | (uint32_t)b32[17] << 16 | (uint32_t)b32[16] << 24; - r->d[4] = (uint32_t)b32[15] | (uint32_t)b32[14] << 8 | (uint32_t)b32[13] << 16 | (uint32_t)b32[12] << 24; - r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24; - r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24; - r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24; - over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); - if (overflow) { - *overflow = over; - } -} - -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { - bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7]; - bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6]; - bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5]; - bin[12] = a->d[4] >> 24; bin[13] = a->d[4] >> 16; bin[14] = a->d[4] >> 8; bin[15] = a->d[4]; - bin[16] = a->d[3] >> 24; bin[17] = a->d[3] >> 16; bin[18] = a->d[3] >> 8; bin[19] = a->d[3]; - bin[20] = a->d[2] >> 24; bin[21] = a->d[2] >> 16; bin[22] = a->d[2] >> 8; bin[23] = a->d[2]; - bin[24] = a->d[1] >> 24; bin[25] = a->d[1] >> 16; bin[26] = a->d[1] >> 8; bin[27] = a->d[1]; - bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; -} - -SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { - return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; -} - -static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { - uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0); - uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1; - r->d[0] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[1]) + SECP256K1_N_1; - r->d[1] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[2]) + SECP256K1_N_2; - r->d[2] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[3]) + SECP256K1_N_3; - r->d[3] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[4]) + SECP256K1_N_4; - r->d[4] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[5]) + SECP256K1_N_5; - r->d[5] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[6]) + SECP256K1_N_6; - r->d[6] = t & nonzero; t >>= 32; - t += (uint64_t)(~a->d[7]) + SECP256K1_N_7; - r->d[7] = t & nonzero; -} - -SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { - return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; -} - -static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { - int yes = 0; - int no = 0; - no |= (a->d[7] < SECP256K1_N_H_7); - yes |= (a->d[7] > SECP256K1_N_H_7) & ~no; - no |= (a->d[6] < SECP256K1_N_H_6) & ~yes; /* No need for a > check. */ - no |= (a->d[5] < SECP256K1_N_H_5) & ~yes; /* No need for a > check. */ - no |= (a->d[4] < SECP256K1_N_H_4) & ~yes; /* No need for a > check. */ - no |= (a->d[3] < SECP256K1_N_H_3) & ~yes; - yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; - no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; - yes |= (a->d[2] > SECP256K1_N_H_2) & ~no; - no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; - yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; - yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; - return yes; -} - -static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { - /* If we are flag = 0, mask = 00...00 and this is a no-op; - * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ - uint32_t mask = !flag - 1; - uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0); - uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); - r->d[0] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); - r->d[1] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); - r->d[2] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); - r->d[3] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[4] ^ mask) + (SECP256K1_N_4 & mask); - r->d[4] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[5] ^ mask) + (SECP256K1_N_5 & mask); - r->d[5] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[6] ^ mask) + (SECP256K1_N_6 & mask); - r->d[6] = t & nonzero; t >>= 32; - t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask); - r->d[7] = t & nonzero; - return 2 * (mask == 0) - 1; -} - - -/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ - -/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define muladd(a,b) { \ - uint32_t tl, th; \ - { \ - uint64_t t = (uint64_t)a * b; \ - th = t >> 32; /* at most 0xFFFFFFFE */ \ - tl = t; \ - } \ - c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ - c1 += th; /* overflow is handled on the next line */ \ - c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \ - VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ -} - -/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ -#define muladd_fast(a,b) { \ - uint32_t tl, th; \ - { \ - uint64_t t = (uint64_t)a * b; \ - th = t >> 32; /* at most 0xFFFFFFFE */ \ - tl = t; \ - } \ - c0 += tl; /* overflow is handled on the next line */ \ - th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ - c1 += th; /* never overflows by contract (verified in the next line) */ \ - VERIFY_CHECK(c1 >= th); \ -} - -/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define muladd2(a,b) { \ - uint32_t tl, th, th2, tl2; \ - { \ - uint64_t t = (uint64_t)a * b; \ - th = t >> 32; /* at most 0xFFFFFFFE */ \ - tl = t; \ - } \ - th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \ - c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ - tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \ - th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ - c0 += tl2; /* overflow is handled on the next line */ \ - th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ - c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ - c1 += th2; /* overflow is handled on the next line */ \ - c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ -} - -/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ -#define sumadd(a) { \ - unsigned int over; \ - c0 += (a); /* overflow is handled on the next line */ \ - over = (c0 < (a)) ? 1 : 0; \ - c1 += over; /* overflow is handled on the next line */ \ - c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ -} - -/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ -#define sumadd_fast(a) { \ - c0 += (a); /* overflow is handled on the next line */ \ - c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ - VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ - VERIFY_CHECK(c2 == 0); \ -} - -/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. */ -#define extract(n) { \ - (n) = c0; \ - c0 = c1; \ - c1 = c2; \ - c2 = 0; \ -} - -/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. c2 is required to be zero. */ -#define extract_fast(n) { \ - (n) = c0; \ - c0 = c1; \ - c1 = 0; \ - VERIFY_CHECK(c2 == 0); \ -} - -static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint32_t *l) { - uint64_t c; - uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15]; - uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12; - uint32_t p0, p1, p2, p3, p4, p5, p6, p7, p8; - - /* 96 bit accumulator. */ - uint32_t c0, c1, c2; - - /* Reduce 512 bits into 385. */ - /* m[0..12] = l[0..7] + n[0..7] * SECP256K1_N_C. */ - c0 = l[0]; c1 = 0; c2 = 0; - muladd_fast(n0, SECP256K1_N_C_0); - extract_fast(m0); - sumadd_fast(l[1]); - muladd(n1, SECP256K1_N_C_0); - muladd(n0, SECP256K1_N_C_1); - extract(m1); - sumadd(l[2]); - muladd(n2, SECP256K1_N_C_0); - muladd(n1, SECP256K1_N_C_1); - muladd(n0, SECP256K1_N_C_2); - extract(m2); - sumadd(l[3]); - muladd(n3, SECP256K1_N_C_0); - muladd(n2, SECP256K1_N_C_1); - muladd(n1, SECP256K1_N_C_2); - muladd(n0, SECP256K1_N_C_3); - extract(m3); - sumadd(l[4]); - muladd(n4, SECP256K1_N_C_0); - muladd(n3, SECP256K1_N_C_1); - muladd(n2, SECP256K1_N_C_2); - muladd(n1, SECP256K1_N_C_3); - sumadd(n0); - extract(m4); - sumadd(l[5]); - muladd(n5, SECP256K1_N_C_0); - muladd(n4, SECP256K1_N_C_1); - muladd(n3, SECP256K1_N_C_2); - muladd(n2, SECP256K1_N_C_3); - sumadd(n1); - extract(m5); - sumadd(l[6]); - muladd(n6, SECP256K1_N_C_0); - muladd(n5, SECP256K1_N_C_1); - muladd(n4, SECP256K1_N_C_2); - muladd(n3, SECP256K1_N_C_3); - sumadd(n2); - extract(m6); - sumadd(l[7]); - muladd(n7, SECP256K1_N_C_0); - muladd(n6, SECP256K1_N_C_1); - muladd(n5, SECP256K1_N_C_2); - muladd(n4, SECP256K1_N_C_3); - sumadd(n3); - extract(m7); - muladd(n7, SECP256K1_N_C_1); - muladd(n6, SECP256K1_N_C_2); - muladd(n5, SECP256K1_N_C_3); - sumadd(n4); - extract(m8); - muladd(n7, SECP256K1_N_C_2); - muladd(n6, SECP256K1_N_C_3); - sumadd(n5); - extract(m9); - muladd(n7, SECP256K1_N_C_3); - sumadd(n6); - extract(m10); - sumadd_fast(n7); - extract_fast(m11); - VERIFY_CHECK(c0 <= 1); - m12 = c0; - - /* Reduce 385 bits into 258. */ - /* p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. */ - c0 = m0; c1 = 0; c2 = 0; - muladd_fast(m8, SECP256K1_N_C_0); - extract_fast(p0); - sumadd_fast(m1); - muladd(m9, SECP256K1_N_C_0); - muladd(m8, SECP256K1_N_C_1); - extract(p1); - sumadd(m2); - muladd(m10, SECP256K1_N_C_0); - muladd(m9, SECP256K1_N_C_1); - muladd(m8, SECP256K1_N_C_2); - extract(p2); - sumadd(m3); - muladd(m11, SECP256K1_N_C_0); - muladd(m10, SECP256K1_N_C_1); - muladd(m9, SECP256K1_N_C_2); - muladd(m8, SECP256K1_N_C_3); - extract(p3); - sumadd(m4); - muladd(m12, SECP256K1_N_C_0); - muladd(m11, SECP256K1_N_C_1); - muladd(m10, SECP256K1_N_C_2); - muladd(m9, SECP256K1_N_C_3); - sumadd(m8); - extract(p4); - sumadd(m5); - muladd(m12, SECP256K1_N_C_1); - muladd(m11, SECP256K1_N_C_2); - muladd(m10, SECP256K1_N_C_3); - sumadd(m9); - extract(p5); - sumadd(m6); - muladd(m12, SECP256K1_N_C_2); - muladd(m11, SECP256K1_N_C_3); - sumadd(m10); - extract(p6); - sumadd_fast(m7); - muladd_fast(m12, SECP256K1_N_C_3); - sumadd_fast(m11); - extract_fast(p7); - p8 = c0 + m12; - VERIFY_CHECK(p8 <= 2); - - /* Reduce 258 bits into 256. */ - /* r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. */ - c = p0 + (uint64_t)SECP256K1_N_C_0 * p8; - r->d[0] = c & 0xFFFFFFFFUL; c >>= 32; - c += p1 + (uint64_t)SECP256K1_N_C_1 * p8; - r->d[1] = c & 0xFFFFFFFFUL; c >>= 32; - c += p2 + (uint64_t)SECP256K1_N_C_2 * p8; - r->d[2] = c & 0xFFFFFFFFUL; c >>= 32; - c += p3 + (uint64_t)SECP256K1_N_C_3 * p8; - r->d[3] = c & 0xFFFFFFFFUL; c >>= 32; - c += p4 + (uint64_t)p8; - r->d[4] = c & 0xFFFFFFFFUL; c >>= 32; - c += p5; - r->d[5] = c & 0xFFFFFFFFUL; c >>= 32; - c += p6; - r->d[6] = c & 0xFFFFFFFFUL; c >>= 32; - c += p7; - r->d[7] = c & 0xFFFFFFFFUL; c >>= 32; - - /* Final reduction of r. */ - secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); -} - -static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, const secp256k1_scalar *b) { - /* 96 bit accumulator. */ - uint32_t c0 = 0, c1 = 0, c2 = 0; - - /* l[0..15] = a[0..7] * b[0..7]. */ - muladd_fast(a->d[0], b->d[0]); - extract_fast(l[0]); - muladd(a->d[0], b->d[1]); - muladd(a->d[1], b->d[0]); - extract(l[1]); - muladd(a->d[0], b->d[2]); - muladd(a->d[1], b->d[1]); - muladd(a->d[2], b->d[0]); - extract(l[2]); - muladd(a->d[0], b->d[3]); - muladd(a->d[1], b->d[2]); - muladd(a->d[2], b->d[1]); - muladd(a->d[3], b->d[0]); - extract(l[3]); - muladd(a->d[0], b->d[4]); - muladd(a->d[1], b->d[3]); - muladd(a->d[2], b->d[2]); - muladd(a->d[3], b->d[1]); - muladd(a->d[4], b->d[0]); - extract(l[4]); - muladd(a->d[0], b->d[5]); - muladd(a->d[1], b->d[4]); - muladd(a->d[2], b->d[3]); - muladd(a->d[3], b->d[2]); - muladd(a->d[4], b->d[1]); - muladd(a->d[5], b->d[0]); - extract(l[5]); - muladd(a->d[0], b->d[6]); - muladd(a->d[1], b->d[5]); - muladd(a->d[2], b->d[4]); - muladd(a->d[3], b->d[3]); - muladd(a->d[4], b->d[2]); - muladd(a->d[5], b->d[1]); - muladd(a->d[6], b->d[0]); - extract(l[6]); - muladd(a->d[0], b->d[7]); - muladd(a->d[1], b->d[6]); - muladd(a->d[2], b->d[5]); - muladd(a->d[3], b->d[4]); - muladd(a->d[4], b->d[3]); - muladd(a->d[5], b->d[2]); - muladd(a->d[6], b->d[1]); - muladd(a->d[7], b->d[0]); - extract(l[7]); - muladd(a->d[1], b->d[7]); - muladd(a->d[2], b->d[6]); - muladd(a->d[3], b->d[5]); - muladd(a->d[4], b->d[4]); - muladd(a->d[5], b->d[3]); - muladd(a->d[6], b->d[2]); - muladd(a->d[7], b->d[1]); - extract(l[8]); - muladd(a->d[2], b->d[7]); - muladd(a->d[3], b->d[6]); - muladd(a->d[4], b->d[5]); - muladd(a->d[5], b->d[4]); - muladd(a->d[6], b->d[3]); - muladd(a->d[7], b->d[2]); - extract(l[9]); - muladd(a->d[3], b->d[7]); - muladd(a->d[4], b->d[6]); - muladd(a->d[5], b->d[5]); - muladd(a->d[6], b->d[4]); - muladd(a->d[7], b->d[3]); - extract(l[10]); - muladd(a->d[4], b->d[7]); - muladd(a->d[5], b->d[6]); - muladd(a->d[6], b->d[5]); - muladd(a->d[7], b->d[4]); - extract(l[11]); - muladd(a->d[5], b->d[7]); - muladd(a->d[6], b->d[6]); - muladd(a->d[7], b->d[5]); - extract(l[12]); - muladd(a->d[6], b->d[7]); - muladd(a->d[7], b->d[6]); - extract(l[13]); - muladd_fast(a->d[7], b->d[7]); - extract_fast(l[14]); - VERIFY_CHECK(c1 == 0); - l[15] = c0; -} - -static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar *a) { - /* 96 bit accumulator. */ - uint32_t c0 = 0, c1 = 0, c2 = 0; - - /* l[0..15] = a[0..7]^2. */ - muladd_fast(a->d[0], a->d[0]); - extract_fast(l[0]); - muladd2(a->d[0], a->d[1]); - extract(l[1]); - muladd2(a->d[0], a->d[2]); - muladd(a->d[1], a->d[1]); - extract(l[2]); - muladd2(a->d[0], a->d[3]); - muladd2(a->d[1], a->d[2]); - extract(l[3]); - muladd2(a->d[0], a->d[4]); - muladd2(a->d[1], a->d[3]); - muladd(a->d[2], a->d[2]); - extract(l[4]); - muladd2(a->d[0], a->d[5]); - muladd2(a->d[1], a->d[4]); - muladd2(a->d[2], a->d[3]); - extract(l[5]); - muladd2(a->d[0], a->d[6]); - muladd2(a->d[1], a->d[5]); - muladd2(a->d[2], a->d[4]); - muladd(a->d[3], a->d[3]); - extract(l[6]); - muladd2(a->d[0], a->d[7]); - muladd2(a->d[1], a->d[6]); - muladd2(a->d[2], a->d[5]); - muladd2(a->d[3], a->d[4]); - extract(l[7]); - muladd2(a->d[1], a->d[7]); - muladd2(a->d[2], a->d[6]); - muladd2(a->d[3], a->d[5]); - muladd(a->d[4], a->d[4]); - extract(l[8]); - muladd2(a->d[2], a->d[7]); - muladd2(a->d[3], a->d[6]); - muladd2(a->d[4], a->d[5]); - extract(l[9]); - muladd2(a->d[3], a->d[7]); - muladd2(a->d[4], a->d[6]); - muladd(a->d[5], a->d[5]); - extract(l[10]); - muladd2(a->d[4], a->d[7]); - muladd2(a->d[5], a->d[6]); - extract(l[11]); - muladd2(a->d[5], a->d[7]); - muladd(a->d[6], a->d[6]); - extract(l[12]); - muladd2(a->d[6], a->d[7]); - extract(l[13]); - muladd_fast(a->d[7], a->d[7]); - extract_fast(l[14]); - VERIFY_CHECK(c1 == 0); - l[15] = c0; -} - -#undef sumadd -#undef sumadd_fast -#undef muladd -#undef muladd_fast -#undef muladd2 -#undef extract -#undef extract_fast - -static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { - uint32_t l[16]; - secp256k1_scalar_mul_512(l, a, b); - secp256k1_scalar_reduce_512(r, l); -} - -static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { - int ret; - VERIFY_CHECK(n > 0); - VERIFY_CHECK(n < 16); - ret = r->d[0] & ((1 << n) - 1); - r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n)); - r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n)); - r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n)); - r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n)); - r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - n)); - r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n)); - r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n)); - r->d[7] = (r->d[7] >> n); - return ret; -} - -static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { - uint32_t l[16]; - secp256k1_scalar_sqr_512(l, a); - secp256k1_scalar_reduce_512(r, l); -} - -#ifdef USE_ENDOMORPHISM -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { - r1->d[0] = a->d[0]; - r1->d[1] = a->d[1]; - r1->d[2] = a->d[2]; - r1->d[3] = a->d[3]; - r1->d[4] = 0; - r1->d[5] = 0; - r1->d[6] = 0; - r1->d[7] = 0; - r2->d[0] = a->d[4]; - r2->d[1] = a->d[5]; - r2->d[2] = a->d[6]; - r2->d[3] = a->d[7]; - r2->d[4] = 0; - r2->d[5] = 0; - r2->d[6] = 0; - r2->d[7] = 0; -} -#endif - -SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { - return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0; -} - -SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { - uint32_t l[16]; - unsigned int shiftlimbs; - unsigned int shiftlow; - unsigned int shifthigh; - VERIFY_CHECK(shift >= 256); - secp256k1_scalar_mul_512(l, a, b); - shiftlimbs = shift >> 5; - shiftlow = shift & 0x1F; - shifthigh = 32 - shiftlow; - r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 480 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[1] = shift < 480 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[2] = shift < 448 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 416 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[3] = shift < 416 ? (l[3 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[4 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[4] = shift < 384 ? (l[4 + shiftlimbs] >> shiftlow | (shift < 352 && shiftlow ? (l[5 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0; - r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0; - secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); -} - -#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h deleted file mode 100644 index fa790570ff..0000000000 --- a/src/secp256k1/src/scalar_impl.h +++ /dev/null @@ -1,333 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_SCALAR_IMPL_H -#define SECP256K1_SCALAR_IMPL_H - -#include "group.h" -#include "scalar.h" - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#if defined(EXHAUSTIVE_TEST_ORDER) -#include "scalar_low_impl.h" -#elif defined(USE_SCALAR_4X64) -#include "scalar_4x64_impl.h" -#elif defined(USE_SCALAR_8X32) -#include "scalar_8x32_impl.h" -#else -#error "Please select scalar implementation" -#endif - -#ifndef USE_NUM_NONE -static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a) { - unsigned char c[32]; - secp256k1_scalar_get_b32(c, a); - secp256k1_num_set_bin(r, c, 32); -} - -/** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */ -static void secp256k1_scalar_order_get_num(secp256k1_num *r) { -#if defined(EXHAUSTIVE_TEST_ORDER) - static const unsigned char order[32] = { - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,EXHAUSTIVE_TEST_ORDER - }; -#else - static const unsigned char order[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,0x41 - }; -#endif - secp256k1_num_set_bin(r, order, 32); -} -#endif - -static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { -#if defined(EXHAUSTIVE_TEST_ORDER) - int i; - *r = 0; - for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) - if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) - *r = i; - /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus - * have a composite group order; fix it in exhaustive_tests.c). */ - VERIFY_CHECK(*r != 0); -} -#else - secp256k1_scalar *t; - int i; - /* First compute xN as x ^ (2^N - 1) for some values of N, - * and uM as x ^ M for some values of M. */ - secp256k1_scalar x2, x3, x6, x8, x14, x28, x56, x112, x126; - secp256k1_scalar u2, u5, u9, u11, u13; - - secp256k1_scalar_sqr(&u2, x); - secp256k1_scalar_mul(&x2, &u2, x); - secp256k1_scalar_mul(&u5, &u2, &x2); - secp256k1_scalar_mul(&x3, &u5, &u2); - secp256k1_scalar_mul(&u9, &x3, &u2); - secp256k1_scalar_mul(&u11, &u9, &u2); - secp256k1_scalar_mul(&u13, &u11, &u2); - - secp256k1_scalar_sqr(&x6, &u13); - secp256k1_scalar_sqr(&x6, &x6); - secp256k1_scalar_mul(&x6, &x6, &u11); - - secp256k1_scalar_sqr(&x8, &x6); - secp256k1_scalar_sqr(&x8, &x8); - secp256k1_scalar_mul(&x8, &x8, &x2); - - secp256k1_scalar_sqr(&x14, &x8); - for (i = 0; i < 5; i++) { - secp256k1_scalar_sqr(&x14, &x14); - } - secp256k1_scalar_mul(&x14, &x14, &x6); - - secp256k1_scalar_sqr(&x28, &x14); - for (i = 0; i < 13; i++) { - secp256k1_scalar_sqr(&x28, &x28); - } - secp256k1_scalar_mul(&x28, &x28, &x14); - - secp256k1_scalar_sqr(&x56, &x28); - for (i = 0; i < 27; i++) { - secp256k1_scalar_sqr(&x56, &x56); - } - secp256k1_scalar_mul(&x56, &x56, &x28); - - secp256k1_scalar_sqr(&x112, &x56); - for (i = 0; i < 55; i++) { - secp256k1_scalar_sqr(&x112, &x112); - } - secp256k1_scalar_mul(&x112, &x112, &x56); - - secp256k1_scalar_sqr(&x126, &x112); - for (i = 0; i < 13; i++) { - secp256k1_scalar_sqr(&x126, &x126); - } - secp256k1_scalar_mul(&x126, &x126, &x14); - - /* Then accumulate the final result (t starts at x126). */ - t = &x126; - for (i = 0; i < 3; i++) { - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u5); /* 101 */ - for (i = 0; i < 4; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 4; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u5); /* 101 */ - for (i = 0; i < 5; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u11); /* 1011 */ - for (i = 0; i < 4; i++) { - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u11); /* 1011 */ - for (i = 0; i < 4; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 5; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 6; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u13); /* 1101 */ - for (i = 0; i < 4; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u5); /* 101 */ - for (i = 0; i < 3; i++) { - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 5; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u9); /* 1001 */ - for (i = 0; i < 6; i++) { /* 000 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u5); /* 101 */ - for (i = 0; i < 10; i++) { /* 0000000 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 4; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 9; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x8); /* 11111111 */ - for (i = 0; i < 5; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u9); /* 1001 */ - for (i = 0; i < 6; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u11); /* 1011 */ - for (i = 0; i < 4; i++) { - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u13); /* 1101 */ - for (i = 0; i < 5; i++) { - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 6; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u13); /* 1101 */ - for (i = 0; i < 10; i++) { /* 000000 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u13); /* 1101 */ - for (i = 0; i < 4; i++) { - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &u9); /* 1001 */ - for (i = 0; i < 6; i++) { /* 00000 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 8; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(r, t, &x6); /* 111111 */ -} - -SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { - return !(a->d[0] & 1); -} -#endif - -static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { -#if defined(USE_SCALAR_INV_BUILTIN) - secp256k1_scalar_inverse(r, x); -#elif defined(USE_SCALAR_INV_NUM) - unsigned char b[32]; - secp256k1_num n, m; - secp256k1_scalar t = *x; - secp256k1_scalar_get_b32(b, &t); - secp256k1_num_set_bin(&n, b, 32); - secp256k1_scalar_order_get_num(&m); - secp256k1_num_mod_inverse(&n, &n, &m); - secp256k1_num_get_bin(b, 32, &n); - secp256k1_scalar_set_b32(r, b, NULL); - /* Verify that the inverse was computed correctly, without GMP code. */ - secp256k1_scalar_mul(&t, &t, r); - CHECK(secp256k1_scalar_is_one(&t)); -#else -#error "Please select scalar inverse implementation" -#endif -} - -#ifdef USE_ENDOMORPHISM -#if defined(EXHAUSTIVE_TEST_ORDER) -/** - * Find k1 and k2 given k, such that k1 + k2 * lambda == k mod n; unlike in the - * full case we don't bother making k1 and k2 be small, we just want them to be - * nontrivial to get full test coverage for the exhaustive tests. We therefore - * (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda. - */ -static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { - *r2 = (*a + 5) % EXHAUSTIVE_TEST_ORDER; - *r1 = (*a + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; -} -#else -/** - * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where - * lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, - * 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72} - * - * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm - * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 - * and k2 have a small size. - * It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are: - * - * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} - * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3} - * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8} - * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} - * - * The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives - * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and - * compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2. - * - * g1, g2 are precomputed constants used to replace division with a rounded multiplication - * when decomposing the scalar for an endomorphism-based point multiplication. - * - * The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve - * Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5. - * - * The derivation is described in the paper "Efficient Software Implementation of Public-Key - * Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez), - * Section 4.3 (here we use a somewhat higher-precision estimate): - * d = a1*b2 - b1*a2 - * g1 = round((2^272)*b2/d) - * g2 = round((2^272)*b1/d) - * - * (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found - * as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda'). - * - * The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order). - */ - -static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { - secp256k1_scalar c1, c2; - static const secp256k1_scalar minus_lambda = SECP256K1_SCALAR_CONST( - 0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL, - 0xA880B9FCUL, 0x8EC739C2UL, 0xE0CFC810UL, 0xB51283CFUL - ); - static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST( - 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, - 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL - ); - static const secp256k1_scalar minus_b2 = SECP256K1_SCALAR_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, - 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL - ); - static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST( - 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL, - 0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL - ); - static const secp256k1_scalar g2 = SECP256K1_SCALAR_CONST( - 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL, - 0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL - ); - VERIFY_CHECK(r1 != a); - VERIFY_CHECK(r2 != a); - /* these _var calls are constant time since the shift amount is constant */ - secp256k1_scalar_mul_shift_var(&c1, a, &g1, 272); - secp256k1_scalar_mul_shift_var(&c2, a, &g2, 272); - secp256k1_scalar_mul(&c1, &c1, &minus_b1); - secp256k1_scalar_mul(&c2, &c2, &minus_b2); - secp256k1_scalar_add(r2, &c1, &c2); - secp256k1_scalar_mul(r1, r2, &minus_lambda); - secp256k1_scalar_add(r1, r1, a); -} -#endif -#endif - -#endif /* SECP256K1_SCALAR_IMPL_H */ diff --git a/src/secp256k1/src/scalar_low.h b/src/secp256k1/src/scalar_low.h deleted file mode 100644 index 5836febc5b..0000000000 --- a/src/secp256k1/src/scalar_low.h +++ /dev/null @@ -1,15 +0,0 @@ -/********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_H -#define SECP256K1_SCALAR_REPR_H - -#include - -/** A scalar modulo the group order of the secp256k1 curve. */ -typedef uint32_t secp256k1_scalar; - -#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/src/secp256k1/src/scalar_low_impl.h b/src/secp256k1/src/scalar_low_impl.h deleted file mode 100644 index c80e70c5a2..0000000000 --- a/src/secp256k1/src/scalar_low_impl.h +++ /dev/null @@ -1,114 +0,0 @@ -/********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_SCALAR_REPR_IMPL_H -#define SECP256K1_SCALAR_REPR_IMPL_H - -#include "scalar.h" - -#include - -SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { - return !(*a & 1); -} - -SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; } -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; } - -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - if (offset < 32) - return ((*a >> offset) & ((((uint32_t)1) << count) - 1)); - else - return 0; -} - -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { - return secp256k1_scalar_get_bits(a, offset, count); -} - -SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; } - -static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { - *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER; - return *r < *b; -} - -static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { - if (flag && bit < 32) - *r += (1 << bit); -#ifdef VERIFY - VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); -#endif -} - -static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { - const int base = 0x100 % EXHAUSTIVE_TEST_ORDER; - int i; - *r = 0; - for (i = 0; i < 32; i++) { - *r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER; - } - /* just deny overflow, it basically always happens */ - if (overflow) *overflow = 0; -} - -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { - memset(bin, 0, 32); - bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a; -} - -SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { - return *a == 0; -} - -static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { - if (*a == 0) { - *r = 0; - } else { - *r = EXHAUSTIVE_TEST_ORDER - *a; - } -} - -SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { - return *a == 1; -} - -static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { - return *a > EXHAUSTIVE_TEST_ORDER / 2; -} - -static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { - if (flag) secp256k1_scalar_negate(r, r); - return flag ? -1 : 1; -} - -static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { - *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; -} - -static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { - int ret; - VERIFY_CHECK(n > 0); - VERIFY_CHECK(n < 16); - ret = *r & ((1 << n) - 1); - *r >>= n; - return ret; -} - -static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { - *r = (*a * *a) % EXHAUSTIVE_TEST_ORDER; -} - -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { - *r1 = *a; - *r2 = 0; -} - -SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { - return *a == *b; -} - -#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c deleted file mode 100644 index 0421b1f800..0000000000 --- a/src/secp256k1/src/secp256k1.c +++ /dev/null @@ -1,589 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Copyright (c) 2019 Chaintope Inc. * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#include "include/secp256k1.h" - -#include "util.h" -#include "num_impl.h" -#include "field_impl.h" -#include "scalar_impl.h" -#include "group_impl.h" -#include "ecmult_impl.h" -#include "ecmult_const_impl.h" -#include "ecmult_gen_impl.h" -#include "ecdsa_impl.h" -#include "eckey_impl.h" -#include "hash_impl.h" - -#define ARG_CHECK(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - secp256k1_callback_call(&ctx->illegal_callback, #cond); \ - return 0; \ - } \ -} while(0) - -static void default_illegal_callback_fn(const char* str, void* data) { - (void)data; - fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); - abort(); -} - -static const secp256k1_callback default_illegal_callback = { - default_illegal_callback_fn, - NULL -}; - -static void default_error_callback_fn(const char* str, void* data) { - (void)data; - fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); - abort(); -} - -static const secp256k1_callback default_error_callback = { - default_error_callback_fn, - NULL -}; - - -struct secp256k1_context_struct { - secp256k1_ecmult_context ecmult_ctx; - secp256k1_ecmult_gen_context ecmult_gen_ctx; - secp256k1_callback illegal_callback; - secp256k1_callback error_callback; -}; - -secp256k1_context* secp256k1_context_create(unsigned int flags) { - secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context)); - ret->illegal_callback = default_illegal_callback; - ret->error_callback = default_error_callback; - - if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { - secp256k1_callback_call(&ret->illegal_callback, - "Invalid flags"); - free(ret); - return NULL; - } - - secp256k1_ecmult_context_init(&ret->ecmult_ctx); - secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx); - - if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) { - secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback); - } - if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) { - secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback); - } - - return ret; -} - -secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { - secp256k1_context* ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_context)); - ret->illegal_callback = ctx->illegal_callback; - ret->error_callback = ctx->error_callback; - secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback); - secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback); - return ret; -} - -void secp256k1_context_destroy(secp256k1_context* ctx) { - if (ctx != NULL) { - secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); - secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); - - free(ctx); - } -} - -void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { - if (fun == NULL) { - fun = default_illegal_callback_fn; - } - ctx->illegal_callback.fn = fun; - ctx->illegal_callback.data = data; -} - -void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { - if (fun == NULL) { - fun = default_error_callback_fn; - } - ctx->error_callback.fn = fun; - ctx->error_callback.data = data; -} - -static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { - if (sizeof(secp256k1_ge_storage) == 64) { - /* When the secp256k1_ge_storage type is exactly 64 byte, use its - * representation inside secp256k1_pubkey, as conversion is very fast. - * Note that secp256k1_pubkey_save must use the same representation. */ - secp256k1_ge_storage s; - memcpy(&s, &pubkey->data[0], 64); - secp256k1_ge_from_storage(ge, &s); - } else { - /* Otherwise, fall back to 32-byte big endian for X and Y. */ - secp256k1_fe x, y; - secp256k1_fe_set_b32(&x, pubkey->data); - secp256k1_fe_set_b32(&y, pubkey->data + 32); - secp256k1_ge_set_xy(ge, &x, &y); - } - ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); - return 1; -} - -static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { - if (sizeof(secp256k1_ge_storage) == 64) { - secp256k1_ge_storage s; - secp256k1_ge_to_storage(&s, ge); - memcpy(&pubkey->data[0], &s, 64); - } else { - VERIFY_CHECK(!secp256k1_ge_is_infinity(ge)); - secp256k1_fe_normalize_var(&ge->x); - secp256k1_fe_normalize_var(&ge->y); - secp256k1_fe_get_b32(pubkey->data, &ge->x); - secp256k1_fe_get_b32(pubkey->data + 32, &ge->y); - } -} - -int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { - secp256k1_ge Q; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(input != NULL); - if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) { - return 0; - } - secp256k1_pubkey_save(pubkey, &Q); - secp256k1_ge_clear(&Q); - return 1; -} - -int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags) { - secp256k1_ge Q; - size_t len; - int ret = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(outputlen != NULL); - ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65)); - len = *outputlen; - *outputlen = 0; - ARG_CHECK(output != NULL); - memset(output, 0, len); - ARG_CHECK(pubkey != NULL); - ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); - if (secp256k1_pubkey_load(ctx, &Q, pubkey)) { - ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); - if (ret) { - *outputlen = len; - } - } - return ret; -} - -static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) { - (void)ctx; - if (sizeof(secp256k1_scalar) == 32) { - /* When the secp256k1_scalar type is exactly 32 byte, use its - * representation inside secp256k1_ecdsa_signature, as conversion is very fast. - * Note that secp256k1_ecdsa_signature_save must use the same representation. */ - memcpy(r, &sig->data[0], 32); - memcpy(s, &sig->data[32], 32); - } else { - secp256k1_scalar_set_b32(r, &sig->data[0], NULL); - secp256k1_scalar_set_b32(s, &sig->data[32], NULL); - } -} - -static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s) { - if (sizeof(secp256k1_scalar) == 32) { - memcpy(&sig->data[0], r, 32); - memcpy(&sig->data[32], s, 32); - } else { - secp256k1_scalar_get_b32(&sig->data[0], r); - secp256k1_scalar_get_b32(&sig->data[32], s); - } -} - -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; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(input != NULL); - - if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) { - secp256k1_ecdsa_signature_save(sig, &r, &s); - return 1; - } else { - memset(sig, 0, sizeof(*sig)); - return 0; - } -} - -int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input64) { - secp256k1_scalar r, s; - int ret = 1; - int overflow = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(input64 != NULL); - - secp256k1_scalar_set_b32(&r, &input64[0], &overflow); - ret &= !overflow; - secp256k1_scalar_set_b32(&s, &input64[32], &overflow); - ret &= !overflow; - if (ret) { - secp256k1_ecdsa_signature_save(sig, &r, &s); - } else { - memset(sig, 0, sizeof(*sig)); - } - return ret; -} - -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; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output != NULL); - ARG_CHECK(outputlen != NULL); - ARG_CHECK(sig != NULL); - - secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); - return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s); -} - -int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) { - secp256k1_scalar r, s; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(output64 != NULL); - ARG_CHECK(sig != NULL); - - secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); - secp256k1_scalar_get_b32(&output64[0], &r); - secp256k1_scalar_get_b32(&output64[32], &s); - return 1; -} - -int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) { - secp256k1_scalar r, s; - int ret = 0; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(sigin != NULL); - - secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin); - ret = secp256k1_scalar_is_high(&s); - if (sigout != NULL) { - if (ret) { - secp256k1_scalar_negate(&s, &s); - } - secp256k1_ecdsa_signature_save(sigout, &r, &s); - } - - return ret; -} - -int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { - secp256k1_ge q; - secp256k1_scalar r, s; - secp256k1_scalar m; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(sig != NULL); - ARG_CHECK(pubkey != NULL); - - secp256k1_scalar_set_b32(&m, msg32, NULL); - secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); - return (!secp256k1_scalar_is_high(&s) && - secp256k1_pubkey_load(ctx, &q, pubkey) && - secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m)); -} - -static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { - unsigned char keydata[112]; - int keylen = 64; - secp256k1_rfc6979_hmac_sha256_t rng; - unsigned int i; - /* We feed a byte array to the PRNG as input, consisting of: - * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d. - * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. - * - optionally 16 extra bytes with the algorithm name. - * Because the arguments have distinct fixed lengths it is not possible for - * different argument mixtures to emulate each other and result in the same - * nonces. - */ - memcpy(keydata, key32, 32); - memcpy(keydata + 32, msg32, 32); - if (data != NULL) { - memcpy(keydata + 64, data, 32); - keylen = 96; - } - if (algo16 != NULL) { - memcpy(keydata + keylen, algo16, 16); - keylen += 16; - } - secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, keylen); - memset(keydata, 0, sizeof(keydata)); - for (i = 0; i <= counter; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - } - secp256k1_rfc6979_hmac_sha256_finalize(&rng); - return 1; -} - -const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; -const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979; - -int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { - secp256k1_scalar r, s; - secp256k1_scalar sec, non, msg; - int ret = 0; - int overflow = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(signature != NULL); - ARG_CHECK(seckey != NULL); - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; - } - - secp256k1_scalar_set_b32(&sec, seckey, &overflow); - /* Fail if the secret key is invalid. */ - if (!overflow && !secp256k1_scalar_is_zero(&sec)) { - unsigned char nonce32[32]; - unsigned int count = 0; - secp256k1_scalar_set_b32(&msg, msg32, NULL); - while (1) { - ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); - if (!ret) { - break; - } - secp256k1_scalar_set_b32(&non, nonce32, &overflow); - if (!overflow && !secp256k1_scalar_is_zero(&non)) { - if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) { - break; - } - } - count++; - } - memset(nonce32, 0, 32); - secp256k1_scalar_clear(&msg); - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); - } - if (ret) { - secp256k1_ecdsa_signature_save(signature, &r, &s); - } else { - memset(signature, 0, sizeof(*signature)); - } - return ret; -} - -int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) { - secp256k1_scalar sec; - int ret; - int overflow; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - - secp256k1_scalar_set_b32(&sec, seckey, &overflow); - ret = !overflow && !secp256k1_scalar_is_zero(&sec); - secp256k1_scalar_clear(&sec); - return ret; -} - -int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) { - secp256k1_gej pj; - secp256k1_ge p; - secp256k1_scalar sec; - int overflow; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - memset(pubkey, 0, sizeof(*pubkey)); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(seckey != NULL); - - secp256k1_scalar_set_b32(&sec, seckey, &overflow); - ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec)); - if (ret) { - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); - secp256k1_ge_set_gej(&p, &pj); - secp256k1_pubkey_save(pubkey, &p); - } - secp256k1_scalar_clear(&sec); - return ret; -} - -int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) { - secp256k1_scalar sec; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - - secp256k1_scalar_set_b32(&sec, seckey, NULL); - secp256k1_scalar_negate(&sec, &sec); - secp256k1_scalar_get_b32(seckey, &sec); - - return 1; -} - -int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) { - int ret = 0; - secp256k1_ge p; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(pubkey != NULL); - - ret = secp256k1_pubkey_load(ctx, &p, pubkey); - memset(pubkey, 0, sizeof(*pubkey)); - if (ret) { - secp256k1_ge_neg(&p, &p); - secp256k1_pubkey_save(pubkey, &p); - } - return ret; -} - -int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) { - secp256k1_scalar term; - secp256k1_scalar sec; - int ret = 0; - int overflow = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - ARG_CHECK(tweak != NULL); - - secp256k1_scalar_set_b32(&term, tweak, &overflow); - secp256k1_scalar_set_b32(&sec, seckey, NULL); - - ret = !overflow && secp256k1_eckey_privkey_tweak_add(&sec, &term); - memset(seckey, 0, 32); - if (ret) { - secp256k1_scalar_get_b32(seckey, &sec); - } - - secp256k1_scalar_clear(&sec); - secp256k1_scalar_clear(&term); - return ret; -} - -int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { - secp256k1_ge p; - secp256k1_scalar term; - int ret = 0; - int overflow = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(tweak != NULL); - - secp256k1_scalar_set_b32(&term, tweak, &overflow); - ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); - memset(pubkey, 0, sizeof(*pubkey)); - if (ret) { - if (secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) { - secp256k1_pubkey_save(pubkey, &p); - } else { - ret = 0; - } - } - - return ret; -} - -int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) { - secp256k1_scalar factor; - secp256k1_scalar sec; - int ret = 0; - int overflow = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - ARG_CHECK(tweak != NULL); - - secp256k1_scalar_set_b32(&factor, tweak, &overflow); - secp256k1_scalar_set_b32(&sec, seckey, NULL); - ret = !overflow && secp256k1_eckey_privkey_tweak_mul(&sec, &factor); - memset(seckey, 0, 32); - if (ret) { - secp256k1_scalar_get_b32(seckey, &sec); - } - - secp256k1_scalar_clear(&sec); - secp256k1_scalar_clear(&factor); - return ret; -} - -int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { - secp256k1_ge p; - secp256k1_scalar factor; - int ret = 0; - int overflow = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - ARG_CHECK(pubkey != NULL); - ARG_CHECK(tweak != NULL); - - secp256k1_scalar_set_b32(&factor, tweak, &overflow); - ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); - memset(pubkey, 0, sizeof(*pubkey)); - if (ret) { - if (secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor)) { - secp256k1_pubkey_save(pubkey, &p); - } else { - ret = 0; - } - } - - return ret; -} - -int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) { - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); - return 1; -} - -int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, const secp256k1_pubkey * const *pubnonces, size_t n) { - size_t i; - secp256k1_gej Qj; - secp256k1_ge Q; - - ARG_CHECK(pubnonce != NULL); - memset(pubnonce, 0, sizeof(*pubnonce)); - ARG_CHECK(n >= 1); - ARG_CHECK(pubnonces != NULL); - - secp256k1_gej_set_infinity(&Qj); - - for (i = 0; i < n; i++) { - secp256k1_pubkey_load(ctx, &Q, pubnonces[i]); - secp256k1_gej_add_ge(&Qj, &Qj, &Q); - } - if (secp256k1_gej_is_infinity(&Qj)) { - return 0; - } - secp256k1_ge_set_gej(&Q, &Qj); - secp256k1_pubkey_save(pubnonce, &Q); - return 1; -} - -#ifdef ENABLE_MODULE_ECDH -# include "modules/ecdh/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_RECOVERY -# include "modules/recovery/main_impl.h" -#endif - -#ifdef ENABLE_MODULE_SCHNORR -# include "modules/schnorr/main_impl.h" -#endif diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h deleted file mode 100644 index f1f9be077e..0000000000 --- a/src/secp256k1/src/testrand.h +++ /dev/null @@ -1,38 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_TESTRAND_H -#define SECP256K1_TESTRAND_H - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -/* A non-cryptographic RNG used only for test infrastructure. */ - -/** Seed the pseudorandom number generator for testing. */ -SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16); - -/** Generate a pseudorandom number in the range [0..2**32-1]. */ -static uint32_t secp256k1_rand32(void); - -/** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or - * more. */ -static uint32_t secp256k1_rand_bits(int bits); - -/** Generate a pseudorandom number in the range [0..range-1]. */ -static uint32_t secp256k1_rand_int(uint32_t range); - -/** Generate a pseudorandom 32-byte array. */ -static void secp256k1_rand256(unsigned char *b32); - -/** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ -static void secp256k1_rand256_test(unsigned char *b32); - -/** Generate pseudorandom bytes with long sequences of zero and one bits. */ -static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len); - -#endif /* SECP256K1_TESTRAND_H */ diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h deleted file mode 100644 index 1255574209..0000000000 --- a/src/secp256k1/src/testrand_impl.h +++ /dev/null @@ -1,110 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_TESTRAND_IMPL_H -#define SECP256K1_TESTRAND_IMPL_H - -#include -#include - -#include "testrand.h" -#include "hash.h" - -static secp256k1_rfc6979_hmac_sha256_t secp256k1_test_rng; -static uint32_t secp256k1_test_rng_precomputed[8]; -static int secp256k1_test_rng_precomputed_used = 8; -static uint64_t secp256k1_test_rng_integer; -static int secp256k1_test_rng_integer_bits_left = 0; - -SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16) { - secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16); -} - -SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { - if (secp256k1_test_rng_precomputed_used == 8) { - secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, (unsigned char*)(&secp256k1_test_rng_precomputed[0]), sizeof(secp256k1_test_rng_precomputed)); - secp256k1_test_rng_precomputed_used = 0; - } - return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++]; -} - -static uint32_t secp256k1_rand_bits(int bits) { - uint32_t ret; - if (secp256k1_test_rng_integer_bits_left < bits) { - secp256k1_test_rng_integer |= (((uint64_t)secp256k1_rand32()) << secp256k1_test_rng_integer_bits_left); - secp256k1_test_rng_integer_bits_left += 32; - } - ret = secp256k1_test_rng_integer; - secp256k1_test_rng_integer >>= bits; - secp256k1_test_rng_integer_bits_left -= bits; - ret &= ((~((uint32_t)0)) >> (32 - bits)); - return ret; -} - -static uint32_t secp256k1_rand_int(uint32_t range) { - /* We want a uniform integer between 0 and range-1, inclusive. - * B is the smallest number such that range <= 2**B. - * two mechanisms implemented here: - * - generate B bits numbers until one below range is found, and return it - * - find the largest multiple M of range that is <= 2**(B+A), generate B+A - * bits numbers until one below M is found, and return it modulo range - * The second mechanism consumes A more bits of entropy in every iteration, - * but may need fewer iterations due to M being closer to 2**(B+A) then - * range is to 2**B. The array below (indexed by B) contains a 0 when the - * first mechanism is to be used, and the number A otherwise. - */ - static const int addbits[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0}; - uint32_t trange, mult; - int bits = 0; - if (range <= 1) { - return 0; - } - trange = range - 1; - while (trange > 0) { - trange >>= 1; - bits++; - } - if (addbits[bits]) { - bits = bits + addbits[bits]; - mult = ((~((uint32_t)0)) >> (32 - bits)) / range; - trange = range * mult; - } else { - trange = range; - mult = 1; - } - while(1) { - uint32_t x = secp256k1_rand_bits(bits); - if (x < trange) { - return (mult == 1) ? x : (x % range); - } - } -} - -static void secp256k1_rand256(unsigned char *b32) { - secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32); -} - -static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len) { - size_t bits = 0; - memset(bytes, 0, len); - while (bits < len * 8) { - int now; - uint32_t val; - now = 1 + (secp256k1_rand_bits(6) * secp256k1_rand_bits(5) + 16) / 31; - val = secp256k1_rand_bits(1); - while (now > 0 && bits < len * 8) { - bytes[bits / 8] |= val << (bits % 8); - now--; - bits++; - } - } -} - -static void secp256k1_rand256_test(unsigned char *b32) { - secp256k1_rand_bytes_test(b32, 32); -} - -#endif /* SECP256K1_TESTRAND_IMPL_H */ diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c deleted file mode 100644 index 8bf8e65c56..0000000000 --- a/src/secp256k1/src/tests.c +++ /dev/null @@ -1,4545 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#include -#include -#include - -#include - -#include "secp256k1.c" -#include "include/secp256k1.h" -#include "testrand_impl.h" - -#ifdef ENABLE_OPENSSL_TESTS -#include "openssl/bn.h" -#include "openssl/ec.h" -#include "openssl/ecdsa.h" -#include "openssl/obj_mac.h" -#endif - -#include "contrib/lax_der_parsing.c" -#include "contrib/lax_der_privatekey_parsing.c" - -#if !defined(VG_CHECK) -# if defined(VALGRIND) -# include -# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) -# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) -# else -# define VG_UNDEF(x,y) -# define VG_CHECK(x,y) -# endif -#endif - -static int count = 64; -static secp256k1_context *ctx = NULL; - -static void counting_illegal_callback_fn(const char* str, void* data) { - /* Dummy callback function that just counts. */ - int32_t *p; - (void)str; - p = data; - (*p)++; -} - -static void uncounting_illegal_callback_fn(const char* str, void* data) { - /* Dummy callback function that just counts (backwards). */ - int32_t *p; - (void)str; - p = data; - (*p)--; -} - -void random_field_element_test(secp256k1_fe *fe) { - do { - unsigned char b32[32]; - secp256k1_rand256_test(b32); - if (secp256k1_fe_set_b32(fe, b32)) { - break; - } - } while(1); -} - -void random_field_element_magnitude(secp256k1_fe *fe) { - secp256k1_fe zero; - int n = secp256k1_rand_int(9); - secp256k1_fe_normalize(fe); - if (n == 0) { - return; - } - secp256k1_fe_clear(&zero); - secp256k1_fe_negate(&zero, &zero, 0); - secp256k1_fe_mul_int(&zero, n - 1); - secp256k1_fe_add(fe, &zero); - VERIFY_CHECK(fe->magnitude == n); -} - -void random_group_element_test(secp256k1_ge *ge) { - secp256k1_fe fe; - do { - random_field_element_test(&fe); - if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand_bits(1))) { - secp256k1_fe_normalize(&ge->y); - break; - } - } while(1); -} - -void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { - secp256k1_fe z2, z3; - do { - random_field_element_test(&gej->z); - if (!secp256k1_fe_is_zero(&gej->z)) { - break; - } - } while(1); - secp256k1_fe_sqr(&z2, &gej->z); - secp256k1_fe_mul(&z3, &z2, &gej->z); - secp256k1_fe_mul(&gej->x, &ge->x, &z2); - secp256k1_fe_mul(&gej->y, &ge->y, &z3); - gej->infinity = ge->infinity; -} - -void random_scalar_order_test(secp256k1_scalar *num) { - do { - unsigned char b32[32]; - int overflow = 0; - secp256k1_rand256_test(b32); - secp256k1_scalar_set_b32(num, b32, &overflow); - if (overflow || secp256k1_scalar_is_zero(num)) { - continue; - } - break; - } while(1); -} - -void random_scalar_order(secp256k1_scalar *num) { - do { - unsigned char b32[32]; - int overflow = 0; - secp256k1_rand256(b32); - secp256k1_scalar_set_b32(num, b32, &overflow); - if (overflow || secp256k1_scalar_is_zero(num)) { - continue; - } - break; - } while(1); -} - -void run_context_tests(void) { - secp256k1_pubkey pubkey; - secp256k1_pubkey zero_pubkey; - secp256k1_ecdsa_signature sig; - unsigned char ctmp[32]; - int32_t ecount; - int32_t ecount2; - secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - secp256k1_gej pubj; - secp256k1_ge pub; - secp256k1_scalar msg, key, nonce; - secp256k1_scalar sigr, sigs; - - memset(&zero_pubkey, 0, sizeof(zero_pubkey)); - - ecount = 0; - ecount2 = 10; - secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2); - secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL); - CHECK(vrfy->error_callback.fn != sign->error_callback.fn); - - /*** clone and destroy all of them to make sure cloning was complete ***/ - { - secp256k1_context *ctx_tmp; - - ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp); - } - - /* Verify that the error callback makes it across the clone. */ - CHECK(vrfy->error_callback.fn != sign->error_callback.fn); - /* And that it resets back to default. */ - secp256k1_context_set_error_callback(sign, NULL, NULL); - CHECK(vrfy->error_callback.fn == sign->error_callback.fn); - - /*** attempt to use them ***/ - random_scalar_order_test(&msg); - random_scalar_order_test(&key); - secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key); - secp256k1_ge_set_gej(&pub, &pubj); - - /* Verify context-type checking illegal-argument errors. */ - memset(ctmp, 1, 32); - CHECK(secp256k1_ec_pubkey_create(vrfy, &pubkey, ctmp) == 0); - CHECK(ecount == 1); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(sign, &pubkey, ctmp) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ecdsa_sign(vrfy, &sig, ctmp, ctmp, NULL, NULL) == 0); - CHECK(ecount == 2); - VG_UNDEF(&sig, sizeof(sig)); - CHECK(secp256k1_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1); - VG_CHECK(&sig, sizeof(sig)); - CHECK(ecount2 == 10); - CHECK(secp256k1_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 0); - CHECK(ecount2 == 11); - CHECK(secp256k1_ecdsa_verify(vrfy, &sig, ctmp, &pubkey) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 0); - CHECK(ecount2 == 12); - CHECK(secp256k1_ec_pubkey_tweak_add(vrfy, &pubkey, ctmp) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0); - CHECK(ecount2 == 13); - CHECK(secp256k1_ec_pubkey_negate(vrfy, &pubkey) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_ec_pubkey_negate(sign, &pubkey) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_ec_pubkey_negate(sign, NULL) == 0); - CHECK(ecount2 == 14); - CHECK(secp256k1_ec_pubkey_negate(vrfy, &zero_pubkey) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1); - CHECK(ecount == 3); - CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_context_randomize(sign, NULL) == 1); - CHECK(ecount2 == 14); - secp256k1_context_set_illegal_callback(vrfy, NULL, NULL); - secp256k1_context_set_illegal_callback(sign, NULL, NULL); - - /* This shouldn't leak memory, due to already-set tests. */ - secp256k1_ecmult_gen_context_build(&sign->ecmult_gen_ctx, NULL); - secp256k1_ecmult_context_build(&vrfy->ecmult_ctx, NULL); - - /* obtain a working nonce */ - do { - random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); - - /* try signing */ - CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); - CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); - - /* try verifying */ - CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sigr, &sigs, &pub, &msg)); - CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg)); - - /* cleanup */ - secp256k1_context_destroy(none); - secp256k1_context_destroy(sign); - secp256k1_context_destroy(vrfy); - secp256k1_context_destroy(both); - /* Defined as no-op. */ - secp256k1_context_destroy(NULL); -} - -/***** HASH TESTS *****/ - -void run_sha256_tests(void) { - static const char *inputs[8] = { - "", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe", - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - "For this sample, this 63-byte string will be used as input data", - "This is exactly 64 bytes long, not counting the terminating byte" - }; - static const unsigned char outputs[8][32] = { - {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, - {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}, - {0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50}, - {0xf3, 0x0c, 0xeb, 0x2b, 0xb2, 0x82, 0x9e, 0x79, 0xe4, 0xca, 0x97, 0x53, 0xd3, 0x5a, 0x8e, 0xcc, 0x00, 0x26, 0x2d, 0x16, 0x4c, 0xc0, 0x77, 0x08, 0x02, 0x95, 0x38, 0x1c, 0xbd, 0x64, 0x3f, 0x0d}, - {0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30}, - {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}, - {0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42}, - {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8} - }; - int i; - for (i = 0; i < 8; i++) { - unsigned char out[32]; - secp256k1_sha256_t hasher; - secp256k1_sha256_initialize(&hasher); - secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); - secp256k1_sha256_finalize(&hasher, out); - CHECK(memcmp(out, outputs[i], 32) == 0); - if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand_int(strlen(inputs[i])); - secp256k1_sha256_initialize(&hasher); - secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); - secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); - secp256k1_sha256_finalize(&hasher, out); - CHECK(memcmp(out, outputs[i], 32) == 0); - } - } -} - -void run_hmac_sha256_tests(void) { - static const char *keys[6] = { - "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", - "\x4a\x65\x66\x65", - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", - "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - }; - static const char *inputs[6] = { - "\x48\x69\x20\x54\x68\x65\x72\x65", - "\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f", - "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", - "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", - "\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61\x72\x67\x65\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f\x63\x6b\x2d\x53\x69\x7a\x65\x20\x4b\x65\x79\x20\x2d\x20\x48\x61\x73\x68\x20\x4b\x65\x79\x20\x46\x69\x72\x73\x74", - "\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e" - }; - static const unsigned char outputs[6][32] = { - {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7}, - {0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43}, - {0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe}, - {0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b}, - {0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54}, - {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2} - }; - int i; - for (i = 0; i < 6; i++) { - secp256k1_hmac_sha256_t hasher; - unsigned char out[32]; - secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); - secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); - secp256k1_hmac_sha256_finalize(&hasher, out); - CHECK(memcmp(out, outputs[i], 32) == 0); - if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand_int(strlen(inputs[i])); - secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); - secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); - secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); - secp256k1_hmac_sha256_finalize(&hasher, out); - CHECK(memcmp(out, outputs[i], 32) == 0); - } - } -} - -void run_rfc6979_hmac_sha256_tests(void) { - static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0}; - static const unsigned char out1[3][32] = { - {0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb}, - {0x2b, 0xf0, 0xff, 0xf1, 0xd3, 0xc3, 0x78, 0xa2, 0x2d, 0xc5, 0xde, 0x1d, 0x85, 0x65, 0x22, 0x32, 0x5c, 0x65, 0xb5, 0x04, 0x49, 0x1a, 0x0c, 0xbd, 0x01, 0xcb, 0x8f, 0x3a, 0xa6, 0x7f, 0xfd, 0x4a}, - {0xf5, 0x28, 0xb4, 0x10, 0xcb, 0x54, 0x1f, 0x77, 0x00, 0x0d, 0x7a, 0xfb, 0x6c, 0x5b, 0x53, 0xc5, 0xc4, 0x71, 0xea, 0xb4, 0x3e, 0x46, 0x6d, 0x9a, 0xc5, 0x19, 0x0c, 0x39, 0xc8, 0x2f, 0xd8, 0x2e} - }; - - static const unsigned char key2[64] = {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, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; - static const unsigned char out2[3][32] = { - {0x9c, 0x23, 0x6c, 0x16, 0x5b, 0x82, 0xae, 0x0c, 0xd5, 0x90, 0x65, 0x9e, 0x10, 0x0b, 0x6b, 0xab, 0x30, 0x36, 0xe7, 0xba, 0x8b, 0x06, 0x74, 0x9b, 0xaf, 0x69, 0x81, 0xe1, 0x6f, 0x1a, 0x2b, 0x95}, - {0xdf, 0x47, 0x10, 0x61, 0x62, 0x5b, 0xc0, 0xea, 0x14, 0xb6, 0x82, 0xfe, 0xee, 0x2c, 0x9c, 0x02, 0xf2, 0x35, 0xda, 0x04, 0x20, 0x4c, 0x1d, 0x62, 0xa1, 0x53, 0x6c, 0x6e, 0x17, 0xae, 0xd7, 0xa9}, - {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} - }; - - secp256k1_rfc6979_hmac_sha256_t rng; - unsigned char out[32]; - int i; - - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64); - for (i = 0; i < 3; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(memcmp(out, out1[i], 32) == 0); - } - secp256k1_rfc6979_hmac_sha256_finalize(&rng); - - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65); - for (i = 0; i < 3; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(memcmp(out, out1[i], 32) != 0); - } - secp256k1_rfc6979_hmac_sha256_finalize(&rng); - - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64); - for (i = 0; i < 3; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(memcmp(out, out2[i], 32) == 0); - } - secp256k1_rfc6979_hmac_sha256_finalize(&rng); -} - -/***** RANDOM TESTS *****/ - -void test_rand_bits(int rand32, int bits) { - /* (1-1/2^B)^rounds[B] < 1/10^9, so rounds is the number of iterations to - * get a false negative chance below once in a billion */ - static const unsigned int rounds[7] = {1, 30, 73, 156, 322, 653, 1316}; - /* We try multiplying the results with various odd numbers, which shouldn't - * influence the uniform distribution modulo a power of 2. */ - static const uint32_t mults[6] = {1, 3, 21, 289, 0x9999, 0x80402011}; - /* We only select up to 6 bits from the output to analyse */ - unsigned int usebits = bits > 6 ? 6 : bits; - unsigned int maxshift = bits - usebits; - /* For each of the maxshift+1 usebits-bit sequences inside a bits-bit - number, track all observed outcomes, one per bit in a uint64_t. */ - uint64_t x[6][27] = {{0}}; - unsigned int i, shift, m; - /* Multiply the output of all rand calls with the odd number m, which - should not change the uniformity of its distribution. */ - for (i = 0; i < rounds[usebits]; i++) { - uint32_t r = (rand32 ? secp256k1_rand32() : secp256k1_rand_bits(bits)); - CHECK((((uint64_t)r) >> bits) == 0); - for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { - uint32_t rm = r * mults[m]; - for (shift = 0; shift <= maxshift; shift++) { - x[m][shift] |= (((uint64_t)1) << ((rm >> shift) & ((1 << usebits) - 1))); - } - } - } - for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { - for (shift = 0; shift <= maxshift; shift++) { - /* Test that the lower usebits bits of x[shift] are 1 */ - CHECK(((~x[m][shift]) << (64 - (1 << usebits))) == 0); - } - } -} - -/* Subrange must be a whole divisor of range, and at most 64 */ -void test_rand_int(uint32_t range, uint32_t subrange) { - /* (1-1/subrange)^rounds < 1/10^9 */ - int rounds = (subrange * 2073) / 100; - int i; - uint64_t x = 0; - CHECK((range % subrange) == 0); - for (i = 0; i < rounds; i++) { - uint32_t r = secp256k1_rand_int(range); - CHECK(r < range); - r = r % subrange; - x |= (((uint64_t)1) << r); - } - /* Test that the lower subrange bits of x are 1. */ - CHECK(((~x) << (64 - subrange)) == 0); -} - -void run_rand_bits(void) { - size_t b; - test_rand_bits(1, 32); - for (b = 1; b <= 32; b++) { - test_rand_bits(0, b); - } -} - -void run_rand_int(void) { - static const uint32_t ms[] = {1, 3, 17, 1000, 13771, 999999, 33554432}; - static const uint32_t ss[] = {1, 3, 6, 9, 13, 31, 64}; - unsigned int m, s; - for (m = 0; m < sizeof(ms) / sizeof(ms[0]); m++) { - for (s = 0; s < sizeof(ss) / sizeof(ss[0]); s++) { - test_rand_int(ms[m] * ss[s], ss[s]); - } - } -} - -/***** NUM TESTS *****/ - -#ifndef USE_NUM_NONE -void random_num_negate(secp256k1_num *num) { - if (secp256k1_rand_bits(1)) { - secp256k1_num_negate(num); - } -} - -void random_num_order_test(secp256k1_num *num) { - secp256k1_scalar sc; - random_scalar_order_test(&sc); - secp256k1_scalar_get_num(num, &sc); -} - -void random_num_order(secp256k1_num *num) { - secp256k1_scalar sc; - random_scalar_order(&sc); - secp256k1_scalar_get_num(num, &sc); -} - -void test_num_negate(void) { - secp256k1_num n1; - secp256k1_num n2; - random_num_order_test(&n1); /* n1 = R */ - random_num_negate(&n1); - secp256k1_num_copy(&n2, &n1); /* n2 = R */ - secp256k1_num_sub(&n1, &n2, &n1); /* n1 = n2-n1 = 0 */ - CHECK(secp256k1_num_is_zero(&n1)); - secp256k1_num_copy(&n1, &n2); /* n1 = R */ - secp256k1_num_negate(&n1); /* n1 = -R */ - CHECK(!secp256k1_num_is_zero(&n1)); - secp256k1_num_add(&n1, &n2, &n1); /* n1 = n2+n1 = 0 */ - CHECK(secp256k1_num_is_zero(&n1)); - secp256k1_num_copy(&n1, &n2); /* n1 = R */ - secp256k1_num_negate(&n1); /* n1 = -R */ - CHECK(secp256k1_num_is_neg(&n1) != secp256k1_num_is_neg(&n2)); - secp256k1_num_negate(&n1); /* n1 = R */ - CHECK(secp256k1_num_eq(&n1, &n2)); -} - -void test_num_add_sub(void) { - int i; - secp256k1_scalar s; - secp256k1_num n1; - secp256k1_num n2; - secp256k1_num n1p2, n2p1, n1m2, n2m1; - random_num_order_test(&n1); /* n1 = R1 */ - if (secp256k1_rand_bits(1)) { - random_num_negate(&n1); - } - random_num_order_test(&n2); /* n2 = R2 */ - if (secp256k1_rand_bits(1)) { - random_num_negate(&n2); - } - secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */ - secp256k1_num_add(&n2p1, &n2, &n1); /* n2p1 = R2 + R1 */ - secp256k1_num_sub(&n1m2, &n1, &n2); /* n1m2 = R1 - R2 */ - secp256k1_num_sub(&n2m1, &n2, &n1); /* n2m1 = R2 - R1 */ - CHECK(secp256k1_num_eq(&n1p2, &n2p1)); - CHECK(!secp256k1_num_eq(&n1p2, &n1m2)); - secp256k1_num_negate(&n2m1); /* n2m1 = -R2 + R1 */ - CHECK(secp256k1_num_eq(&n2m1, &n1m2)); - CHECK(!secp256k1_num_eq(&n2m1, &n1)); - secp256k1_num_add(&n2m1, &n2m1, &n2); /* n2m1 = -R2 + R1 + R2 = R1 */ - CHECK(secp256k1_num_eq(&n2m1, &n1)); - 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) { - int i; - for (i = 0; i < 100*count; i++) { - test_num_negate(); - test_num_add_sub(); - test_num_mod(); - test_num_jacobi(); - } -} -#endif - -/***** SCALAR TESTS *****/ - -void scalar_test(void) { - secp256k1_scalar s; - secp256k1_scalar s1; - secp256k1_scalar s2; -#ifndef USE_NUM_NONE - secp256k1_num snum, s1num, s2num; - secp256k1_num order, half_order; -#endif - unsigned char c[32]; - - /* Set 's' to a random scalar, with value 'snum'. */ - random_scalar_order_test(&s); - - /* Set 's1' to a random scalar, with value 's1num'. */ - random_scalar_order_test(&s1); - - /* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */ - random_scalar_order_test(&s2); - secp256k1_scalar_get_b32(c, &s2); - -#ifndef USE_NUM_NONE - secp256k1_scalar_get_num(&snum, &s); - secp256k1_scalar_get_num(&s1num, &s1); - secp256k1_scalar_get_num(&s2num, &s2); - - secp256k1_scalar_order_get_num(&order); - half_order = order; - secp256k1_num_shift(&half_order, 1); -#endif - - { - int i; - /* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */ - secp256k1_scalar n; - secp256k1_scalar_set_int(&n, 0); - for (i = 0; i < 256; i += 4) { - secp256k1_scalar t; - int j; - secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4)); - for (j = 0; j < 4; j++) { - secp256k1_scalar_add(&n, &n, &n); - } - secp256k1_scalar_add(&n, &n, &t); - } - CHECK(secp256k1_scalar_eq(&n, &s)); - } - - { - /* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */ - secp256k1_scalar n; - int i = 0; - secp256k1_scalar_set_int(&n, 0); - while (i < 256) { - secp256k1_scalar t; - int j; - int now = secp256k1_rand_int(15) + 1; - if (now + i > 256) { - now = 256 - i; - } - secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits_var(&s, 256 - now - i, now)); - for (j = 0; j < now; j++) { - secp256k1_scalar_add(&n, &n, &n); - } - secp256k1_scalar_add(&n, &n, &t); - i += now; - } - CHECK(secp256k1_scalar_eq(&n, &s)); - } - -#ifndef USE_NUM_NONE - { - /* Test that adding the scalars together is equal to adding their numbers together modulo the order. */ - secp256k1_num rnum; - secp256k1_num r2num; - secp256k1_scalar r; - secp256k1_num_add(&rnum, &snum, &s2num); - secp256k1_num_mod(&rnum, &order); - secp256k1_scalar_add(&r, &s, &s2); - secp256k1_scalar_get_num(&r2num, &r); - CHECK(secp256k1_num_eq(&rnum, &r2num)); - } - - { - /* Test that multiplying the scalars is equal to multiplying their numbers modulo the order. */ - secp256k1_scalar r; - secp256k1_num r2num; - secp256k1_num rnum; - secp256k1_num_mul(&rnum, &snum, &s2num); - secp256k1_num_mod(&rnum, &order); - secp256k1_scalar_mul(&r, &s, &s2); - secp256k1_scalar_get_num(&r2num, &r); - CHECK(secp256k1_num_eq(&rnum, &r2num)); - /* The result can only be zero if at least one of the factors was zero. */ - CHECK(secp256k1_scalar_is_zero(&r) == (secp256k1_scalar_is_zero(&s) || secp256k1_scalar_is_zero(&s2))); - /* The results can only be equal to one of the factors if that factor was zero, or the other factor was one. */ - CHECK(secp256k1_num_eq(&rnum, &snum) == (secp256k1_scalar_is_zero(&s) || secp256k1_scalar_is_one(&s2))); - CHECK(secp256k1_num_eq(&rnum, &s2num) == (secp256k1_scalar_is_zero(&s2) || secp256k1_scalar_is_one(&s))); - } - - { - secp256k1_scalar neg; - secp256k1_num negnum; - secp256k1_num negnum2; - /* Check that comparison with zero matches comparison with zero on the number. */ - CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s)); - /* Check that comparison with the half order is equal to testing for high scalar. */ - CHECK(secp256k1_scalar_is_high(&s) == (secp256k1_num_cmp(&snum, &half_order) > 0)); - secp256k1_scalar_negate(&neg, &s); - secp256k1_num_sub(&negnum, &order, &snum); - secp256k1_num_mod(&negnum, &order); - /* Check that comparison with the half order is equal to testing for high scalar after negation. */ - CHECK(secp256k1_scalar_is_high(&neg) == (secp256k1_num_cmp(&negnum, &half_order) > 0)); - /* Negating should change the high property, unless the value was already zero. */ - CHECK((secp256k1_scalar_is_high(&s) == secp256k1_scalar_is_high(&neg)) == secp256k1_scalar_is_zero(&s)); - secp256k1_scalar_get_num(&negnum2, &neg); - /* Negating a scalar should be equal to (order - n) mod order on the number. */ - CHECK(secp256k1_num_eq(&negnum, &negnum2)); - secp256k1_scalar_add(&neg, &neg, &s); - /* Adding a number to its negation should result in zero. */ - CHECK(secp256k1_scalar_is_zero(&neg)); - secp256k1_scalar_negate(&neg, &neg); - /* Negating zero should still result in zero. */ - CHECK(secp256k1_scalar_is_zero(&neg)); - } - - { - /* Test secp256k1_scalar_mul_shift_var. */ - secp256k1_scalar r; - secp256k1_num one; - secp256k1_num rnum; - secp256k1_num rnum2; - unsigned char cone[1] = {0x01}; - unsigned int shift = 256 + secp256k1_rand_int(257); - secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift); - secp256k1_num_mul(&rnum, &s1num, &s2num); - secp256k1_num_shift(&rnum, shift - 1); - secp256k1_num_set_bin(&one, cone, 1); - secp256k1_num_add(&rnum, &rnum, &one); - secp256k1_num_shift(&rnum, 1); - secp256k1_scalar_get_num(&rnum2, &r); - CHECK(secp256k1_num_eq(&rnum, &rnum2)); - } - - { - /* test secp256k1_scalar_shr_int */ - secp256k1_scalar r; - int i; - random_scalar_order_test(&r); - for (i = 0; i < 100; ++i) { - int low; - int shift = 1 + secp256k1_rand_int(15); - int expected = r.d[0] % (1 << shift); - low = secp256k1_scalar_shr_int(&r, shift); - CHECK(expected == low); - } - } -#endif - - { - /* Test that scalar inverses are equal to the inverse of their number modulo the order. */ - if (!secp256k1_scalar_is_zero(&s)) { - secp256k1_scalar inv; -#ifndef USE_NUM_NONE - secp256k1_num invnum; - secp256k1_num invnum2; -#endif - secp256k1_scalar_inverse(&inv, &s); -#ifndef USE_NUM_NONE - secp256k1_num_mod_inverse(&invnum, &snum, &order); - secp256k1_scalar_get_num(&invnum2, &inv); - CHECK(secp256k1_num_eq(&invnum, &invnum2)); -#endif - secp256k1_scalar_mul(&inv, &inv, &s); - /* Multiplying a scalar with its inverse must result in one. */ - CHECK(secp256k1_scalar_is_one(&inv)); - 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 - } - } - - { - /* Test commutativity of add. */ - secp256k1_scalar r1, r2; - secp256k1_scalar_add(&r1, &s1, &s2); - secp256k1_scalar_add(&r2, &s2, &s1); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - - { - secp256k1_scalar r1, r2; - secp256k1_scalar b; - int i; - /* Test add_bit. */ - int bit = secp256k1_rand_bits(8); - secp256k1_scalar_set_int(&b, 1); - CHECK(secp256k1_scalar_is_one(&b)); - for (i = 0; i < bit; i++) { - secp256k1_scalar_add(&b, &b, &b); - } - r1 = s1; - r2 = s1; - if (!secp256k1_scalar_add(&r1, &r1, &b)) { - /* No overflow happened. */ - secp256k1_scalar_cadd_bit(&r2, bit, 1); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - /* cadd is a noop when flag is zero */ - secp256k1_scalar_cadd_bit(&r2, bit, 0); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - } - - { - /* Test commutativity of mul. */ - secp256k1_scalar r1, r2; - secp256k1_scalar_mul(&r1, &s1, &s2); - secp256k1_scalar_mul(&r2, &s2, &s1); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - - { - /* Test associativity of add. */ - secp256k1_scalar r1, r2; - secp256k1_scalar_add(&r1, &s1, &s2); - secp256k1_scalar_add(&r1, &r1, &s); - secp256k1_scalar_add(&r2, &s2, &s); - secp256k1_scalar_add(&r2, &s1, &r2); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - - { - /* Test associativity of mul. */ - secp256k1_scalar r1, r2; - secp256k1_scalar_mul(&r1, &s1, &s2); - secp256k1_scalar_mul(&r1, &r1, &s); - secp256k1_scalar_mul(&r2, &s2, &s); - secp256k1_scalar_mul(&r2, &s1, &r2); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - - { - /* Test distributitivity of mul over add. */ - secp256k1_scalar r1, r2, t; - secp256k1_scalar_add(&r1, &s1, &s2); - secp256k1_scalar_mul(&r1, &r1, &s); - secp256k1_scalar_mul(&r2, &s1, &s); - secp256k1_scalar_mul(&t, &s2, &s); - secp256k1_scalar_add(&r2, &r2, &t); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - - { - /* Test square. */ - secp256k1_scalar r1, r2; - secp256k1_scalar_sqr(&r1, &s1); - secp256k1_scalar_mul(&r2, &s1, &s1); - CHECK(secp256k1_scalar_eq(&r1, &r2)); - } - - { - /* Test multiplicative identity. */ - secp256k1_scalar r1, v1; - secp256k1_scalar_set_int(&v1,1); - secp256k1_scalar_mul(&r1, &s1, &v1); - CHECK(secp256k1_scalar_eq(&r1, &s1)); - } - - { - /* Test additive identity. */ - secp256k1_scalar r1, v0; - secp256k1_scalar_set_int(&v0,0); - secp256k1_scalar_add(&r1, &s1, &v0); - CHECK(secp256k1_scalar_eq(&r1, &s1)); - } - - { - /* Test zero product property. */ - secp256k1_scalar r1, v0; - secp256k1_scalar_set_int(&v0,0); - secp256k1_scalar_mul(&r1, &s1, &v0); - CHECK(secp256k1_scalar_eq(&r1, &v0)); - } - -} - -void run_scalar_tests(void) { - int i; - for (i = 0; i < 128 * count; i++) { - scalar_test(); - } - - { - /* (-1)+1 should be zero. */ - secp256k1_scalar s, o; - secp256k1_scalar_set_int(&s, 1); - CHECK(secp256k1_scalar_is_one(&s)); - secp256k1_scalar_negate(&o, &s); - secp256k1_scalar_add(&o, &o, &s); - CHECK(secp256k1_scalar_is_zero(&o)); - secp256k1_scalar_negate(&o, &o); - CHECK(secp256k1_scalar_is_zero(&o)); - } - -#ifndef USE_NUM_NONE - { - /* A scalar with value of the curve order should be 0. */ - secp256k1_num order; - secp256k1_scalar zero; - unsigned char bin[32]; - int overflow = 0; - secp256k1_scalar_order_get_num(&order); - secp256k1_num_get_bin(bin, 32, &order); - secp256k1_scalar_set_b32(&zero, bin, &overflow); - CHECK(overflow == 1); - CHECK(secp256k1_scalar_is_zero(&zero)); - } -#endif - - { - /* Does check_overflow check catch all ones? */ - static const secp256k1_scalar overflowed = SECP256K1_SCALAR_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL - ); - CHECK(secp256k1_scalar_check_overflow(&overflowed)); - } - - { - /* Static test vectors. - * These were reduced from ~10^12 random vectors based on comparison-decision - * and edge-case coverage on 32-bit and 64-bit implementations. - * The responses were generated with Sage 5.9. - */ - secp256k1_scalar x; - secp256k1_scalar y; - secp256k1_scalar z; - secp256k1_scalar zz; - secp256k1_scalar one; - secp256k1_scalar r1; - secp256k1_scalar r2; -#if defined(USE_SCALAR_INV_NUM) - secp256k1_scalar zzv; -#endif - int overflow; - 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, - 0xff, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff}}, - {{0xef, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff}}, - {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x00}, - {0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xe0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff}}, - {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x1e, 0xf8, 0xff, 0xff, 0xff, 0xfd, 0xff}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xe0, - 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, - 0xf3, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, - 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, - 0x00, 0xfe, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff}}, - {{0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xfc, 0x9f, - 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0x0f, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, - 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, - {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0x00, 0x00, 0xf8, 0xff, 0x0f, 0xc0, 0xff, 0xff, - 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0xff}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, - 0xf7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0x00, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0}, - {0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, - {{0x00, 0xf8, 0xff, 0x03, 0xff, 0xff, 0xff, 0x00, - 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x03, 0xc0, 0xff, 0x0f, 0xfc, 0xff}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, - 0xff, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, - {{0x8f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x7f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x03, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0x7f}, - {0xff, 0xcf, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, - 0x00, 0xc0, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, - 0xbf, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, - 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0x01, 0xfc, 0xff, 0x01, 0x00, 0xfe, 0xff}, - {0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00}}, - {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x7f, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0xff, - 0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xfc, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x3f, - 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0f, 0x7e, 0x00, 0x00}}, - {{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x1f, 0x00, 0x00, 0xfe, 0x07, 0x00}, - {0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfb, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60}}, - {{0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, - 0x80, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - {0xff, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00}}, - {{0x80, 0x00, 0x00, 0x00, 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, 0xff}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, - 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0xff, 0xff, 0xcf, 0xff, 0x1f, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x7e, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00}, - {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0xff, 0xff, 0x7f, 0x00, 0x80, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, - {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x80, - 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x1f, 0x00, 0xfe}}, - {{0xff, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0xff, - 0xff, 0x03, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, - 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {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}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x7f, 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, 0xff, 0xff, 0xff, 0xff}, - {0x7f, 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, 0xff, 0xff, 0xff, 0xff}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xc0, - 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, - 0xf0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff}}, - {{0x7f, 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, 0xff, 0xff, 0xff, 0xff}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}, - {{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}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x7e, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - {0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, - {{0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x00, - 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, - 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, - 0xff, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x3f, 0x00, 0x00, 0xc0, 0xf1, 0x7f, 0x00}}, - {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00}, - {0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, - 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, - 0x00, 0x00, 0xfc, 0xff, 0xff, 0x01, 0xff, 0xff}}, - {{0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x80, 0x00, 0x00, 0x80, 0xff, 0x03, 0xe0, 0x01, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, - {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xfe, 0xff, 0xff, 0xf0, 0x07, 0x00, 0x3c, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x07, 0xe0, 0xff, 0x00, 0x00, 0x00}}, - {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x80, 0x00, - 0x00, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0xff, 0x1f, - 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0xfe, 0xff}}, - {{0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, - 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, - 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf0}, - {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}}, - {{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[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, - 0x20, 0x1e, 0x86, 0xd0, 0x95, 0xf6, 0x92, 0x35}, - {0xdc, 0x90, 0x7a, 0x07, 0x2e, 0x1e, 0x44, 0x6d, - 0xf8, 0x15, 0x24, 0x5b, 0x5a, 0x96, 0x37, 0x9c, - 0x37, 0x7b, 0x0d, 0xac, 0x1b, 0x65, 0x58, 0x49, - 0x43, 0xb7, 0x31, 0xbb, 0xa7, 0xf4, 0x97, 0x15}}, - {{0xf1, 0xf7, 0x3a, 0x50, 0xe6, 0x10, 0xba, 0x22, - 0x43, 0x4d, 0x1f, 0x1f, 0x7c, 0x27, 0xca, 0x9c, - 0xb8, 0xb6, 0xa0, 0xfc, 0xd8, 0xc0, 0x05, 0x2f, - 0xf7, 0x08, 0xe1, 0x76, 0xdd, 0xd0, 0x80, 0xc8}, - {0xe3, 0x80, 0x80, 0xb8, 0xdb, 0xe3, 0xa9, 0x77, - 0x00, 0xb0, 0xf5, 0x2e, 0x27, 0xe2, 0x68, 0xc4, - 0x88, 0xe8, 0x04, 0xc1, 0x12, 0xbf, 0x78, 0x59, - 0xe6, 0xa9, 0x7c, 0xe1, 0x81, 0xdd, 0xb9, 0xd5}}, - {{0x96, 0xe2, 0xee, 0x01, 0xa6, 0x80, 0x31, 0xef, - 0x5c, 0xd0, 0x19, 0xb4, 0x7d, 0x5f, 0x79, 0xab, - 0xa1, 0x97, 0xd3, 0x7e, 0x33, 0xbb, 0x86, 0x55, - 0x60, 0x20, 0x10, 0x0d, 0x94, 0x2d, 0x11, 0x7c}, - {0xcc, 0xab, 0xe0, 0xe8, 0x98, 0x65, 0x12, 0x96, - 0x38, 0x5a, 0x1a, 0xf2, 0x85, 0x23, 0x59, 0x5f, - 0xf9, 0xf3, 0xc2, 0x81, 0x70, 0x92, 0x65, 0x12, - 0x9c, 0x65, 0x1e, 0x96, 0x00, 0xef, 0xe7, 0x63}}, - {{0xac, 0x1e, 0x62, 0xc2, 0x59, 0xfc, 0x4e, 0x5c, - 0x83, 0xb0, 0xd0, 0x6f, 0xce, 0x19, 0xf6, 0xbf, - 0xa4, 0xb0, 0xe0, 0x53, 0x66, 0x1f, 0xbf, 0xc9, - 0x33, 0x47, 0x37, 0xa9, 0x3d, 0x5d, 0xb0, 0x48}, - {0x86, 0xb9, 0x2a, 0x7f, 0x8e, 0xa8, 0x60, 0x42, - 0x26, 0x6d, 0x6e, 0x1c, 0xa2, 0xec, 0xe0, 0xe5, - 0x3e, 0x0a, 0x33, 0xbb, 0x61, 0x4c, 0x9f, 0x3c, - 0xd1, 0xdf, 0x49, 0x33, 0xcd, 0x72, 0x78, 0x18}}, - {{0xf7, 0xd3, 0xcd, 0x49, 0x5c, 0x13, 0x22, 0xfb, - 0x2e, 0xb2, 0x2f, 0x27, 0xf5, 0x8a, 0x5d, 0x74, - 0xc1, 0x58, 0xc5, 0xc2, 0x2d, 0x9f, 0x52, 0xc6, - 0x63, 0x9f, 0xba, 0x05, 0x76, 0x45, 0x7a, 0x63}, - {0x8a, 0xfa, 0x55, 0x4d, 0xdd, 0xa3, 0xb2, 0xc3, - 0x44, 0xfd, 0xec, 0x72, 0xde, 0xef, 0xc0, 0x99, - 0xf5, 0x9f, 0xe2, 0x52, 0xb4, 0x05, 0x32, 0x58, - 0x57, 0xc1, 0x8f, 0xea, 0xc3, 0x24, 0x5b, 0x94}}, - {{0x05, 0x83, 0xee, 0xdd, 0x64, 0xf0, 0x14, 0x3b, - 0xa0, 0x14, 0x4a, 0x3a, 0x41, 0x82, 0x7c, 0xa7, - 0x2c, 0xaa, 0xb1, 0x76, 0xbb, 0x59, 0x64, 0x5f, - 0x52, 0xad, 0x25, 0x29, 0x9d, 0x8f, 0x0b, 0xb0}, - {0x7e, 0xe3, 0x7c, 0xca, 0xcd, 0x4f, 0xb0, 0x6d, - 0x7a, 0xb2, 0x3e, 0xa0, 0x08, 0xb9, 0xa8, 0x2d, - 0xc2, 0xf4, 0x99, 0x66, 0xcc, 0xac, 0xd8, 0xb9, - 0x72, 0x2a, 0x4a, 0x3e, 0x0f, 0x7b, 0xbf, 0xf4}}, - {{0x8c, 0x9c, 0x78, 0x2b, 0x39, 0x61, 0x7e, 0xf7, - 0x65, 0x37, 0x66, 0x09, 0x38, 0xb9, 0x6f, 0x70, - 0x78, 0x87, 0xff, 0xcf, 0x93, 0xca, 0x85, 0x06, - 0x44, 0x84, 0xa7, 0xfe, 0xd3, 0xa4, 0xe3, 0x7e}, - {0xa2, 0x56, 0x49, 0x23, 0x54, 0xa5, 0x50, 0xe9, - 0x5f, 0xf0, 0x4d, 0xe7, 0xdc, 0x38, 0x32, 0x79, - 0x4f, 0x1c, 0xb7, 0xe4, 0xbb, 0xf8, 0xbb, 0x2e, - 0x40, 0x41, 0x4b, 0xcc, 0xe3, 0x1e, 0x16, 0x36}}, - {{0x0c, 0x1e, 0xd7, 0x09, 0x25, 0x40, 0x97, 0xcb, - 0x5c, 0x46, 0xa8, 0xda, 0xef, 0x25, 0xd5, 0xe5, - 0x92, 0x4d, 0xcf, 0xa3, 0xc4, 0x5d, 0x35, 0x4a, - 0xe4, 0x61, 0x92, 0xf3, 0xbf, 0x0e, 0xcd, 0xbe}, - {0xe4, 0xaf, 0x0a, 0xb3, 0x30, 0x8b, 0x9b, 0x48, - 0x49, 0x43, 0xc7, 0x64, 0x60, 0x4a, 0x2b, 0x9e, - 0x95, 0x5f, 0x56, 0xe8, 0x35, 0xdc, 0xeb, 0xdc, - 0xc7, 0xc4, 0xfe, 0x30, 0x40, 0xc7, 0xbf, 0xa4}}, - {{0xd4, 0xa0, 0xf5, 0x81, 0x49, 0x6b, 0xb6, 0x8b, - 0x0a, 0x69, 0xf9, 0xfe, 0xa8, 0x32, 0xe5, 0xe0, - 0xa5, 0xcd, 0x02, 0x53, 0xf9, 0x2c, 0xe3, 0x53, - 0x83, 0x36, 0xc6, 0x02, 0xb5, 0xeb, 0x64, 0xb8}, - {0x1d, 0x42, 0xb9, 0xf9, 0xe9, 0xe3, 0x93, 0x2c, - 0x4c, 0xee, 0x6c, 0x5a, 0x47, 0x9e, 0x62, 0x01, - 0x6b, 0x04, 0xfe, 0xa4, 0x30, 0x2b, 0x0d, 0x4f, - 0x71, 0x10, 0xd3, 0x55, 0xca, 0xf3, 0x5e, 0x80}}, - {{0x77, 0x05, 0xf6, 0x0c, 0x15, 0x9b, 0x45, 0xe7, - 0xb9, 0x11, 0xb8, 0xf5, 0xd6, 0xda, 0x73, 0x0c, - 0xda, 0x92, 0xea, 0xd0, 0x9d, 0xd0, 0x18, 0x92, - 0xce, 0x9a, 0xaa, 0xee, 0x0f, 0xef, 0xde, 0x30}, - {0xf1, 0xf1, 0xd6, 0x9b, 0x51, 0xd7, 0x77, 0x62, - 0x52, 0x10, 0xb8, 0x7a, 0x84, 0x9d, 0x15, 0x4e, - 0x07, 0xdc, 0x1e, 0x75, 0x0d, 0x0c, 0x3b, 0xdb, - 0x74, 0x58, 0x62, 0x02, 0x90, 0x54, 0x8b, 0x43}}, - {{0xa6, 0xfe, 0x0b, 0x87, 0x80, 0x43, 0x67, 0x25, - 0x57, 0x5d, 0xec, 0x40, 0x50, 0x08, 0xd5, 0x5d, - 0x43, 0xd7, 0xe0, 0xaa, 0xe0, 0x13, 0xb6, 0xb0, - 0xc0, 0xd4, 0xe5, 0x0d, 0x45, 0x83, 0xd6, 0x13}, - {0x40, 0x45, 0x0a, 0x92, 0x31, 0xea, 0x8c, 0x60, - 0x8c, 0x1f, 0xd8, 0x76, 0x45, 0xb9, 0x29, 0x00, - 0x26, 0x32, 0xd8, 0xa6, 0x96, 0x88, 0xe2, 0xc4, - 0x8b, 0xdb, 0x7f, 0x17, 0x87, 0xcc, 0xc8, 0xf2}}, - {{0xc2, 0x56, 0xe2, 0xb6, 0x1a, 0x81, 0xe7, 0x31, - 0x63, 0x2e, 0xbb, 0x0d, 0x2f, 0x81, 0x67, 0xd4, - 0x22, 0xe2, 0x38, 0x02, 0x25, 0x97, 0xc7, 0x88, - 0x6e, 0xdf, 0xbe, 0x2a, 0xa5, 0x73, 0x63, 0xaa}, - {0x50, 0x45, 0xe2, 0xc3, 0xbd, 0x89, 0xfc, 0x57, - 0xbd, 0x3c, 0xa3, 0x98, 0x7e, 0x7f, 0x36, 0x38, - 0x92, 0x39, 0x1f, 0x0f, 0x81, 0x1a, 0x06, 0x51, - 0x1f, 0x8d, 0x6a, 0xff, 0x47, 0x16, 0x06, 0x9c}}, - {{0x33, 0x95, 0xa2, 0x6f, 0x27, 0x5f, 0x9c, 0x9c, - 0x64, 0x45, 0xcb, 0xd1, 0x3c, 0xee, 0x5e, 0x5f, - 0x48, 0xa6, 0xaf, 0xe3, 0x79, 0xcf, 0xb1, 0xe2, - 0xbf, 0x55, 0x0e, 0xa2, 0x3b, 0x62, 0xf0, 0xe4}, - {0x14, 0xe8, 0x06, 0xe3, 0xbe, 0x7e, 0x67, 0x01, - 0xc5, 0x21, 0x67, 0xd8, 0x54, 0xb5, 0x7f, 0xa4, - 0xf9, 0x75, 0x70, 0x1c, 0xfd, 0x79, 0xdb, 0x86, - 0xad, 0x37, 0x85, 0x83, 0x56, 0x4e, 0xf0, 0xbf}}, - {{0xbc, 0xa6, 0xe0, 0x56, 0x4e, 0xef, 0xfa, 0xf5, - 0x1d, 0x5d, 0x3f, 0x2a, 0x5b, 0x19, 0xab, 0x51, - 0xc5, 0x8b, 0xdd, 0x98, 0x28, 0x35, 0x2f, 0xc3, - 0x81, 0x4f, 0x5c, 0xe5, 0x70, 0xb9, 0xeb, 0x62}, - {0xc4, 0x6d, 0x26, 0xb0, 0x17, 0x6b, 0xfe, 0x6c, - 0x12, 0xf8, 0xe7, 0xc1, 0xf5, 0x2f, 0xfa, 0x91, - 0x13, 0x27, 0xbd, 0x73, 0xcc, 0x33, 0x31, 0x1c, - 0x39, 0xe3, 0x27, 0x6a, 0x95, 0xcf, 0xc5, 0xfb}}, - {{0x30, 0xb2, 0x99, 0x84, 0xf0, 0x18, 0x2a, 0x6e, - 0x1e, 0x27, 0xed, 0xa2, 0x29, 0x99, 0x41, 0x56, - 0xe8, 0xd4, 0x0d, 0xef, 0x99, 0x9c, 0xf3, 0x58, - 0x29, 0x55, 0x1a, 0xc0, 0x68, 0xd6, 0x74, 0xa4}, - {0x07, 0x9c, 0xe7, 0xec, 0xf5, 0x36, 0x73, 0x41, - 0xa3, 0x1c, 0xe5, 0x93, 0x97, 0x6a, 0xfd, 0xf7, - 0x53, 0x18, 0xab, 0xaf, 0xeb, 0x85, 0xbd, 0x92, - 0x90, 0xab, 0x3c, 0xbf, 0x30, 0x82, 0xad, 0xf6}}, - {{0xc6, 0x87, 0x8a, 0x2a, 0xea, 0xc0, 0xa9, 0xec, - 0x6d, 0xd3, 0xdc, 0x32, 0x23, 0xce, 0x62, 0x19, - 0xa4, 0x7e, 0xa8, 0xdd, 0x1c, 0x33, 0xae, 0xd3, - 0x4f, 0x62, 0x9f, 0x52, 0xe7, 0x65, 0x46, 0xf4}, - {0x97, 0x51, 0x27, 0x67, 0x2d, 0xa2, 0x82, 0x87, - 0x98, 0xd3, 0xb6, 0x14, 0x7f, 0x51, 0xd3, 0x9a, - 0x0b, 0xd0, 0x76, 0x81, 0xb2, 0x4f, 0x58, 0x92, - 0xa4, 0x86, 0xa1, 0xa7, 0x09, 0x1d, 0xef, 0x9b}}, - {{0xb3, 0x0f, 0x2b, 0x69, 0x0d, 0x06, 0x90, 0x64, - 0xbd, 0x43, 0x4c, 0x10, 0xe8, 0x98, 0x1c, 0xa3, - 0xe1, 0x68, 0xe9, 0x79, 0x6c, 0x29, 0x51, 0x3f, - 0x41, 0xdc, 0xdf, 0x1f, 0xf3, 0x60, 0xbe, 0x33}, - {0xa1, 0x5f, 0xf7, 0x1d, 0xb4, 0x3e, 0x9b, 0x3c, - 0xe7, 0xbd, 0xb6, 0x06, 0xd5, 0x60, 0x06, 0x6d, - 0x50, 0xd2, 0xf4, 0x1a, 0x31, 0x08, 0xf2, 0xea, - 0x8e, 0xef, 0x5f, 0x7d, 0xb6, 0xd0, 0xc0, 0x27}}, - {{0x62, 0x9a, 0xd9, 0xbb, 0x38, 0x36, 0xce, 0xf7, - 0x5d, 0x2f, 0x13, 0xec, 0xc8, 0x2d, 0x02, 0x8a, - 0x2e, 0x72, 0xf0, 0xe5, 0x15, 0x9d, 0x72, 0xae, - 0xfc, 0xb3, 0x4f, 0x02, 0xea, 0xe1, 0x09, 0xfe}, - {0x00, 0x00, 0x00, 0x00, 0xfa, 0x0a, 0x3d, 0xbc, - 0xad, 0x16, 0x0c, 0xb6, 0xe7, 0x7c, 0x8b, 0x39, - 0x9a, 0x43, 0xbb, 0xe3, 0xc2, 0x55, 0x15, 0x14, - 0x75, 0xac, 0x90, 0x9b, 0x7f, 0x9a, 0x92, 0x00}}, - {{0x8b, 0xac, 0x70, 0x86, 0x29, 0x8f, 0x00, 0x23, - 0x7b, 0x45, 0x30, 0xaa, 0xb8, 0x4c, 0xc7, 0x8d, - 0x4e, 0x47, 0x85, 0xc6, 0x19, 0xe3, 0x96, 0xc2, - 0x9a, 0xa0, 0x12, 0xed, 0x6f, 0xd7, 0x76, 0x16}, - {0x45, 0xaf, 0x7e, 0x33, 0xc7, 0x7f, 0x10, 0x6c, - 0x7c, 0x9f, 0x29, 0xc1, 0xa8, 0x7e, 0x15, 0x84, - 0xe7, 0x7d, 0xc0, 0x6d, 0xab, 0x71, 0x5d, 0xd0, - 0x6b, 0x9f, 0x97, 0xab, 0xcb, 0x51, 0x0c, 0x9f}}, - {{0x9e, 0xc3, 0x92, 0xb4, 0x04, 0x9f, 0xc8, 0xbb, - 0xdd, 0x9e, 0xc6, 0x05, 0xfd, 0x65, 0xec, 0x94, - 0x7f, 0x2c, 0x16, 0xc4, 0x40, 0xac, 0x63, 0x7b, - 0x7d, 0xb8, 0x0c, 0xe4, 0x5b, 0xe3, 0xa7, 0x0e}, - {0x43, 0xf4, 0x44, 0xe8, 0xcc, 0xc8, 0xd4, 0x54, - 0x33, 0x37, 0x50, 0xf2, 0x87, 0x42, 0x2e, 0x00, - 0x49, 0x60, 0x62, 0x02, 0xfd, 0x1a, 0x7c, 0xdb, - 0x29, 0x6c, 0x6d, 0x54, 0x53, 0x08, 0xd1, 0xc8}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, - {{0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, - 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, - 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, - 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}, - {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, - 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, - 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, - 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, - {{0x28, 0x56, 0xac, 0x0e, 0x4f, 0x98, 0x09, 0xf0, - 0x49, 0xfa, 0x7f, 0x84, 0xac, 0x7e, 0x50, 0x5b, - 0x17, 0x43, 0x14, 0x89, 0x9c, 0x53, 0xa8, 0x94, - 0x30, 0xf2, 0x11, 0x4d, 0x92, 0x14, 0x27, 0xe8}, - {0x39, 0x7a, 0x84, 0x56, 0x79, 0x9d, 0xec, 0x26, - 0x2c, 0x53, 0xc1, 0x94, 0xc9, 0x8d, 0x9e, 0x9d, - 0x32, 0x1f, 0xdd, 0x84, 0x04, 0xe8, 0xe2, 0x0a, - 0x6b, 0xbe, 0xbb, 0x42, 0x40, 0x67, 0x30, 0x6c}}, - {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, - 0x40, 0x2d, 0xa1, 0x73, 0x2f, 0xc9, 0xbe, 0xbd}, - {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, - 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, - 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, - 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, - {{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}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, - {{0x1c, 0xc4, 0xf7, 0xda, 0x0f, 0x65, 0xca, 0x39, - 0x70, 0x52, 0x92, 0x8e, 0xc3, 0xc8, 0x15, 0xea, - 0x7f, 0x10, 0x9e, 0x77, 0x4b, 0x6e, 0x2d, 0xdf, - 0xe8, 0x30, 0x9d, 0xda, 0xe8, 0x9a, 0x65, 0xae}, - {0x02, 0xb0, 0x16, 0xb1, 0x1d, 0xc8, 0x57, 0x7b, - 0xa2, 0x3a, 0xa2, 0xa3, 0x38, 0x5c, 0x8f, 0xeb, - 0x66, 0x37, 0x91, 0xa8, 0x5f, 0xef, 0x04, 0xf6, - 0x59, 0x75, 0xe1, 0xee, 0x92, 0xf6, 0x0e, 0x30}}, - {{0x8d, 0x76, 0x14, 0xa4, 0x14, 0x06, 0x9f, 0x9a, - 0xdf, 0x4a, 0x85, 0xa7, 0x6b, 0xbf, 0x29, 0x6f, - 0xbc, 0x34, 0x87, 0x5d, 0xeb, 0xbb, 0x2e, 0xa9, - 0xc9, 0x1f, 0x58, 0xd6, 0x9a, 0x82, 0xa0, 0x56}, - {0xd4, 0xb9, 0xdb, 0x88, 0x1d, 0x04, 0xe9, 0x93, - 0x8d, 0x3f, 0x20, 0xd5, 0x86, 0xa8, 0x83, 0x07, - 0xdb, 0x09, 0xd8, 0x22, 0x1f, 0x7f, 0xf1, 0x71, - 0xc8, 0xe7, 0x5d, 0x47, 0xaf, 0x8b, 0x72, 0xe9}}, - {{0x83, 0xb9, 0x39, 0xb2, 0xa4, 0xdf, 0x46, 0x87, - 0xc2, 0xb8, 0xf1, 0xe6, 0x4c, 0xd1, 0xe2, 0xa9, - 0xe4, 0x70, 0x30, 0x34, 0xbc, 0x52, 0x7c, 0x55, - 0xa6, 0xec, 0x80, 0xa4, 0xe5, 0xd2, 0xdc, 0x73}, - {0x08, 0xf1, 0x03, 0xcf, 0x16, 0x73, 0xe8, 0x7d, - 0xb6, 0x7e, 0x9b, 0xc0, 0xb4, 0xc2, 0xa5, 0x86, - 0x02, 0x77, 0xd5, 0x27, 0x86, 0xa5, 0x15, 0xfb, - 0xae, 0x9b, 0x8c, 0xa9, 0xf9, 0xf8, 0xa8, 0x4a}}, - {{0x8b, 0x00, 0x49, 0xdb, 0xfa, 0xf0, 0x1b, 0xa2, - 0xed, 0x8a, 0x9a, 0x7a, 0x36, 0x78, 0x4a, 0xc7, - 0xf7, 0xad, 0x39, 0xd0, 0x6c, 0x65, 0x7a, 0x41, - 0xce, 0xd6, 0xd6, 0x4c, 0x20, 0x21, 0x6b, 0xc7}, - {0xc6, 0xca, 0x78, 0x1d, 0x32, 0x6c, 0x6c, 0x06, - 0x91, 0xf2, 0x1a, 0xe8, 0x43, 0x16, 0xea, 0x04, - 0x3c, 0x1f, 0x07, 0x85, 0xf7, 0x09, 0x22, 0x08, - 0xba, 0x13, 0xfd, 0x78, 0x1e, 0x3f, 0x6f, 0x62}}, - {{0x25, 0x9b, 0x7c, 0xb0, 0xac, 0x72, 0x6f, 0xb2, - 0xe3, 0x53, 0x84, 0x7a, 0x1a, 0x9a, 0x98, 0x9b, - 0x44, 0xd3, 0x59, 0xd0, 0x8e, 0x57, 0x41, 0x40, - 0x78, 0xa7, 0x30, 0x2f, 0x4c, 0x9c, 0xb9, 0x68}, - {0xb7, 0x75, 0x03, 0x63, 0x61, 0xc2, 0x48, 0x6e, - 0x12, 0x3d, 0xbf, 0x4b, 0x27, 0xdf, 0xb1, 0x7a, - 0xff, 0x4e, 0x31, 0x07, 0x83, 0xf4, 0x62, 0x5b, - 0x19, 0xa5, 0xac, 0xa0, 0x32, 0x58, 0x0d, 0xa7}}, - {{0x43, 0x4f, 0x10, 0xa4, 0xca, 0xdb, 0x38, 0x67, - 0xfa, 0xae, 0x96, 0xb5, 0x6d, 0x97, 0xff, 0x1f, - 0xb6, 0x83, 0x43, 0xd3, 0xa0, 0x2d, 0x70, 0x7a, - 0x64, 0x05, 0x4c, 0xa7, 0xc1, 0xa5, 0x21, 0x51}, - {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}}, - {{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 < 33; i++) { - secp256k1_scalar_set_b32(&x, chal[i][0], &overflow); - CHECK(!overflow); - secp256k1_scalar_set_b32(&y, chal[i][1], &overflow); - CHECK(!overflow); - secp256k1_scalar_set_b32(&r1, res[i][0], &overflow); - CHECK(!overflow); - secp256k1_scalar_set_b32(&r2, res[i][1], &overflow); - CHECK(!overflow); - secp256k1_scalar_mul(&z, &x, &y); - CHECK(!secp256k1_scalar_check_overflow(&z)); - CHECK(secp256k1_scalar_eq(&r1, &z)); - if (!secp256k1_scalar_is_zero(&y)) { - secp256k1_scalar_inverse(&zz, &y); - CHECK(!secp256k1_scalar_check_overflow(&zz)); -#if defined(USE_SCALAR_INV_NUM) - secp256k1_scalar_inverse_var(&zzv, &y); - CHECK(secp256k1_scalar_eq(&zzv, &zz)); -#endif - secp256k1_scalar_mul(&z, &z, &zz); - CHECK(!secp256k1_scalar_check_overflow(&z)); - CHECK(secp256k1_scalar_eq(&x, &z)); - secp256k1_scalar_mul(&zz, &zz, &y); - CHECK(!secp256k1_scalar_check_overflow(&zz)); - CHECK(secp256k1_scalar_eq(&one, &zz)); - } - secp256k1_scalar_mul(&z, &x, &x); - CHECK(!secp256k1_scalar_check_overflow(&z)); - secp256k1_scalar_sqr(&zz, &x); - CHECK(!secp256k1_scalar_check_overflow(&zz)); - CHECK(secp256k1_scalar_eq(&zz, &z)); - CHECK(secp256k1_scalar_eq(&r2, &zz)); - } - } -} - -/***** FIELD TESTS *****/ - -void random_fe(secp256k1_fe *x) { - unsigned char bin[32]; - do { - secp256k1_rand256(bin); - if (secp256k1_fe_set_b32(x, bin)) { - return; - } - } while(1); -} - -void random_fe_test(secp256k1_fe *x) { - unsigned char bin[32]; - do { - secp256k1_rand256_test(bin); - if (secp256k1_fe_set_b32(x, bin)) { - return; - } - } while(1); -} - -void random_fe_non_zero(secp256k1_fe *nz) { - int tries = 10; - while (--tries >= 0) { - random_fe(nz); - secp256k1_fe_normalize(nz); - if (!secp256k1_fe_is_zero(nz)) { - break; - } - } - /* Infinitesimal probability of spurious failure here */ - CHECK(tries >= 0); -} - -void random_fe_non_square(secp256k1_fe *ns) { - secp256k1_fe r; - random_fe_non_zero(ns); - if (secp256k1_fe_sqrt(&r, ns)) { - secp256k1_fe_negate(ns, ns, 1); - } -} - -int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { - secp256k1_fe an = *a; - secp256k1_fe bn = *b; - secp256k1_fe_normalize_weak(&an); - secp256k1_fe_normalize_var(&bn); - return secp256k1_fe_equal_var(&an, &bn); -} - -int check_fe_inverse(const secp256k1_fe *a, const secp256k1_fe *ai) { - secp256k1_fe x; - secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_fe_mul(&x, a, ai); - return check_fe_equal(&x, &one); -} - -void run_field_convert(void) { - static const unsigned char b32[32] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, - 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40 - }; - static const secp256k1_fe_storage fes = SECP256K1_FE_STORAGE_CONST( - 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, - 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL - ); - static const secp256k1_fe fe = SECP256K1_FE_CONST( - 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, - 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL - ); - secp256k1_fe fe2; - unsigned char b322[32]; - secp256k1_fe_storage fes2; - /* Check conversions to fe. */ - CHECK(secp256k1_fe_set_b32(&fe2, b32)); - CHECK(secp256k1_fe_equal_var(&fe, &fe2)); - secp256k1_fe_from_storage(&fe2, &fes); - CHECK(secp256k1_fe_equal_var(&fe, &fe2)); - /* Check conversion from fe. */ - secp256k1_fe_get_b32(b322, &fe); - CHECK(memcmp(b322, b32, 32) == 0); - secp256k1_fe_to_storage(&fes2, &fe); - CHECK(memcmp(&fes2, &fes, sizeof(fes)) == 0); -} - -int fe_memcmp(const secp256k1_fe *a, const secp256k1_fe *b) { - secp256k1_fe t = *b; -#ifdef VERIFY - t.magnitude = a->magnitude; - t.normalized = a->normalized; -#endif - return memcmp(a, &t, sizeof(secp256k1_fe)); -} - -void run_field_misc(void) { - secp256k1_fe x; - secp256k1_fe y; - secp256k1_fe z; - secp256k1_fe q; - secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); - int i, j; - for (i = 0; i < 5*count; i++) { - secp256k1_fe_storage xs, ys, zs; - random_fe(&x); - random_fe_non_zero(&y); - /* Test the fe equality and comparison operations. */ - CHECK(secp256k1_fe_cmp_var(&x, &x) == 0); - CHECK(secp256k1_fe_equal_var(&x, &x)); - z = x; - secp256k1_fe_add(&z,&y); - /* Test fe conditional move; z is not normalized here. */ - q = x; - secp256k1_fe_cmov(&x, &z, 0); - VERIFY_CHECK(!x.normalized && x.magnitude == z.magnitude); - secp256k1_fe_cmov(&x, &x, 1); - CHECK(fe_memcmp(&x, &z) != 0); - CHECK(fe_memcmp(&x, &q) == 0); - secp256k1_fe_cmov(&q, &z, 1); - VERIFY_CHECK(!q.normalized && q.magnitude == z.magnitude); - CHECK(fe_memcmp(&q, &z) == 0); - secp256k1_fe_normalize_var(&x); - secp256k1_fe_normalize_var(&z); - CHECK(!secp256k1_fe_equal_var(&x, &z)); - secp256k1_fe_normalize_var(&q); - secp256k1_fe_cmov(&q, &z, (i&1)); - VERIFY_CHECK(q.normalized && q.magnitude == 1); - for (j = 0; j < 6; j++) { - secp256k1_fe_negate(&z, &z, j+1); - secp256k1_fe_normalize_var(&q); - secp256k1_fe_cmov(&q, &z, (j&1)); - VERIFY_CHECK(!q.normalized && q.magnitude == (j+2)); - } - secp256k1_fe_normalize_var(&z); - /* Test storage conversion and conditional moves. */ - secp256k1_fe_to_storage(&xs, &x); - secp256k1_fe_to_storage(&ys, &y); - secp256k1_fe_to_storage(&zs, &z); - secp256k1_fe_storage_cmov(&zs, &xs, 0); - secp256k1_fe_storage_cmov(&zs, &zs, 1); - CHECK(memcmp(&xs, &zs, sizeof(xs)) != 0); - secp256k1_fe_storage_cmov(&ys, &xs, 1); - CHECK(memcmp(&xs, &ys, sizeof(xs)) == 0); - secp256k1_fe_from_storage(&x, &xs); - secp256k1_fe_from_storage(&y, &ys); - secp256k1_fe_from_storage(&z, &zs); - /* Test that mul_int, mul, and add agree. */ - secp256k1_fe_add(&y, &x); - secp256k1_fe_add(&y, &x); - z = x; - secp256k1_fe_mul_int(&z, 3); - CHECK(check_fe_equal(&y, &z)); - secp256k1_fe_add(&y, &x); - secp256k1_fe_add(&z, &x); - CHECK(check_fe_equal(&z, &y)); - z = x; - secp256k1_fe_mul_int(&z, 5); - secp256k1_fe_mul(&q, &x, &fe5); - CHECK(check_fe_equal(&z, &q)); - secp256k1_fe_negate(&x, &x, 1); - secp256k1_fe_add(&z, &x); - secp256k1_fe_add(&q, &x); - CHECK(check_fe_equal(&y, &z)); - CHECK(check_fe_equal(&q, &y)); - } -} - -void run_field_inv(void) { - secp256k1_fe x, xi, xii; - int i; - for (i = 0; i < 10*count; i++) { - random_fe_non_zero(&x); - secp256k1_fe_inv(&xi, &x); - CHECK(check_fe_inverse(&x, &xi)); - secp256k1_fe_inv(&xii, &xi); - CHECK(check_fe_equal(&x, &xii)); - } -} - -void run_field_inv_var(void) { - secp256k1_fe x, xi, xii; - int i; - for (i = 0; i < 10*count; i++) { - random_fe_non_zero(&x); - secp256k1_fe_inv_var(&xi, &x); - CHECK(check_fe_inverse(&x, &xi)); - secp256k1_fe_inv_var(&xii, &xi); - CHECK(check_fe_equal(&x, &xii)); - } -} - -void run_field_inv_all_var(void) { - secp256k1_fe x[16], xi[16], xii[16]; - int i; - /* Check it's safe to call for 0 elements */ - secp256k1_fe_inv_all_var(xi, x, 0); - for (i = 0; i < count; i++) { - size_t j; - size_t len = secp256k1_rand_int(15) + 1; - for (j = 0; j < len; j++) { - random_fe_non_zero(&x[j]); - } - secp256k1_fe_inv_all_var(xi, x, len); - for (j = 0; j < len; j++) { - CHECK(check_fe_inverse(&x[j], &xi[j])); - } - secp256k1_fe_inv_all_var(xii, xi, len); - for (j = 0; j < len; j++) { - CHECK(check_fe_equal(&x[j], &xii[j])); - } - } -} - -void run_sqr(void) { - secp256k1_fe x, s; - - { - int i; - secp256k1_fe_set_int(&x, 1); - secp256k1_fe_negate(&x, &x, 1); - - for (i = 1; i <= 512; ++i) { - secp256k1_fe_mul_int(&x, 2); - secp256k1_fe_normalize(&x); - secp256k1_fe_sqr(&s, &x); - } - } -} - -void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { - secp256k1_fe r1, r2; - int v = secp256k1_fe_sqrt(&r1, a); - CHECK((v == 0) == (k == NULL)); - - if (k != NULL) { - /* Check that the returned root is +/- the given known answer */ - secp256k1_fe_negate(&r2, &r1, 1); - secp256k1_fe_add(&r1, k); secp256k1_fe_add(&r2, k); - secp256k1_fe_normalize(&r1); secp256k1_fe_normalize(&r2); - CHECK(secp256k1_fe_is_zero(&r1) || secp256k1_fe_is_zero(&r2)); - } -} - -void run_sqrt(void) { - secp256k1_fe ns, x, s, t; - int i; - - /* Check sqrt(0) is 0 */ - secp256k1_fe_set_int(&x, 0); - secp256k1_fe_sqr(&s, &x); - test_sqrt(&s, &x); - - /* Check sqrt of small squares (and their negatives) */ - for (i = 1; i <= 100; i++) { - secp256k1_fe_set_int(&x, i); - secp256k1_fe_sqr(&s, &x); - test_sqrt(&s, &x); - secp256k1_fe_negate(&t, &s, 1); - test_sqrt(&t, NULL); - } - - /* Consistency checks for large random values */ - for (i = 0; i < 10; i++) { - int j; - random_fe_non_square(&ns); - for (j = 0; j < count; j++) { - random_fe(&x); - secp256k1_fe_sqr(&s, &x); - test_sqrt(&s, &x); - secp256k1_fe_negate(&t, &s, 1); - test_sqrt(&t, NULL); - secp256k1_fe_mul(&t, &s, &ns); - test_sqrt(&t, NULL); - } - } -} - -/***** GROUP TESTS *****/ - -void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); - CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); -} - -/* This compares jacobian points including their Z, not just their geometric meaning. */ -int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { - secp256k1_gej a2; - secp256k1_gej b2; - int ret = 1; - ret &= a->infinity == b->infinity; - if (ret && !a->infinity) { - a2 = *a; - b2 = *b; - secp256k1_fe_normalize(&a2.x); - secp256k1_fe_normalize(&a2.y); - secp256k1_fe_normalize(&a2.z); - secp256k1_fe_normalize(&b2.x); - secp256k1_fe_normalize(&b2.y); - secp256k1_fe_normalize(&b2.z); - ret &= secp256k1_fe_cmp_var(&a2.x, &b2.x) == 0; - ret &= secp256k1_fe_cmp_var(&a2.y, &b2.y) == 0; - ret &= secp256k1_fe_cmp_var(&a2.z, &b2.z) == 0; - } - return ret; -} - -void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { - secp256k1_fe z2s; - secp256k1_fe u1, u2, s1, s2; - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ - secp256k1_fe_sqr(&z2s, &b->z); - secp256k1_fe_mul(&u1, &a->x, &z2s); - u2 = b->x; secp256k1_fe_normalize_weak(&u2); - secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); - s2 = b->y; secp256k1_fe_normalize_weak(&s2); - CHECK(secp256k1_fe_equal_var(&u1, &u2)); - CHECK(secp256k1_fe_equal_var(&s1, &s2)); -} - -void test_ge(void) { - int i, i1; -#ifdef USE_ENDOMORPHISM - int runs = 6; -#else - int runs = 4; -#endif - /* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4). - * The second in each pair of identical points uses a random Z coordinate in the Jacobian form. - * All magnitudes are randomized. - * All 17*17 combinations of points are added to each other, using all applicable methods. - * - * When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well. - */ - secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs)); - secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs)); - secp256k1_fe *zinv = (secp256k1_fe *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs)); - secp256k1_fe zf; - secp256k1_fe zfi2, zfi3; - - secp256k1_gej_set_infinity(&gej[0]); - secp256k1_ge_clear(&ge[0]); - secp256k1_ge_set_gej_var(&ge[0], &gej[0]); - for (i = 0; i < runs; i++) { - int j; - secp256k1_ge g; - random_group_element_test(&g); -#ifdef USE_ENDOMORPHISM - if (i >= runs - 2) { - secp256k1_ge_mul_lambda(&g, &ge[1]); - } - if (i >= runs - 1) { - secp256k1_ge_mul_lambda(&g, &g); - } -#endif - ge[1 + 4 * i] = g; - ge[2 + 4 * i] = g; - secp256k1_ge_neg(&ge[3 + 4 * i], &g); - secp256k1_ge_neg(&ge[4 + 4 * i], &g); - secp256k1_gej_set_ge(&gej[1 + 4 * i], &ge[1 + 4 * i]); - random_group_element_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); - secp256k1_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]); - random_group_element_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); - for (j = 0; j < 4; j++) { - random_field_element_magnitude(&ge[1 + j + 4 * i].x); - random_field_element_magnitude(&ge[1 + j + 4 * i].y); - random_field_element_magnitude(&gej[1 + j + 4 * i].x); - random_field_element_magnitude(&gej[1 + j + 4 * i].y); - random_field_element_magnitude(&gej[1 + j + 4 * i].z); - } - } - - /* Compute z inverses. */ - { - secp256k1_fe *zs = checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs)); - for (i = 0; i < 4 * runs + 1; i++) { - if (i == 0) { - /* The point at infinity does not have a meaningful z inverse. Any should do. */ - do { - random_field_element_test(&zs[i]); - } while(secp256k1_fe_is_zero(&zs[i])); - } else { - zs[i] = gej[i].z; - } - } - secp256k1_fe_inv_all_var(zinv, zs, 4 * runs + 1); - free(zs); - } - - /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */ - do { - random_field_element_test(&zf); - } while(secp256k1_fe_is_zero(&zf)); - random_field_element_magnitude(&zf); - secp256k1_fe_inv_var(&zfi3, &zf); - secp256k1_fe_sqr(&zfi2, &zfi3); - secp256k1_fe_mul(&zfi3, &zfi3, &zfi2); - - for (i1 = 0; i1 < 1 + 4 * runs; i1++) { - int i2; - for (i2 = 0; i2 < 1 + 4 * runs; i2++) { - /* Compute reference result using gej + gej (var). */ - secp256k1_gej refj, resj; - secp256k1_ge ref; - secp256k1_fe zr; - secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); - /* Check Z ratio. */ - if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&refj)) { - secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); - CHECK(secp256k1_fe_equal_var(&zrz, &refj.z)); - } - secp256k1_ge_set_gej_var(&ref, &refj); - - /* Test gej + ge with Z ratio result (var). */ - secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); - ge_equals_gej(&ref, &resj); - if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&resj)) { - secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); - CHECK(secp256k1_fe_equal_var(&zrz, &resj.z)); - } - - /* Test gej + ge (var, with additional Z factor). */ - { - secp256k1_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */ - secp256k1_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2); - secp256k1_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3); - random_field_element_magnitude(&ge2_zfi.x); - random_field_element_magnitude(&ge2_zfi.y); - secp256k1_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf); - ge_equals_gej(&ref, &resj); - } - - /* Test gej + ge (const). */ - if (i2 != 0) { - /* secp256k1_gej_add_ge does not support its second argument being infinity. */ - secp256k1_gej_add_ge(&resj, &gej[i1], &ge[i2]); - ge_equals_gej(&ref, &resj); - } - - /* Test doubling (var). */ - if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) { - secp256k1_fe zr2; - /* Normal doubling with Z ratio result. */ - secp256k1_gej_double_var(&resj, &gej[i1], &zr2); - ge_equals_gej(&ref, &resj); - /* Check Z ratio. */ - secp256k1_fe_mul(&zr2, &zr2, &gej[i1].z); - CHECK(secp256k1_fe_equal_var(&zr2, &resj.z)); - /* Normal doubling. */ - secp256k1_gej_double_var(&resj, &gej[i2], NULL); - ge_equals_gej(&ref, &resj); - } - - /* Test adding opposites. */ - if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 != ((i2 + 3)%4)/2)) { - CHECK(secp256k1_ge_is_infinity(&ref)); - } - - /* Test adding infinity. */ - if (i1 == 0) { - CHECK(secp256k1_ge_is_infinity(&ge[i1])); - CHECK(secp256k1_gej_is_infinity(&gej[i1])); - ge_equals_gej(&ref, &gej[i2]); - } - if (i2 == 0) { - CHECK(secp256k1_ge_is_infinity(&ge[i2])); - CHECK(secp256k1_gej_is_infinity(&gej[i2])); - ge_equals_gej(&ref, &gej[i1]); - } - } - } - - /* Test adding all points together in random order equals infinity. */ - { - secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY; - secp256k1_gej *gej_shuffled = (secp256k1_gej *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej)); - for (i = 0; i < 4 * runs + 1; i++) { - gej_shuffled[i] = gej[i]; - } - for (i = 0; i < 4 * runs + 1; i++) { - int swap = i + secp256k1_rand_int(4 * runs + 1 - i); - if (swap != i) { - secp256k1_gej t = gej_shuffled[i]; - gej_shuffled[i] = gej_shuffled[swap]; - gej_shuffled[swap] = t; - } - } - for (i = 0; i < 4 * runs + 1; i++) { - secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i], NULL); - } - CHECK(secp256k1_gej_is_infinity(&sum)); - free(gej_shuffled); - } - - /* Test batch gej -> ge conversion with and without known z ratios. */ - { - secp256k1_fe *zr = (secp256k1_fe *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_fe)); - secp256k1_ge *ge_set_table = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); - secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); - for (i = 0; i < 4 * runs + 1; i++) { - /* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */ - if (i < 4 * runs) { - secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z); - } - } - secp256k1_ge_set_table_gej_var(ge_set_table, gej, zr, 4 * runs + 1); - secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1, &ctx->error_callback); - for (i = 0; i < 4 * runs + 1; i++) { - secp256k1_fe s; - random_fe_non_zero(&s); - secp256k1_gej_rescale(&gej[i], &s); - ge_equals_gej(&ge_set_table[i], &gej[i]); - ge_equals_gej(&ge_set_all[i], &gej[i]); - } - free(ge_set_table); - free(ge_set_all); - free(zr); - } - - free(ge); - free(gej); - free(zinv); -} - -void test_add_neg_y_diff_x(void) { - /* The point of this test is to check that we can add two points - * whose y-coordinates are negatives of each other but whose x - * coordinates differ. If the x-coordinates were the same, these - * points would be negatives of each other and their sum is - * infinity. This is cool because it "covers up" any degeneracy - * in the addition algorithm that would cause the xy coordinates - * 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-core/secp256k1/issues/257 - * which this test is a regression test for. - * - * These points were generated in sage as - * # secp256k1 params - * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) - * C = EllipticCurve ([F (0), F (7)]) - * G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) - * N = FiniteField(G.order()) - * - * # endomorphism values (lambda is 1^{1/3} in N, beta is 1^{1/3} in F) - * x = polygen(N) - * lam = (1 - x^3).roots()[1][0] - * - * # random "bad pair" - * P = C.random_element() - * Q = -int(lam) * P - * print " P: %x %x" % P.xy() - * print " Q: %x %x" % Q.xy() - * print "P + Q: %x %x" % (P + Q).xy() - */ - secp256k1_gej aj = SECP256K1_GEJ_CONST( - 0x8d24cd95, 0x0a355af1, 0x3c543505, 0x44238d30, - 0x0643d79f, 0x05a59614, 0x2f8ec030, 0xd58977cb, - 0x001e337a, 0x38093dcd, 0x6c0f386d, 0x0b1293a8, - 0x4d72c879, 0xd7681924, 0x44e6d2f3, 0x9190117d - ); - secp256k1_gej bj = SECP256K1_GEJ_CONST( - 0xc7b74206, 0x1f788cd9, 0xabd0937d, 0x164a0d86, - 0x95f6ff75, 0xf19a4ce9, 0xd013bd7b, 0xbf92d2a7, - 0xffe1cc85, 0xc7f6c232, 0x93f0c792, 0xf4ed6c57, - 0xb28d3786, 0x2897e6db, 0xbb192d0b, 0x6e6feab2 - ); - secp256k1_gej sumj = SECP256K1_GEJ_CONST( - 0x671a63c0, 0x3efdad4c, 0x389a7798, 0x24356027, - 0xb3d69010, 0x278625c3, 0x5c86d390, 0x184a8f7a, - 0x5f6409c2, 0x2ce01f2b, 0x511fd375, 0x25071d08, - 0xda651801, 0x70e95caf, 0x8f0d893c, 0xbed8fbbe - ); - secp256k1_ge b; - secp256k1_gej resj; - secp256k1_ge res; - secp256k1_ge_set_gej(&b, &bj); - - secp256k1_gej_add_var(&resj, &aj, &bj, NULL); - secp256k1_ge_set_gej(&res, &resj); - ge_equals_gej(&res, &sumj); - - secp256k1_gej_add_ge(&resj, &aj, &b); - secp256k1_ge_set_gej(&res, &resj); - ge_equals_gej(&res, &sumj); - - secp256k1_gej_add_ge_var(&resj, &aj, &b, NULL); - secp256k1_ge_set_gej(&res, &resj); - ge_equals_gej(&res, &sumj); -} - -void run_ge(void) { - int i; - for (i = 0; i < count * 32; i++) { - test_ge(); - } - test_add_neg_y_diff_x(); -} - -void test_ec_combine(void) { - secp256k1_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - secp256k1_pubkey data[6]; - const secp256k1_pubkey* d[6]; - secp256k1_pubkey sd; - secp256k1_pubkey sd2; - secp256k1_gej Qj; - secp256k1_ge Q; - int i; - for (i = 1; i <= 6; i++) { - secp256k1_scalar s; - random_scalar_order_test(&s); - secp256k1_scalar_add(&sum, &sum, &s); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &s); - secp256k1_ge_set_gej(&Q, &Qj); - secp256k1_pubkey_save(&data[i - 1], &Q); - d[i - 1] = &data[i - 1]; - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sum); - secp256k1_ge_set_gej(&Q, &Qj); - secp256k1_pubkey_save(&sd, &Q); - CHECK(secp256k1_ec_pubkey_combine(ctx, &sd2, d, i) == 1); - CHECK(memcmp(&sd, &sd2, sizeof(sd)) == 0); - } -} - -void run_ec_combine(void) { - int i; - for (i = 0; i < count * 8; i++) { - test_ec_combine(); - } -} - -void test_group_decompress(const secp256k1_fe* x) { - /* The input itself, normalized. */ - secp256k1_fe fex = *x; - 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(&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); - - CHECK(res_quad == res_even); - CHECK(res_quad == res_odd); - - if (res_quad) { - secp256k1_fe_normalize_var(&ge_quad.x); - secp256k1_fe_normalize_var(&ge_odd.x); - secp256k1_fe_normalize_var(&ge_even.x); - secp256k1_fe_normalize_var(&ge_quad.y); - secp256k1_fe_normalize_var(&ge_odd.y); - secp256k1_fe_normalize_var(&ge_even.y); - - /* No infinity allowed. */ - CHECK(!ge_quad.infinity); - CHECK(!ge_even.infinity); - CHECK(!ge_odd.infinity); - - /* Check that the x coordinates check out. */ - CHECK(secp256k1_fe_equal_var(&ge_quad.x, x)); - CHECK(secp256k1_fe_equal_var(&ge_even.x, 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_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)); - } -} - -void run_group_decompress(void) { - int i; - for (i = 0; i < count * 4; i++) { - secp256k1_fe fe; - random_fe_test(&fe); - test_group_decompress(&fe); - } -} - -/***** ECMULT TESTS *****/ - -void run_ecmult_chain(void) { - /* random starting point A (on the curve) */ - secp256k1_gej a = SECP256K1_GEJ_CONST( - 0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3, - 0x727fd8bc, 0x04d3362c, 0x6c7bf458, 0xe2846004, - 0xa357ae91, 0x5c4a6528, 0x1309edf2, 0x0504740f, - 0x0eb33439, 0x90216b4f, 0x81063cb6, 0x5f2f7e0f - ); - /* two random initial factors xn and gn */ - secp256k1_scalar xn = SECP256K1_SCALAR_CONST( - 0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c, - 0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407 - ); - secp256k1_scalar gn = SECP256K1_SCALAR_CONST( - 0xa1e58d22, 0x553dcd42, 0xb2398062, 0x5d4c57a9, - 0x6e9323d4, 0x2b3152e5, 0xca2c3990, 0xedc7c9de - ); - /* two small multipliers to be applied to xn and gn in every iteration: */ - static const secp256k1_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); - static const secp256k1_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); - /* accumulators with the resulting coefficients to A and G */ - secp256k1_scalar ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_scalar ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - /* actual points */ - secp256k1_gej x; - secp256k1_gej x2; - int i; - - /* the point being computed */ - x = a; - for (i = 0; i < 200*count; i++) { - /* in each iteration, compute X = xn*X + gn*G; */ - secp256k1_ecmult(&ctx->ecmult_ctx, &x, &x, &xn, &gn); - /* also compute ae and ge: the actual accumulated factors for A and G */ - /* if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) */ - secp256k1_scalar_mul(&ae, &ae, &xn); - secp256k1_scalar_mul(&ge, &ge, &xn); - secp256k1_scalar_add(&ge, &ge, &gn); - /* modify xn and gn */ - secp256k1_scalar_mul(&xn, &xn, &xf); - secp256k1_scalar_mul(&gn, &gn, &gf); - - /* verify */ - if (i == 19999) { - /* expected result after 19999 iterations */ - secp256k1_gej rp = SECP256K1_GEJ_CONST( - 0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE, - 0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830, - 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D, - 0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88 - ); - - secp256k1_gej_neg(&rp, &rp); - secp256k1_gej_add_var(&rp, &rp, &x, NULL); - CHECK(secp256k1_gej_is_infinity(&rp)); - } - } - /* redo the computation, but directly with the resulting ae and ge coefficients: */ - secp256k1_ecmult(&ctx->ecmult_ctx, &x2, &a, &ae, &ge); - secp256k1_gej_neg(&x2, &x2); - secp256k1_gej_add_var(&x2, &x2, &x, NULL); - CHECK(secp256k1_gej_is_infinity(&x2)); -} - -void test_point_times_order(const secp256k1_gej *point) { - /* X * (point + G) + (order-X) * (pointer + G) = 0 */ - secp256k1_scalar x; - secp256k1_scalar nx; - secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_gej res1, res2; - secp256k1_ge res3; - unsigned char pub[65]; - size_t psize = 65; - random_scalar_order_test(&x); - secp256k1_scalar_negate(&nx, &x); - secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &x, &x); /* calc res1 = x * point + x * G; */ - secp256k1_ecmult(&ctx->ecmult_ctx, &res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ - secp256k1_gej_add_var(&res1, &res1, &res2, NULL); - CHECK(secp256k1_gej_is_infinity(&res1)); - CHECK(secp256k1_gej_is_valid_var(&res1) == 0); - secp256k1_ge_set_gej(&res3, &res1); - CHECK(secp256k1_ge_is_infinity(&res3)); - CHECK(secp256k1_ge_is_valid_var(&res3) == 0); - CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0); - psize = 65; - CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); - /* check zero/one edge cases */ - secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &zero); - secp256k1_ge_set_gej(&res3, &res1); - CHECK(secp256k1_ge_is_infinity(&res3)); - secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &one, &zero); - secp256k1_ge_set_gej(&res3, &res1); - ge_equals_gej(&res3, point); - secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &one); - secp256k1_ge_set_gej(&res3, &res1); - ge_equals_ge(&res3, &secp256k1_ge_const_g); -} - -void run_point_times_order(void) { - int i; - secp256k1_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); - static const secp256k1_fe xr = SECP256K1_FE_CONST( - 0x7603CB59, 0xB0EF6C63, 0xFE608479, 0x2A0C378C, - 0xDB3233A8, 0x0F8A9A09, 0xA877DEAD, 0x31B38C45 - ); - for (i = 0; i < 500; i++) { - secp256k1_ge p; - if (secp256k1_ge_set_xo_var(&p, &x, 1)) { - secp256k1_gej j; - CHECK(secp256k1_ge_is_valid_var(&p)); - secp256k1_gej_set_ge(&j, &p); - CHECK(secp256k1_gej_is_valid_var(&j)); - test_point_times_order(&j); - } - secp256k1_fe_sqr(&x, &x); - } - secp256k1_fe_normalize_var(&x); - CHECK(secp256k1_fe_equal_var(&x, &xr)); -} - -void ecmult_const_random_mult(void) { - /* random starting point A (on the curve) */ - secp256k1_ge a = SECP256K1_GE_CONST( - 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b, - 0xa97f9263, 0xb1e88044, 0x93351325, 0x91bc450a, - 0x535c59f7, 0x325e5d2b, 0xc391fbe8, 0x3c12787c, - 0x337e4a98, 0xe82a9011, 0x0123ba37, 0xdd769c7d - ); - /* random initial factor xn */ - secp256k1_scalar xn = SECP256K1_SCALAR_CONST( - 0x649d4f77, 0xc4242df7, 0x7f2079c9, 0x14530327, - 0xa31b876a, 0xd2d8ce2a, 0x2236d5c6, 0xd7b2029b - ); - /* expected xn * A (from sage) */ - secp256k1_ge expected_b = SECP256K1_GE_CONST( - 0x23773684, 0x4d209dc7, 0x098a786f, 0x20d06fcd, - 0x070a38bf, 0xc11ac651, 0x03004319, 0x1e2a8786, - 0xed8c3b8e, 0xc06dd57b, 0xd06ea66e, 0x45492b0f, - 0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956 - ); - secp256k1_gej b; - secp256k1_ecmult_const(&b, &a, &xn); - - CHECK(secp256k1_ge_is_valid_var(&a)); - ge_equals_gej(&expected_b, &b); -} - -void ecmult_const_commutativity(void) { - secp256k1_scalar a; - secp256k1_scalar b; - secp256k1_gej res1; - secp256k1_gej res2; - secp256k1_ge mid1; - secp256k1_ge mid2; - random_scalar_order_test(&a); - random_scalar_order_test(&b); - - secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a); - secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b); - secp256k1_ge_set_gej(&mid1, &res1); - secp256k1_ge_set_gej(&mid2, &res2); - secp256k1_ecmult_const(&res1, &mid1, &b); - secp256k1_ecmult_const(&res2, &mid2, &a); - secp256k1_ge_set_gej(&mid1, &res1); - secp256k1_ge_set_gej(&mid2, &res2); - ge_equals_ge(&mid1, &mid2); -} - -void ecmult_const_mult_zero_one(void) { - secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_scalar negone; - secp256k1_gej res1; - secp256k1_ge res2; - secp256k1_ge point; - secp256k1_scalar_negate(&negone, &one); - - random_group_element_test(&point); - secp256k1_ecmult_const(&res1, &point, &zero); - secp256k1_ge_set_gej(&res2, &res1); - CHECK(secp256k1_ge_is_infinity(&res2)); - secp256k1_ecmult_const(&res1, &point, &one); - secp256k1_ge_set_gej(&res2, &res1); - ge_equals_ge(&res2, &point); - secp256k1_ecmult_const(&res1, &point, &negone); - secp256k1_gej_neg(&res1, &res1); - secp256k1_ge_set_gej(&res2, &res1); - ge_equals_ge(&res2, &point); -} - -void ecmult_const_chain_multiply(void) { - /* Check known result (randomly generated test problem from sage) */ - const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST( - 0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d, - 0xcd83d307, 0x827bed62, 0x05fad0ce, 0x18fae63b - ); - const secp256k1_gej expected_point = SECP256K1_GEJ_CONST( - 0x5494c15d, 0x32099706, 0xc2395f94, 0x348745fd, - 0x757ce30e, 0x4e8c90fb, 0xa2bad184, 0xf883c69f, - 0x5d195d20, 0xe191bf7f, 0x1be3e55f, 0x56a80196, - 0x6071ad01, 0xf1462f66, 0xc997fa94, 0xdb858435 - ); - secp256k1_gej point; - secp256k1_ge res; - int i; - - secp256k1_gej_set_ge(&point, &secp256k1_ge_const_g); - for (i = 0; i < 100; ++i) { - secp256k1_ge tmp; - secp256k1_ge_set_gej(&tmp, &point); - secp256k1_ecmult_const(&point, &tmp, &scalar); - } - secp256k1_ge_set_gej(&res, &point); - ge_equals_gej(&res, &expected_point); -} - -void run_ecmult_const_tests(void) { - ecmult_const_mult_zero_one(); - ecmult_const_random_mult(); - ecmult_const_commutativity(); - ecmult_const_chain_multiply(); -} - -void test_wnaf(const secp256k1_scalar *number, int w) { - secp256k1_scalar x, two, t; - int wnaf[256]; - int zeroes = -1; - int i; - int bits; - secp256k1_scalar_set_int(&x, 0); - secp256k1_scalar_set_int(&two, 2); - bits = secp256k1_ecmult_wnaf(wnaf, 256, number, w); - CHECK(bits <= 256); - for (i = bits-1; i >= 0; i--) { - int v = wnaf[i]; - secp256k1_scalar_mul(&x, &x, &two); - if (v) { - CHECK(zeroes == -1 || zeroes >= w-1); /* check that distance between non-zero elements is at least w-1 */ - zeroes=0; - CHECK((v & 1) == 1); /* check non-zero elements are odd */ - CHECK(v <= (1 << (w-1)) - 1); /* check range below */ - CHECK(v >= -(1 << (w-1)) - 1); /* check range above */ - } else { - CHECK(zeroes != -1); /* check that no unnecessary zero padding exists */ - zeroes++; - } - if (v >= 0) { - secp256k1_scalar_set_int(&t, v); - } else { - secp256k1_scalar_set_int(&t, -v); - secp256k1_scalar_negate(&t, &t); - } - secp256k1_scalar_add(&x, &x, &t); - } - CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */ -} - -void test_constant_wnaf_negate(const secp256k1_scalar *number) { - secp256k1_scalar neg1 = *number; - secp256k1_scalar neg2 = *number; - int sign1 = 1; - int sign2 = 1; - - if (!secp256k1_scalar_get_bits(&neg1, 0, 1)) { - secp256k1_scalar_negate(&neg1, &neg1); - sign1 = -1; - } - sign2 = secp256k1_scalar_cond_negate(&neg2, secp256k1_scalar_is_even(&neg2)); - CHECK(sign1 == sign2); - CHECK(secp256k1_scalar_eq(&neg1, &neg2)); -} - -void test_constant_wnaf(const secp256k1_scalar *number, int w) { - secp256k1_scalar x, shift; - int wnaf[256] = {0}; - int i; - int skew; - secp256k1_scalar num = *number; - - secp256k1_scalar_set_int(&x, 0); - secp256k1_scalar_set_int(&shift, 1 << w); - /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */ -#ifdef USE_ENDOMORPHISM - for (i = 0; i < 16; ++i) { - secp256k1_scalar_shr_int(&num, 8); - } -#endif - skew = secp256k1_wnaf_const(wnaf, num, w); - - for (i = WNAF_SIZE(w); i >= 0; --i) { - secp256k1_scalar t; - int v = wnaf[i]; - CHECK(v != 0); /* check nonzero */ - CHECK(v & 1); /* check parity */ - CHECK(v > -(1 << w)); /* check range above */ - CHECK(v < (1 << w)); /* check range below */ - - secp256k1_scalar_mul(&x, &x, &shift); - if (v >= 0) { - secp256k1_scalar_set_int(&t, v); - } else { - secp256k1_scalar_set_int(&t, -v); - secp256k1_scalar_negate(&t, &t); - } - secp256k1_scalar_add(&x, &x, &t); - } - /* Skew num because when encoding numbers as odd we use an offset */ - secp256k1_scalar_cadd_bit(&num, skew == 2, 1); - CHECK(secp256k1_scalar_eq(&x, &num)); -} - -void run_wnaf(void) { - int i; - secp256k1_scalar n = {{0}}; - - /* Sanity check: 1 and 2 are the smallest odd and even numbers and should - * have easier-to-diagnose failure modes */ - n.d[0] = 1; - test_constant_wnaf(&n, 4); - n.d[0] = 2; - test_constant_wnaf(&n, 4); - /* Random tests */ - for (i = 0; i < count; i++) { - random_scalar_order(&n); - test_wnaf(&n, 4+(i%10)); - test_constant_wnaf_negate(&n); - test_constant_wnaf(&n, 4 + (i % 10)); - } - secp256k1_scalar_set_int(&n, 0); - CHECK(secp256k1_scalar_cond_negate(&n, 1) == -1); - CHECK(secp256k1_scalar_is_zero(&n)); - CHECK(secp256k1_scalar_cond_negate(&n, 0) == 1); - CHECK(secp256k1_scalar_is_zero(&n)); -} - -void test_ecmult_constants(void) { - /* Test ecmult_gen() for [0..36) and [order-36..0). */ - secp256k1_scalar x; - secp256k1_gej r; - secp256k1_ge ng; - int i; - int j; - secp256k1_ge_neg(&ng, &secp256k1_ge_const_g); - for (i = 0; i < 36; i++ ) { - secp256k1_scalar_set_int(&x, i); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x); - for (j = 0; j < i; j++) { - if (j == i - 1) { - ge_equals_gej(&secp256k1_ge_const_g, &r); - } - secp256k1_gej_add_ge(&r, &r, &ng); - } - CHECK(secp256k1_gej_is_infinity(&r)); - } - for (i = 1; i <= 36; i++ ) { - secp256k1_scalar_set_int(&x, i); - secp256k1_scalar_negate(&x, &x); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x); - for (j = 0; j < i; j++) { - if (j == i - 1) { - ge_equals_gej(&ng, &r); - } - secp256k1_gej_add_ge(&r, &r, &secp256k1_ge_const_g); - } - CHECK(secp256k1_gej_is_infinity(&r)); - } -} - -void run_ecmult_constants(void) { - test_ecmult_constants(); -} - -void test_ecmult_gen_blind(void) { - /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ - secp256k1_scalar key; - secp256k1_scalar b; - unsigned char seed32[32]; - secp256k1_gej pgej; - secp256k1_gej pgej2; - secp256k1_gej i; - secp256k1_ge pge; - random_scalar_order_test(&key); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key); - secp256k1_rand256(seed32); - b = ctx->ecmult_gen_ctx.blind; - i = ctx->ecmult_gen_ctx.initial; - secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); - CHECK(!secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej2, &key); - CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); - CHECK(!gej_xyz_equals_gej(&i, &ctx->ecmult_gen_ctx.initial)); - secp256k1_ge_set_gej(&pge, &pgej); - ge_equals_gej(&pge, &pgej2); -} - -void test_ecmult_gen_blind_reset(void) { - /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ - secp256k1_scalar b; - secp256k1_gej initial; - secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); - b = ctx->ecmult_gen_ctx.blind; - initial = ctx->ecmult_gen_ctx.initial; - secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); - CHECK(secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); - CHECK(gej_xyz_equals_gej(&initial, &ctx->ecmult_gen_ctx.initial)); -} - -void run_ecmult_gen_blind(void) { - int i; - test_ecmult_gen_blind_reset(); - for (i = 0; i < 10; i++) { - test_ecmult_gen_blind(); - } -} - -#ifdef USE_ENDOMORPHISM -/***** ENDOMORPHISH TESTS *****/ -void test_scalar_split(void) { - secp256k1_scalar full; - secp256k1_scalar s1, slam; - const unsigned char zero[32] = {0}; - unsigned char tmp[32]; - - random_scalar_order_test(&full); - secp256k1_scalar_split_lambda(&s1, &slam, &full); - - /* check that both are <= 128 bits in size */ - if (secp256k1_scalar_is_high(&s1)) { - secp256k1_scalar_negate(&s1, &s1); - } - if (secp256k1_scalar_is_high(&slam)) { - secp256k1_scalar_negate(&slam, &slam); - } - - secp256k1_scalar_get_b32(tmp, &s1); - CHECK(memcmp(zero, tmp, 16) == 0); - secp256k1_scalar_get_b32(tmp, &slam); - CHECK(memcmp(zero, tmp, 16) == 0); -} - -void run_endomorphism_tests(void) { - test_scalar_split(); -} -#endif - -void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { - unsigned char pubkeyc[65]; - secp256k1_pubkey pubkey; - secp256k1_ge ge; - size_t pubkeyclen; - int32_t ecount; - ecount = 0; - secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); - for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) { - /* Smaller sizes are tested exhaustively elsewhere. */ - int32_t i; - memcpy(&pubkeyc[1], input, 64); - VG_UNDEF(&pubkeyc[pubkeyclen], 65 - pubkeyclen); - for (i = 0; i < 256; i++) { - /* Try all type bytes. */ - int xpass; - int ypass; - int ysign; - pubkeyc[0] = i; - /* What sign does this point have? */ - ysign = (input[63] & 1) + 2; - /* For the current type (i) do we expect parsing to work? Handled all of compressed/uncompressed/hybrid. */ - xpass = xvalid && (pubkeyclen == 33) && ((i & 254) == 2); - /* Do we expect a parse and re-serialize as uncompressed to give a matching y? */ - ypass = xvalid && yvalid && ((i & 4) == ((pubkeyclen == 65) << 2)) && - ((i == 4) || ((i & 251) == ysign)) && ((pubkeyclen == 33) || (pubkeyclen == 65)); - if (xpass || ypass) { - /* These cases must parse. */ - unsigned char pubkeyo[65]; - size_t outl; - memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - ecount = 0; - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); - outl = 65; - VG_UNDEF(pubkeyo, 65); - CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - VG_CHECK(pubkeyo, outl); - CHECK(outl == 33); - CHECK(memcmp(&pubkeyo[1], &pubkeyc[1], 32) == 0); - CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0])); - if (ypass) { - /* This test isn't always done because we decode with alternative signs, so the y won't match. */ - CHECK(pubkeyo[0] == ysign); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); - memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - secp256k1_pubkey_save(&pubkey, &ge); - VG_CHECK(&pubkey, sizeof(pubkey)); - outl = 65; - VG_UNDEF(pubkeyo, 65); - CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); - VG_CHECK(pubkeyo, outl); - CHECK(outl == 65); - CHECK(pubkeyo[0] == 4); - CHECK(memcmp(&pubkeyo[1], input, 64) == 0); - } - CHECK(ecount == 0); - } else { - /* These cases must fail to parse. */ - memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); - } - } - } - secp256k1_context_set_illegal_callback(ctx, NULL, NULL); -} - -void run_ec_pubkey_parse_test(void) { -#define SECP256K1_EC_PARSE_TEST_NVALID (12) - const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = { - { - /* Point with leading and trailing zeros in x and y serialization. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x52, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x64, 0xef, 0xa1, 0x7b, 0x77, 0x61, 0xe1, 0xe4, 0x27, 0x06, 0x98, 0x9f, 0xb4, 0x83, - 0xb8, 0xd2, 0xd4, 0x9b, 0xf7, 0x8f, 0xae, 0x98, 0x03, 0xf0, 0x99, 0xb8, 0x34, 0xed, 0xeb, 0x00 - }, - { - /* Point with x equal to a 3rd root of unity.*/ - 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10, 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9, - 0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95, 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee, - 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, - 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, - }, - { - /* Point with largest x. (1/2) */ - 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, 0x2c, - 0x0e, 0x99, 0x4b, 0x14, 0xea, 0x72, 0xf8, 0xc3, 0xeb, 0x95, 0xc7, 0x1e, 0xf6, 0x92, 0x57, 0x5e, - 0x77, 0x50, 0x58, 0x33, 0x2d, 0x7e, 0x52, 0xd0, 0x99, 0x5c, 0xf8, 0x03, 0x88, 0x71, 0xb6, 0x7d, - }, - { - /* Point with largest x. (2/2) */ - 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, 0x2c, - 0xf1, 0x66, 0xb4, 0xeb, 0x15, 0x8d, 0x07, 0x3c, 0x14, 0x6a, 0x38, 0xe1, 0x09, 0x6d, 0xa8, 0xa1, - 0x88, 0xaf, 0xa7, 0xcc, 0xd2, 0x81, 0xad, 0x2f, 0x66, 0xa3, 0x07, 0xfb, 0x77, 0x8e, 0x45, 0xb2, - }, - { - /* Point with smallest x. (1/2) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, - 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, - }, - { - /* Point with smallest x. (2/2) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, - 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, - }, - { - /* Point with largest y. (1/3) */ - 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, - 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, - 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, 0x2e, - }, - { - /* Point with largest y. (2/3) */ - 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, - 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, - 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, 0x2e, - }, - { - /* Point with largest y. (3/3) */ - 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, - 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, - 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, 0x2e, - }, - { - /* Point with smallest y. (1/3) */ - 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, - 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }, - { - /* Point with smallest y. (2/3) */ - 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, - 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }, - { - /* Point with smallest y. (3/3) */ - 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, - 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 - } - }; -#define SECP256K1_EC_PARSE_TEST_NXVALID (4) - const unsigned char onlyxvalid[SECP256K1_EC_PARSE_TEST_NXVALID][64] = { - { - /* Valid if y overflow ignored (y = 1 mod p). (1/3) */ - 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, - 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, - 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, 0x30, - }, - { - /* Valid if y overflow ignored (y = 1 mod p). (2/3) */ - 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, - 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, - 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, 0x30, - }, - { - /* Valid if y overflow ignored (y = 1 mod p). (3/3)*/ - 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, - 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, - 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, 0x30, - }, - { - /* x on curve, y is from y^2 = x^3 + 8. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 - } - }; -#define SECP256K1_EC_PARSE_TEST_NINVALID (7) - const unsigned char invalid[SECP256K1_EC_PARSE_TEST_NINVALID][64] = { - { - /* x is third root of -8, y is -1 * (x^3+7); also on the curve for y^2 = x^3 + 9. */ - 0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, - 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }, - { - /* Valid if x overflow ignored (x = 1 mod p). */ - 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, 0x30, - 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, - 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, - }, - { - /* Valid if x overflow ignored (x = 1 mod p). */ - 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, 0x30, - 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, - 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, - }, - { - /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ - 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, 0x2e, - 0xf4, 0x84, 0x14, 0x5c, 0xb0, 0x14, 0x9b, 0x82, 0x5d, 0xff, 0x41, 0x2f, 0xa0, 0x52, 0xa8, 0x3f, - 0xcb, 0x72, 0xdb, 0x61, 0xd5, 0x6f, 0x37, 0x70, 0xce, 0x06, 0x6b, 0x73, 0x49, 0xa2, 0xaa, 0x28, - }, - { - /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ - 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, 0x2e, - 0x0b, 0x7b, 0xeb, 0xa3, 0x4f, 0xeb, 0x64, 0x7d, 0xa2, 0x00, 0xbe, 0xd0, 0x5f, 0xad, 0x57, 0xc0, - 0x34, 0x8d, 0x24, 0x9e, 0x2a, 0x90, 0xc8, 0x8f, 0x31, 0xf9, 0x94, 0x8b, 0xb6, 0x5d, 0x52, 0x07, - }, - { - /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x8f, 0x53, 0x7e, 0xef, 0xdf, 0xc1, 0x60, 0x6a, 0x07, 0x27, 0xcd, 0x69, 0xb4, 0xa7, 0x33, 0x3d, - 0x38, 0xed, 0x44, 0xe3, 0x93, 0x2a, 0x71, 0x79, 0xee, 0xcb, 0x4b, 0x6f, 0xba, 0x93, 0x60, 0xdc, - }, - { - /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x70, 0xac, 0x81, 0x10, 0x20, 0x3e, 0x9f, 0x95, 0xf8, 0xd8, 0x32, 0x96, 0x4b, 0x58, 0xcc, 0xc2, - 0xc7, 0x12, 0xbb, 0x1c, 0x6c, 0xd5, 0x8e, 0x86, 0x11, 0x34, 0xb4, 0x8f, 0x45, 0x6c, 0x9b, 0x53 - } - }; - const unsigned char pubkeyc[66] = { - /* Serialization of G. */ - 0x04, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, - 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, - 0x98, 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, - 0xA8, 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, - 0xB8, 0x00 - }; - unsigned char sout[65]; - unsigned char shortkey[2]; - secp256k1_ge ge; - secp256k1_pubkey pubkey; - size_t len; - int32_t i; - int32_t ecount; - int32_t ecount2; - ecount = 0; - /* Nothing should be reading this far into pubkeyc. */ - VG_UNDEF(&pubkeyc[65], 1); - secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); - /* Zero length claimed, fail, zeroize, no illegal arg error. */ - memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(shortkey, 2); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 0) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); - /* Length one claimed, fail, zeroize, no illegal arg error. */ - for (i = 0; i < 256 ; i++) { - memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - shortkey[0] = i; - VG_UNDEF(&shortkey[1], 1); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 1) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); - } - /* Length two claimed, fail, zeroize, no illegal arg error. */ - for (i = 0; i < 65536 ; i++) { - memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - shortkey[0] = i & 255; - shortkey[1] = i >> 8; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 2) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); - } - memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */ - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 33) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); - /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */ - CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, pubkeyc, 65) == 0); - CHECK(ecount == 2); - /* NULL input string. Illegal arg and zeroize output. */ - memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, NULL, 65) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 1); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 2); - /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */ - memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 64) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); - /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */ - memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 66) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); - CHECK(ecount == 1); - /* Valid parse. */ - memset(&pubkey, 0, sizeof(pubkey)); - ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - VG_UNDEF(&ge, sizeof(ge)); - CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); - VG_CHECK(&ge.x, sizeof(ge.x)); - VG_CHECK(&ge.y, sizeof(ge.y)); - VG_CHECK(&ge.infinity, sizeof(ge.infinity)); - ge_equals_ge(&secp256k1_ge_const_g, &ge); - CHECK(ecount == 0); - /* secp256k1_ec_pubkey_serialize illegal args. */ - ecount = 0; - len = 65; - CHECK(secp256k1_ec_pubkey_serialize(ctx, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); - CHECK(ecount == 1); - CHECK(len == 0); - CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); - CHECK(ecount == 2); - len = 65; - VG_UNDEF(sout, 65); - CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0); - VG_CHECK(sout, 65); - CHECK(ecount == 3); - CHECK(len == 0); - len = 65; - CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, ~0) == 0); - CHECK(ecount == 4); - CHECK(len == 0); - len = 65; - VG_UNDEF(sout, 65); - CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); - VG_CHECK(sout, 65); - CHECK(ecount == 4); - CHECK(len == 65); - /* Multiple illegal args. Should still set arg error only once. */ - ecount = 0; - ecount2 = 11; - CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); - CHECK(ecount == 1); - /* Does the illegal arg callback actually change the behavior? */ - secp256k1_context_set_illegal_callback(ctx, uncounting_illegal_callback_fn, &ecount2); - CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); - CHECK(ecount == 1); - CHECK(ecount2 == 10); - secp256k1_context_set_illegal_callback(ctx, NULL, NULL); - /* Try a bunch of prefabbed points with all possible encodings. */ - for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) { - ec_pubkey_parse_pointtest(valid[i], 1, 1); - } - for (i = 0; i < SECP256K1_EC_PARSE_TEST_NXVALID; i++) { - ec_pubkey_parse_pointtest(onlyxvalid[i], 1, 0); - } - for (i = 0; i < SECP256K1_EC_PARSE_TEST_NINVALID; i++) { - ec_pubkey_parse_pointtest(invalid[i], 0, 0); - } -} - -void run_eckey_edge_case_test(void) { - const unsigned char orderc[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, 0x41 - }; - const unsigned char zeros[sizeof(secp256k1_pubkey)] = {0x00}; - unsigned char ctmp[33]; - unsigned char ctmp2[33]; - secp256k1_pubkey pubkey; - secp256k1_pubkey pubkey2; - secp256k1_pubkey pubkey_one; - secp256k1_pubkey pubkey_negone; - const secp256k1_pubkey *pubkeys[3]; - size_t len; - int32_t ecount; - /* Group order is too large, reject. */ - CHECK(secp256k1_ec_seckey_verify(ctx, orderc) == 0); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, orderc) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - /* Maximum value is too large, reject. */ - memset(ctmp, 255, 32); - CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); - memset(&pubkey, 1, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - /* Zero is too small, reject. */ - memset(ctmp, 0, 32); - CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); - memset(&pubkey, 1, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - /* One must be accepted. */ - ctmp[31] = 0x01; - CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); - memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - pubkey_one = pubkey; - /* Group order + 1 is too large, reject. */ - memcpy(ctmp, orderc, 32); - ctmp[31] = 0x42; - CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); - memset(&pubkey, 1, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - /* -1 must be accepted. */ - ctmp[31] = 0x40; - CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); - memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - pubkey_negone = pubkey; - /* Tweak of zero leaves the value changed. */ - memset(ctmp2, 0, 32); - CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1); - CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); - memcpy(&pubkey2, &pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); - /* Multiply tweak of zero zeroizes the output. */ - CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0); - CHECK(memcmp(zeros, ctmp, 32) == 0); - CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); - memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - /* Overflowing key tweak zeroizes. */ - memcpy(ctmp, orderc, 32); - ctmp[31] = 0x40; - CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0); - CHECK(memcmp(zeros, ctmp, 32) == 0); - memcpy(ctmp, orderc, 32); - ctmp[31] = 0x40; - CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, orderc) == 0); - CHECK(memcmp(zeros, ctmp, 32) == 0); - memcpy(ctmp, orderc, 32); - ctmp[31] = 0x40; - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); - memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); - memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - /* Private key tweaks results in a key of zero. */ - ctmp2[31] = 1; - CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0); - CHECK(memcmp(zeros, ctmp2, 32) == 0); - ctmp2[31] = 1; - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); - memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - /* Tweak computation wraps and results in a key of 1. */ - ctmp2[31] = 2; - CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 1); - CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); - ctmp2[31] = 2; - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); - ctmp2[31] = 1; - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); - /* Tweak mul * 2 = 1+1. */ - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); - ctmp2[31] = 2; - CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); - /* Test argument errors. */ - ecount = 0; - secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); - CHECK(ecount == 0); - /* Zeroize pubkey on parse error. */ - memset(&pubkey, 0, 32); - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); - memcpy(&pubkey, &pubkey2, sizeof(pubkey)); - memset(&pubkey2, 0, 32); - CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0); - CHECK(ecount == 2); - CHECK(memcmp(&pubkey2, zeros, sizeof(pubkey2)) == 0); - /* Plain argument errors. */ - ecount = 0; - CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ec_seckey_verify(ctx, NULL) == 0); - CHECK(ecount == 1); - ecount = 0; - memset(ctmp2, 0, 32); - ctmp2[31] = 4; - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; - memset(ctmp2, 0, 32); - ctmp2[31] = 4; - CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; - memset(ctmp2, 0, 32); - CHECK(secp256k1_ec_privkey_tweak_add(ctx, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; - memset(ctmp2, 0, 32); - ctmp2[31] = 1; - CHECK(secp256k1_ec_privkey_tweak_mul(ctx, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; - CHECK(secp256k1_ec_pubkey_create(ctx, NULL, ctmp) == 0); - CHECK(ecount == 1); - memset(&pubkey, 1, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); - CHECK(ecount == 2); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - /* secp256k1_ec_pubkey_combine tests. */ - ecount = 0; - pubkeys[0] = &pubkey_one; - VG_UNDEF(&pubkeys[0], sizeof(secp256k1_pubkey *)); - VG_UNDEF(&pubkeys[1], sizeof(secp256k1_pubkey *)); - VG_UNDEF(&pubkeys[2], sizeof(secp256k1_pubkey *)); - memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 0) == 0); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_pubkey_combine(ctx, NULL, pubkeys, 1) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - CHECK(ecount == 2); - memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, NULL, 1) == 0); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - CHECK(ecount == 3); - pubkeys[0] = &pubkey_negone; - memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 1) == 1); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - CHECK(ecount == 3); - len = 33; - CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); - CHECK(memcmp(ctmp, ctmp2, 33) == 0); - /* Result is infinity. */ - pubkeys[0] = &pubkey_one; - pubkeys[1] = &pubkey_negone; - memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 0); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - CHECK(ecount == 3); - /* Passes through infinity but comes out one. */ - pubkeys[2] = &pubkey_one; - memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 3) == 1); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - CHECK(ecount == 3); - len = 33; - CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); - CHECK(memcmp(ctmp, ctmp2, 33) == 0); - /* Adds to two. */ - pubkeys[1] = &pubkey_one; - memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 1); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - CHECK(ecount == 3); - secp256k1_context_set_illegal_callback(ctx, NULL, NULL); -} - -void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { - secp256k1_scalar nonce; - do { - random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); -} - -void test_ecdsa_sign_verify(void) { - secp256k1_gej pubj; - secp256k1_ge pub; - secp256k1_scalar one; - secp256k1_scalar msg, key; - secp256k1_scalar sigr, sigs; - int recid; - int getrec; - random_scalar_order_test(&msg); - random_scalar_order_test(&key); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); - secp256k1_ge_set_gej(&pub, &pubj); - getrec = secp256k1_rand_bits(1); - random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL); - if (getrec) { - CHECK(recid >= 0 && recid < 4); - } - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); - secp256k1_scalar_set_int(&one, 1); - secp256k1_scalar_add(&msg, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); -} - -void run_ecdsa_sign_verify(void) { - int i; - for (i = 0; i < 10*count; i++) { - test_ecdsa_sign_verify(); - } -} - -/** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */ -static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { - (void)msg32; - (void)key32; - (void)algo16; - memcpy(nonce32, data, 32); - return (counter == 0); -} - -static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { - /* Dummy nonce generator that has a fatal error on the first counter value. */ - if (counter == 0) { - return 0; - } - return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 1); -} - -static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { - /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */ - if (counter < 3) { - memset(nonce32, counter==0 ? 0 : 255, 32); - if (counter == 2) { - nonce32[31]--; - } - return 1; - } - if (counter < 5) { - static const unsigned char order[] = { - 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,0x41 - }; - memcpy(nonce32, order, 32); - if (counter == 4) { - nonce32[31]++; - } - return 1; - } - /* Retry rate of 6979 is negligible esp. as we only call this in deterministic tests. */ - /* If someone does fine a case where it retries for secp256k1, we'd like to know. */ - if (counter > 5) { - return 0; - } - return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5); -} - -int is_empty_signature(const secp256k1_ecdsa_signature *sig) { - static const unsigned char res[sizeof(secp256k1_ecdsa_signature)] = {0}; - return memcmp(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0; -} - -void test_ecdsa_end_to_end(void) { - unsigned char extra[32] = {0x00}; - unsigned char privkey[32]; - unsigned char message[32]; - unsigned char privkey2[32]; - secp256k1_ecdsa_signature signature[6]; - secp256k1_scalar r, s; - unsigned char sig[74]; - size_t siglen = 74; - unsigned char pubkeyc[65]; - size_t pubkeyclen = 65; - secp256k1_pubkey pubkey; - secp256k1_pubkey pubkey_tmp; - unsigned char seckey[300]; - size_t seckeylen = 300; - - /* Generate a random key and message. */ - { - secp256k1_scalar msg, key; - random_scalar_order_test(&msg); - random_scalar_order_test(&key); - secp256k1_scalar_get_b32(privkey, &key); - secp256k1_scalar_get_b32(message, &msg); - } - - /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); - - /* Verify exporting and importing public key. */ - CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); - memset(&pubkey, 0, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); - - /* Verify negation changes the key and changes it back */ - memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1); - CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0); - CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1); - CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0); - - /* Verify private key import and export. */ - CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1)); - CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1); - CHECK(memcmp(privkey, privkey2, 32) == 0); - - /* Optionally tweak the keys using addition. */ - if (secp256k1_rand_int(3) == 0) { - int ret1; - int ret2; - unsigned char rnd[32]; - secp256k1_pubkey pubkey2; - secp256k1_rand256_test(rnd); - ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd); - CHECK(ret1 == ret2); - if (ret1 == 0) { - return; - } - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); - } - - /* Optionally tweak the keys using multiplication. */ - if (secp256k1_rand_int(3) == 0) { - int ret1; - int ret2; - unsigned char rnd[32]; - secp256k1_pubkey pubkey2; - secp256k1_rand256_test(rnd); - ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd); - CHECK(ret1 == ret2); - if (ret1 == 0) { - return; - } - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); - } - - /* Sign. */ - CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign(ctx, &signature[4], message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_ecdsa_sign(ctx, &signature[1], message, privkey, NULL, extra) == 1); - extra[31] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, &signature[2], message, privkey, NULL, extra) == 1); - extra[31] = 0; - extra[0] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, &signature[3], message, privkey, NULL, extra) == 1); - CHECK(memcmp(&signature[0], &signature[4], sizeof(signature[0])) == 0); - CHECK(memcmp(&signature[0], &signature[1], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[0], &signature[2], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[0], &signature[3], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[1], &signature[2], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[1], &signature[3], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[2], &signature[3], sizeof(signature[0])) != 0); - /* Verify. */ - CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1); - /* Test lower-S form, malleate, verify and fail, test again, malleate again */ - CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[0])); - secp256k1_ecdsa_signature_load(ctx, &r, &s, &signature[0]); - secp256k1_scalar_negate(&s, &s); - secp256k1_ecdsa_signature_save(&signature[5], &r, &s); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0); - CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); - CHECK(secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); - CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); - CHECK(!secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); - secp256k1_scalar_negate(&s, &s); - secp256k1_ecdsa_signature_save(&signature[5], &r, &s); - CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); - CHECK(memcmp(&signature[5], &signature[0], 64) == 0); - - /* Serialize/parse DER and verify again */ - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); - memset(&signature[0], 0, sizeof(signature[0])); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); - /* Serialize/destroy/parse DER and verify again. */ - siglen = 74; - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); - sig[secp256k1_rand_int(siglen)] += 1 + secp256k1_rand_int(255); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 || - secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0); -} - -void test_random_pubkeys(void) { - secp256k1_ge elem; - secp256k1_ge elem2; - unsigned char in[65]; - /* Generate some randomly sized pubkeys. */ - size_t len = secp256k1_rand_bits(2) == 0 ? 65 : 33; - if (secp256k1_rand_bits(2) == 0) { - len = secp256k1_rand_bits(6); - } - if (len == 65) { - in[0] = secp256k1_rand_bits(1) ? 4 : (secp256k1_rand_bits(1) ? 6 : 7); - } else { - in[0] = secp256k1_rand_bits(1) ? 2 : 3; - } - if (secp256k1_rand_bits(3) == 0) { - in[0] = secp256k1_rand_bits(8); - } - if (len > 1) { - secp256k1_rand256(&in[1]); - } - if (len > 33) { - secp256k1_rand256(&in[33]); - } - if (secp256k1_eckey_pubkey_parse(&elem, in, len)) { - unsigned char out[65]; - unsigned char firstb; - int res; - size_t size = len; - firstb = in[0]; - /* If the pubkey can be parsed, it should round-trip... */ - CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33)); - CHECK(size == len); - CHECK(memcmp(&in[1], &out[1], len-1) == 0); - /* ... except for the type of hybrid inputs. */ - if ((in[0] != 6) && (in[0] != 7)) { - CHECK(in[0] == out[0]); - } - size = 65; - CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0)); - CHECK(size == 65); - CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); - ge_equals_ge(&elem,&elem2); - /* Check that the X9.62 hybrid type is checked. */ - in[0] = secp256k1_rand_bits(1) ? 6 : 7; - res = secp256k1_eckey_pubkey_parse(&elem2, in, size); - if (firstb == 2 || firstb == 3) { - if (in[0] == firstb + 4) { - CHECK(res); - } else { - CHECK(!res); - } - } - if (res) { - ge_equals_ge(&elem,&elem2); - CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0)); - CHECK(memcmp(&in[1], &out[1], 64) == 0); - } - } -} - -void run_random_pubkeys(void) { - int i; - for (i = 0; i < 10*count; i++) { - test_random_pubkeys(); - } -} - -void run_ecdsa_end_to_end(void) { - int i; - for (i = 0; i < 64*count; i++) { - test_ecdsa_end_to_end(); - } -} - -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; - - secp256k1_ecdsa_signature sig_der; - unsigned char roundtrip_der[2048]; - unsigned char compact_der[64]; - size_t len_der = 2048; - int parsed_der = 0, valid_der = 0, roundtrips_der = 0; - - secp256k1_ecdsa_signature sig_der_lax; - unsigned char roundtrip_der_lax[2048]; - unsigned char compact_der_lax[64]; - size_t len_der_lax = 2048; - int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0; - -#ifdef ENABLE_OPENSSL_TESTS - ECDSA_SIG *sig_openssl; - const unsigned char *sigptr; - unsigned char roundtrip_openssl[2048]; - int len_openssl = 2048; - int parsed_openssl, valid_openssl = 0, roundtrips_openssl = 0; -#endif - - parsed_der = secp256k1_ecdsa_signature_parse_der(ctx, &sig_der, sig, siglen); - if (parsed_der) { - ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der, &sig_der)) << 0; - valid_der = (memcmp(compact_der, zeroes, 32) != 0) && (memcmp(compact_der + 32, zeroes, 32) != 0); - } - if (valid_der) { - ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der, &len_der, &sig_der)) << 1; - roundtrips_der = (len_der == siglen) && memcmp(roundtrip_der, sig, siglen) == 0; - } - - parsed_der_lax = ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen); - if (parsed_der_lax) { - ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10; - valid_der_lax = (memcmp(compact_der_lax, zeroes, 32) != 0) && (memcmp(compact_der_lax + 32, zeroes, 32) != 0); - } - if (valid_der_lax) { - ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; - roundtrips_der_lax = (len_der_lax == siglen) && memcmp(roundtrip_der_lax, sig, siglen) == 0; - } - - if (certainly_der) { - ret |= (!parsed_der) << 2; - } - if (certainly_not_der) { - ret |= (parsed_der) << 17; - } - if (valid_der) { - ret |= (!roundtrips_der) << 3; - } - - if (valid_der) { - ret |= (!roundtrips_der_lax) << 12; - ret |= (len_der != len_der_lax) << 13; - ret |= (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0) << 14; - } - ret |= (roundtrips_der != roundtrips_der_lax) << 15; - if (parsed_der) { - ret |= (!parsed_der_lax) << 16; - } - -#ifdef ENABLE_OPENSSL_TESTS - sig_openssl = ECDSA_SIG_new(); - sigptr = sig; - parsed_openssl = (d2i_ECDSA_SIG(&sig_openssl, &sigptr, siglen) != NULL); - if (parsed_openssl) { - valid_openssl = !BN_is_negative(sig_openssl->r) && !BN_is_negative(sig_openssl->s) && BN_num_bits(sig_openssl->r) > 0 && BN_num_bits(sig_openssl->r) <= 256 && BN_num_bits(sig_openssl->s) > 0 && BN_num_bits(sig_openssl->s) <= 256; - if (valid_openssl) { - unsigned char tmp[32] = {0}; - BN_bn2bin(sig_openssl->r, tmp + 32 - BN_num_bytes(sig_openssl->r)); - valid_openssl = memcmp(tmp, max_scalar, 32) < 0; - } - if (valid_openssl) { - unsigned char tmp[32] = {0}; - BN_bn2bin(sig_openssl->s, tmp + 32 - BN_num_bytes(sig_openssl->s)); - valid_openssl = memcmp(tmp, max_scalar, 32) < 0; - } - } - len_openssl = i2d_ECDSA_SIG(sig_openssl, NULL); - if (len_openssl <= 2048) { - unsigned char *ptr = roundtrip_openssl; - CHECK(i2d_ECDSA_SIG(sig_openssl, &ptr) == len_openssl); - roundtrips_openssl = valid_openssl && ((size_t)len_openssl == siglen) && (memcmp(roundtrip_openssl, sig, siglen) == 0); - } else { - len_openssl = 0; - } - ECDSA_SIG_free(sig_openssl); - - ret |= (parsed_der && !parsed_openssl) << 4; - ret |= (valid_der && !valid_openssl) << 5; - ret |= (roundtrips_openssl && !parsed_der) << 6; - ret |= (roundtrips_der != roundtrips_openssl) << 7; - if (roundtrips_openssl) { - ret |= (len_der != (size_t)len_openssl) << 8; - ret |= (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0) << 9; - } -#endif - return ret; -} - -static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) { - size_t i; - for (i = 0; i < ptrlen; i++) { - int shift = ptrlen - 1 - i; - if (shift >= 4) { - ptr[i] = 0; - } else { - ptr[i] = (val >> shift) & 0xFF; - } - } -} - -static void damage_array(unsigned char *sig, size_t *len) { - int pos; - int action = secp256k1_rand_bits(3); - 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 && *len < 2048) { - /* Insert a byte. */ - pos = secp256k1_rand_int(1 + *len); - memmove(sig + pos + 1, sig + pos, *len - pos); - sig[pos] = secp256k1_rand_bits(8); - (*len)++; - return; - } else if (action < 4) { - /* Modify a byte. */ - sig[secp256k1_rand_int(*len)] += 1 + secp256k1_rand_int(255); - return; - } else { /* action < 8 */ - /* Modify a bit. */ - sig[secp256k1_rand_int(*len)] ^= 1 << secp256k1_rand_bits(3); - return; - } -} - -static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly_der, int* certainly_not_der) { - int der; - int nlow[2], nlen[2], nlenlen[2], nhbit[2], nhbyte[2], nzlen[2]; - size_t tlen, elen, glen; - int indet; - int n; - - *len = 0; - der = secp256k1_rand_bits(2) == 0; - *certainly_der = der; - *certainly_not_der = 0; - indet = der ? 0 : secp256k1_rand_int(10) == 0; - - for (n = 0; n < 2; n++) { - /* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */ - nlow[n] = der ? 1 : (secp256k1_rand_bits(3) != 0); - /* The length of the number in bytes (the first byte of which will always be nonzero) */ - nlen[n] = nlow[n] ? secp256k1_rand_int(33) : 32 + secp256k1_rand_int(200) * secp256k1_rand_int(8) / 8; - CHECK(nlen[n] <= 232); - /* The top bit of the number. */ - nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_rand_bits(1)); - /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */ - nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_rand_bits(7) : 1 + secp256k1_rand_int(127)); - /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */ - nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_rand_int(3) : secp256k1_rand_int(300 - nlen[n]) * secp256k1_rand_int(8) / 8); - if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) { - *certainly_not_der = 1; - } - CHECK(nlen[n] + nzlen[n] <= 300); - /* The length of the length descriptor for the number. 0 means short encoding, anything else is long encoding. */ - nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2); - if (!der) { - /* nlenlen[n] max 127 bytes */ - int add = secp256k1_rand_int(127 - nlenlen[n]) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; - nlenlen[n] += add; - if (add != 0) { - *certainly_not_der = 1; - } - } - CHECK(nlen[n] + nzlen[n] + nlenlen[n] <= 427); - } - - /* The total length of the data to go, so far */ - tlen = 2 + nlenlen[0] + nlen[0] + nzlen[0] + 2 + nlenlen[1] + nlen[1] + nzlen[1]; - CHECK(tlen <= 856); - - /* The length of the garbage inside the tuple. */ - elen = (der || indet) ? 0 : secp256k1_rand_int(980 - tlen) * secp256k1_rand_int(8) / 8; - if (elen != 0) { - *certainly_not_der = 1; - } - tlen += elen; - CHECK(tlen <= 980); - - /* The length of the garbage after the end of the tuple. */ - glen = der ? 0 : secp256k1_rand_int(990 - tlen) * secp256k1_rand_int(8) / 8; - if (glen != 0) { - *certainly_not_der = 1; - } - CHECK(tlen + glen <= 990); - - /* Write the tuple header. */ - sig[(*len)++] = 0x30; - if (indet) { - /* Indeterminate length */ - sig[(*len)++] = 0x80; - *certainly_not_der = 1; - } else { - int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2); - if (!der) { - int add = secp256k1_rand_int(127 - tlenlen) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; - tlenlen += add; - if (add != 0) { - *certainly_not_der = 1; - } - } - if (tlenlen == 0) { - /* Short length notation */ - sig[(*len)++] = tlen; - } else { - /* Long length notation */ - sig[(*len)++] = 128 + tlenlen; - assign_big_endian(sig + *len, tlenlen, tlen); - *len += tlenlen; - } - tlen += tlenlen; - } - tlen += 2; - CHECK(tlen + glen <= 1119); - - for (n = 0; n < 2; n++) { - /* Write the integer header. */ - sig[(*len)++] = 0x02; - if (nlenlen[n] == 0) { - /* Short length notation */ - sig[(*len)++] = nlen[n] + nzlen[n]; - } else { - /* Long length notation. */ - sig[(*len)++] = 128 + nlenlen[n]; - assign_big_endian(sig + *len, nlenlen[n], nlen[n] + nzlen[n]); - *len += nlenlen[n]; - } - /* Write zero padding */ - while (nzlen[n] > 0) { - sig[(*len)++] = 0x00; - nzlen[n]--; - } - if (nlen[n] == 32 && !nlow[n]) { - /* Special extra 16 0xFF bytes in "high" 32-byte numbers */ - int i; - for (i = 0; i < 16; i++) { - sig[(*len)++] = 0xFF; - } - nlen[n] -= 16; - } - /* Write first byte of number */ - if (nlen[n] > 0) { - sig[(*len)++] = nhbyte[n]; - nlen[n]--; - } - /* Generate remaining random bytes of number */ - secp256k1_rand_bytes_test(sig + *len, nlen[n]); - *len += nlen[n]; - nlen[n] = 0; - } - - /* Generate random garbage inside tuple. */ - secp256k1_rand_bytes_test(sig + *len, elen); - *len += elen; - - /* Generate end-of-contents bytes. */ - if (indet) { - sig[(*len)++] = 0; - sig[(*len)++] = 0; - tlen += 2; - } - CHECK(tlen + glen <= 1121); - - /* Generate random garbage outside tuple. */ - secp256k1_rand_bytes_test(sig + *len, glen); - *len += glen; - tlen += glen; - CHECK(tlen <= 1121); - CHECK(tlen == *len); -} - -void run_ecdsa_der_parse(void) { - int i,j; - for (i = 0; i < 200 * count; i++) { - unsigned char buffer[2048]; - size_t buflen = 0; - 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) { - damage_array(buffer, &buflen); - /* We don't know anything anymore about the DERness of the result */ - certainly_der = 0; - certainly_not_der = 0; - } - ret = test_ecdsa_der_parse(buffer, buflen, certainly_der, certainly_not_der); - if (ret != 0) { - size_t k; - fprintf(stderr, "Failure %x on ", ret); - for (k = 0; k < buflen; k++) { - fprintf(stderr, "%02x ", buffer[k]); - } - fprintf(stderr, "\n"); - } - CHECK(ret == 0); - } - } -} - -/* Tests several edge cases. */ -void test_ecdsa_edge_cases(void) { - int t; - secp256k1_ecdsa_signature sig; - - /* Test the case where ECDSA recomputes a point that is infinity. */ - { - secp256k1_gej keyj; - secp256k1_ge key; - secp256k1_scalar msg; - secp256k1_scalar sr, ss; - secp256k1_scalar_set_int(&ss, 1); - secp256k1_scalar_negate(&ss, &ss); - secp256k1_scalar_inverse(&ss, &ss); - secp256k1_scalar_set_int(&sr, 1); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr); - secp256k1_ge_set_gej(&key, &keyj); - msg = ss; - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); - } - - /* Verify signature with r of zero fails. */ - { - const unsigned char pubkey_mods_zero[33] = { - 0x02, 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, - 0x41 - }; - secp256k1_ge key; - secp256k1_scalar msg; - secp256k1_scalar sr, ss; - secp256k1_scalar_set_int(&ss, 1); - secp256k1_scalar_set_int(&msg, 0); - secp256k1_scalar_set_int(&sr, 0); - CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey_mods_zero, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); - } - - /* Verify signature with s of zero fails. */ - { - const unsigned char pubkey[33] = { - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01 - }; - secp256k1_ge key; - secp256k1_scalar msg; - secp256k1_scalar sr, ss; - secp256k1_scalar_set_int(&ss, 0); - secp256k1_scalar_set_int(&msg, 0); - secp256k1_scalar_set_int(&sr, 1); - CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); - } - - /* Verify signature with message 0 passes. */ - { - const unsigned char pubkey[33] = { - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02 - }; - const unsigned char pubkey2[33] = { - 0x02, 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, - 0x43 - }; - secp256k1_ge key; - secp256k1_ge key2; - secp256k1_scalar msg; - secp256k1_scalar sr, ss; - secp256k1_scalar_set_int(&ss, 2); - secp256k1_scalar_set_int(&msg, 0); - secp256k1_scalar_set_int(&sr, 2); - CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); - secp256k1_scalar_negate(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); - secp256k1_scalar_set_int(&ss, 1); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); - } - - /* Verify signature with message 1 passes. */ - { - const unsigned char pubkey[33] = { - 0x02, 0x14, 0x4e, 0x5a, 0x58, 0xef, 0x5b, 0x22, - 0x6f, 0xd2, 0xe2, 0x07, 0x6a, 0x77, 0xcf, 0x05, - 0xb4, 0x1d, 0xe7, 0x4a, 0x30, 0x98, 0x27, 0x8c, - 0x93, 0xe6, 0xe6, 0x3c, 0x0b, 0xc4, 0x73, 0x76, - 0x25 - }; - const unsigned char pubkey2[33] = { - 0x02, 0x8a, 0xd5, 0x37, 0xed, 0x73, 0xd9, 0x40, - 0x1d, 0xa0, 0x33, 0xd2, 0xdc, 0xf0, 0xaf, 0xae, - 0x34, 0xcf, 0x5f, 0x96, 0x4c, 0x73, 0x28, 0x0f, - 0x92, 0xc0, 0xf6, 0x9d, 0xd9, 0xb2, 0x09, 0x10, - 0x62 - }; - const unsigned char csr[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, - 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xeb - }; - secp256k1_ge key; - secp256k1_ge key2; - secp256k1_scalar msg; - secp256k1_scalar sr, ss; - secp256k1_scalar_set_int(&ss, 1); - secp256k1_scalar_set_int(&msg, 1); - secp256k1_scalar_set_b32(&sr, csr, NULL); - CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); - secp256k1_scalar_negate(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); - secp256k1_scalar_set_int(&ss, 2); - secp256k1_scalar_inverse_var(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); - } - - /* Verify signature with message -1 passes. */ - { - const unsigned char pubkey[33] = { - 0x03, 0xaf, 0x97, 0xff, 0x7d, 0x3a, 0xf6, 0xa0, - 0x02, 0x94, 0xbd, 0x9f, 0x4b, 0x2e, 0xd7, 0x52, - 0x28, 0xdb, 0x49, 0x2a, 0x65, 0xcb, 0x1e, 0x27, - 0x57, 0x9c, 0xba, 0x74, 0x20, 0xd5, 0x1d, 0x20, - 0xf1 - }; - const unsigned char csr[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, - 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xee - }; - secp256k1_ge key; - secp256k1_scalar msg; - secp256k1_scalar sr, ss; - secp256k1_scalar_set_int(&ss, 1); - secp256k1_scalar_set_int(&msg, 1); - secp256k1_scalar_negate(&msg, &msg); - secp256k1_scalar_set_b32(&sr, csr, NULL); - CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); - secp256k1_scalar_negate(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); - secp256k1_scalar_set_int(&ss, 3); - secp256k1_scalar_inverse_var(&ss, &ss); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); - } - - /* Signature where s would be zero. */ - { - secp256k1_pubkey pubkey; - size_t siglen; - int32_t ecount; - unsigned char signature[72]; - static const unsigned char nonce[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }; - static const unsigned char nonce2[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 - }; - const unsigned char key[32] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - }; - unsigned char msg[32] = { - 0x86, 0x41, 0x99, 0x81, 0x06, 0x23, 0x44, 0x53, - 0xaa, 0x5f, 0x9d, 0x6a, 0x31, 0x78, 0xf4, 0xf7, - 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, - 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, - }; - ecount = 0; - secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); - msg[31] = 0xaa; - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, key) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, NULL, msg, &pubkey) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, NULL, &pubkey) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, NULL) == 0); - CHECK(ecount == 6); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1); - CHECK(ecount == 6); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); - CHECK(ecount == 7); - /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */ - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 0); - CHECK(ecount == 8); - siglen = 72; - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig) == 0); - CHECK(ecount == 9); - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig) == 0); - CHECK(ecount == 10); - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL) == 0); - CHECK(ecount == 11); - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1); - CHECK(ecount == 11); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, NULL, signature, siglen) == 0); - CHECK(ecount == 12); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, NULL, siglen) == 0); - CHECK(ecount == 13); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, signature, siglen) == 1); - CHECK(ecount == 13); - siglen = 10; - /* Too little room for a signature does not fail via ARGCHECK. */ - CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0); - CHECK(ecount == 13); - ecount = 0; - CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, NULL) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, NULL, &sig) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, &sig) == 1); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, NULL, signature) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, NULL) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 1); - CHECK(ecount == 5); - memset(signature, 255, 64); - CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 0); - CHECK(ecount == 5); - secp256k1_context_set_illegal_callback(ctx, NULL, NULL); - } - - /* Nonce function corner cases. */ - for (t = 0; t < 2; t++) { - static const unsigned char zero[32] = {0x00}; - int i; - unsigned char key[32]; - unsigned char msg[32]; - secp256k1_ecdsa_signature sig2; - secp256k1_scalar sr[512], ss; - const unsigned char *extra; - extra = t == 0 ? NULL : zero; - memset(msg, 0, 32); - msg[31] = 1; - /* High key results in signature failure. */ - memset(key, 0xFF, 32); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); - CHECK(is_empty_signature(&sig)); - /* Zero key results in signature failure. */ - memset(key, 0, 32); - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); - CHECK(is_empty_signature(&sig)); - /* Nonce function failure results in signature failure. */ - key[31] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_fail, extra) == 0); - CHECK(is_empty_signature(&sig)); - /* The retry loop successfully makes its way to the first good value. */ - CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_retry, extra) == 1); - CHECK(!is_empty_signature(&sig)); - CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); - CHECK(!is_empty_signature(&sig2)); - CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); - /* The default nonce function is deterministic. */ - CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); - CHECK(!is_empty_signature(&sig2)); - CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); - /* The default nonce function changes output with different messages. */ - for(i = 0; i < 256; i++) { - int j; - msg[0] = i; - CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); - CHECK(!is_empty_signature(&sig2)); - secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); - for (j = 0; j < i; j++) { - CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); - } - } - msg[0] = 0; - msg[31] = 2; - /* The default nonce function changes output with different keys. */ - for(i = 256; i < 512; i++) { - int j; - key[0] = i - 256; - CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); - CHECK(!is_empty_signature(&sig2)); - secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); - for (j = 0; j < i; j++) { - CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); - } - } - key[0] = 0; - } - - { - /* Check that optional nonce arguments do not have equivalent effect. */ - const unsigned char zeros[32] = {0}; - unsigned char nonce[32]; - unsigned char nonce2[32]; - unsigned char nonce3[32]; - unsigned char nonce4[32]; - VG_UNDEF(nonce,32); - VG_UNDEF(nonce2,32); - VG_UNDEF(nonce3,32); - VG_UNDEF(nonce4,32); - CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1); - VG_CHECK(nonce,32); - CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1); - VG_CHECK(nonce2,32); - CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1); - VG_CHECK(nonce3,32); - CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1); - VG_CHECK(nonce4,32); - CHECK(memcmp(nonce, nonce2, 32) != 0); - CHECK(memcmp(nonce, nonce3, 32) != 0); - CHECK(memcmp(nonce, nonce4, 32) != 0); - CHECK(memcmp(nonce2, nonce3, 32) != 0); - CHECK(memcmp(nonce2, nonce4, 32) != 0); - CHECK(memcmp(nonce3, nonce4, 32) != 0); - } - - - /* Privkey export where pubkey is the point at infinity. */ - { - unsigned char privkey[300]; - unsigned char seckey[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, 0x41, - }; - size_t outlen = 300; - CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0)); - outlen = 300; - CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1)); - } -} - -void run_ecdsa_edge_cases(void) { - test_ecdsa_edge_cases(); -} - -#ifdef ENABLE_OPENSSL_TESTS -EC_KEY *get_openssl_key(const unsigned char *key32) { - unsigned char privkey[300]; - size_t privkeylen; - const unsigned char* pbegin = privkey; - int compr = secp256k1_rand_bits(1); - EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); - CHECK(ec_privkey_export_der(ctx, privkey, &privkeylen, key32, compr)); - CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen)); - CHECK(EC_KEY_check_key(ec_key)); - return ec_key; -} - -void test_ecdsa_openssl(void) { - secp256k1_gej qj; - secp256k1_ge q; - secp256k1_scalar sigr, sigs; - secp256k1_scalar one; - secp256k1_scalar msg2; - secp256k1_scalar key, msg; - EC_KEY *ec_key; - unsigned int sigsize = 80; - size_t secp_sigsize = 80; - unsigned char message[32]; - unsigned char signature[80]; - unsigned char key32[32]; - secp256k1_rand256_test(message); - secp256k1_scalar_set_b32(&msg, message, NULL); - random_scalar_order_test(&key); - secp256k1_scalar_get_b32(key32, &key); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &qj, &key); - secp256k1_ge_set_gej(&q, &qj); - ec_key = get_openssl_key(key32); - CHECK(ec_key != NULL); - CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); - CHECK(secp256k1_ecdsa_sig_parse(&sigr, &sigs, signature, sigsize)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg)); - secp256k1_scalar_set_int(&one, 1); - secp256k1_scalar_add(&msg2, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg2)); - - random_sign(&sigr, &sigs, &key, &msg, NULL); - CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sigr, &sigs)); - CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1); - - EC_KEY_free(ec_key); -} - -void run_ecdsa_openssl(void) { - int i; - for (i = 0; i < 10*count; i++) { - test_ecdsa_openssl(); - } -} -#endif - -#ifdef ENABLE_MODULE_ECDH -# include "modules/ecdh/tests_impl.h" -#endif - -#ifdef ENABLE_MODULE_RECOVERY -# include "modules/recovery/tests_impl.h" -#endif - -#ifdef ENABLE_MODULE_SCHNORR -# include "modules/schnorr/tests_impl.h" -#endif - -int main(int argc, char **argv) { - unsigned char seed16[16] = {0}; - unsigned char run32[32] = {0}; - /* find iteration count */ - if (argc > 1) { - count = strtol(argv[1], NULL, 0); - } - - /* find random seed */ - if (argc > 2) { - int pos = 0; - const char* ch = argv[2]; - while (pos < 16 && ch[0] != 0 && ch[1] != 0) { - unsigned short sh; - if (sscanf(ch, "%2hx", &sh)) { - seed16[pos] = sh; - } else { - break; - } - ch += 2; - pos++; - } - } else { - FILE *frand = fopen("/dev/urandom", "r"); - if ((frand == NULL) || !fread(&seed16, sizeof(seed16), 1, frand)) { - uint64_t t = time(NULL) * (uint64_t)1337; - seed16[0] ^= t; - seed16[1] ^= t >> 8; - seed16[2] ^= t >> 16; - seed16[3] ^= t >> 24; - seed16[4] ^= t >> 32; - seed16[5] ^= t >> 40; - seed16[6] ^= t >> 48; - seed16[7] ^= t >> 56; - } - fclose(frand); - } - secp256k1_rand_seed(seed16); - - printf("test count = %i\n", count); - printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); - - /* initialize */ - run_context_tests(); - ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - if (secp256k1_rand_bits(1)) { - secp256k1_rand256(run32); - CHECK(secp256k1_context_randomize(ctx, secp256k1_rand_bits(1) ? run32 : NULL)); - } - - run_rand_bits(); - run_rand_int(); - - run_sha256_tests(); - run_hmac_sha256_tests(); - run_rfc6979_hmac_sha256_tests(); - -#ifndef USE_NUM_NONE - /* num tests */ - run_num_smalltests(); -#endif - - /* scalar tests */ - run_scalar_tests(); - - /* field tests */ - run_field_inv(); - run_field_inv_var(); - run_field_inv_all_var(); - run_field_misc(); - run_field_convert(); - run_sqr(); - run_sqrt(); - - /* group tests */ - run_ge(); - run_group_decompress(); - - /* ecmult tests */ - run_wnaf(); - run_point_times_order(); - run_ecmult_chain(); - run_ecmult_constants(); - run_ecmult_gen_blind(); - run_ecmult_const_tests(); - run_ec_combine(); - - /* endomorphism tests */ -#ifdef USE_ENDOMORPHISM - run_endomorphism_tests(); -#endif - - /* EC point parser test */ - run_ec_pubkey_parse_test(); - - /* EC key edge cases */ - run_eckey_edge_case_test(); - -#ifdef ENABLE_MODULE_ECDH - /* ecdh tests */ - run_ecdh_tests(); -#endif - - /* ecdsa tests */ - run_random_pubkeys(); - run_ecdsa_der_parse(); - run_ecdsa_sign_verify(); - run_ecdsa_end_to_end(); - run_ecdsa_edge_cases(); -#ifdef ENABLE_OPENSSL_TESTS - run_ecdsa_openssl(); -#endif - -#ifdef ENABLE_MODULE_RECOVERY - /* ECDSA pubkey recovery tests */ - run_recovery_tests(); -#endif - -#ifdef ENABLE_MODULE_SCHNORR - /* Schnorr signature tests */ - run_schnorr_tests(); -#endif - - secp256k1_rand256(run32); - printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); - - /* shutdown */ - secp256k1_context_destroy(ctx); - - printf("no problems found\n"); - return 0; -} diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c deleted file mode 100644 index b040bb0733..0000000000 --- a/src/secp256k1/src/tests_exhaustive.c +++ /dev/null @@ -1,470 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2016 Andrew Poelstra * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#include -#include - -#include - -#undef USE_ECMULT_STATIC_PRECOMPUTATION - -#ifndef EXHAUSTIVE_TEST_ORDER -/* see group_impl.h for allowable values */ -#define EXHAUSTIVE_TEST_ORDER 13 -#define EXHAUSTIVE_TEST_LAMBDA 9 /* cube root of 1 mod 13 */ -#endif - -#include "include/secp256k1.h" -#include "group.h" -#include "secp256k1.c" -#include "testrand_impl.h" - -#ifdef ENABLE_MODULE_RECOVERY -#include "src/modules/recovery/main_impl.h" -#include "include/secp256k1_recovery.h" -#endif - -/** stolen from tests.c */ -void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); - CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); -} - -void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { - secp256k1_fe z2s; - secp256k1_fe u1, u2, s1, s2; - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ - secp256k1_fe_sqr(&z2s, &b->z); - secp256k1_fe_mul(&u1, &a->x, &z2s); - u2 = b->x; secp256k1_fe_normalize_weak(&u2); - secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); - s2 = b->y; secp256k1_fe_normalize_weak(&s2); - CHECK(secp256k1_fe_equal_var(&u1, &u2)); - CHECK(secp256k1_fe_equal_var(&s1, &s2)); -} - -void random_fe(secp256k1_fe *x) { - unsigned char bin[32]; - do { - secp256k1_rand256(bin); - if (secp256k1_fe_set_b32(x, bin)) { - return; - } - } while(1); -} -/** END stolen from tests.c */ - -int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, - const unsigned char *key32, const unsigned char *algo16, - void *data, unsigned int attempt) { - secp256k1_scalar s; - int *idata = data; - (void)msg32; - (void)key32; - (void)algo16; - /* Some nonces cannot be used because they'd cause s and/or r to be zero. - * The signing function has retry logic here that just re-calls the nonce - * function with an increased `attempt`. So if attempt > 0 this means we - * need to change the nonce to avoid an infinite loop. */ - if (attempt > 0) { - *idata = (*idata + 1) % EXHAUSTIVE_TEST_ORDER; - } - secp256k1_scalar_set_int(&s, *idata); - secp256k1_scalar_get_b32(nonce32, &s); - return 1; -} - -#ifdef USE_ENDOMORPHISM -void test_exhaustive_endomorphism(const secp256k1_ge *group, int order) { - int i; - for (i = 0; i < order; i++) { - secp256k1_ge res; - secp256k1_ge_mul_lambda(&res, &group[i]); - ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res); - } -} -#endif - -void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj, int order) { - int i, j; - - /* Sanity-check (and check infinity functions) */ - CHECK(secp256k1_ge_is_infinity(&group[0])); - CHECK(secp256k1_gej_is_infinity(&groupj[0])); - for (i = 1; i < order; i++) { - CHECK(!secp256k1_ge_is_infinity(&group[i])); - CHECK(!secp256k1_gej_is_infinity(&groupj[i])); - } - - /* Check all addition formulae */ - for (j = 0; j < order; j++) { - secp256k1_fe fe_inv; - secp256k1_fe_inv(&fe_inv, &groupj[j].z); - for (i = 0; i < order; i++) { - secp256k1_ge zless_gej; - secp256k1_gej tmp; - /* add_var */ - secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL); - ge_equals_gej(&group[(i + j) % order], &tmp); - /* add_ge */ - if (j > 0) { - secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]); - ge_equals_gej(&group[(i + j) % order], &tmp); - } - /* add_ge_var */ - secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); - ge_equals_gej(&group[(i + j) % order], &tmp); - /* add_zinv_var */ - zless_gej.infinity = groupj[j].infinity; - zless_gej.x = groupj[j].x; - zless_gej.y = groupj[j].y; - secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv); - ge_equals_gej(&group[(i + j) % order], &tmp); - } - } - - /* Check doubling */ - for (i = 0; i < order; i++) { - secp256k1_gej tmp; - if (i > 0) { - secp256k1_gej_double_nonzero(&tmp, &groupj[i], NULL); - ge_equals_gej(&group[(2 * i) % order], &tmp); - } - secp256k1_gej_double_var(&tmp, &groupj[i], NULL); - ge_equals_gej(&group[(2 * i) % order], &tmp); - } - - /* Check negation */ - for (i = 1; i < order; i++) { - secp256k1_ge tmp; - secp256k1_gej tmpj; - secp256k1_ge_neg(&tmp, &group[i]); - ge_equals_ge(&group[order - i], &tmp); - secp256k1_gej_neg(&tmpj, &groupj[i]); - ge_equals_gej(&group[order - i], &tmpj); - } -} - -void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *group, const secp256k1_gej *groupj, int order) { - int i, j, r_log; - for (r_log = 1; r_log < order; r_log++) { - for (j = 0; j < order; j++) { - for (i = 0; i < order; i++) { - secp256k1_gej tmp; - secp256k1_scalar na, ng; - secp256k1_scalar_set_int(&na, i); - secp256k1_scalar_set_int(&ng, j); - - secp256k1_ecmult(&ctx->ecmult_ctx, &tmp, &groupj[r_log], &na, &ng); - ge_equals_gej(&group[(i * r_log + j) % order], &tmp); - - if (i > 0) { - secp256k1_ecmult_const(&tmp, &group[i], &ng); - ge_equals_gej(&group[(i * j) % order], &tmp); - } - } - } - } -} - -void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) { - secp256k1_fe x; - unsigned char x_bin[32]; - k %= EXHAUSTIVE_TEST_ORDER; - x = group[k].x; - secp256k1_fe_normalize(&x); - secp256k1_fe_get_b32(x_bin, &x); - secp256k1_scalar_set_b32(r, x_bin, NULL); -} - -void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { - int s, r, msg, key; - for (s = 1; s < order; s++) { - for (r = 1; r < order; r++) { - for (msg = 1; msg < order; msg++) { - for (key = 1; key < order; key++) { - secp256k1_ge nonconst_ge; - secp256k1_ecdsa_signature sig; - secp256k1_pubkey pk; - secp256k1_scalar sk_s, msg_s, r_s, s_s; - secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; - int k, should_verify; - unsigned char msg32[32]; - - secp256k1_scalar_set_int(&s_s, s); - secp256k1_scalar_set_int(&r_s, r); - secp256k1_scalar_set_int(&msg_s, msg); - secp256k1_scalar_set_int(&sk_s, key); - - /* Verify by hand */ - /* Run through every k value that gives us this r and check that *one* works. - * Note there could be none, there could be multiple, ECDSA is weird. */ - should_verify = 0; - for (k = 0; k < order; k++) { - secp256k1_scalar check_x_s; - r_from_k(&check_x_s, group, k); - if (r_s == check_x_s) { - secp256k1_scalar_set_int(&s_times_k_s, k); - secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); - secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); - secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); - should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); - } - } - /* nb we have a "high s" rule */ - should_verify &= !secp256k1_scalar_is_high(&s_s); - - /* Verify by calling verify */ - secp256k1_ecdsa_signature_save(&sig, &r_s, &s_s); - memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); - secp256k1_pubkey_save(&pk, &nonconst_ge); - secp256k1_scalar_get_b32(msg32, &msg_s); - CHECK(should_verify == - secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); - } - } - } - } -} - -void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { - int i, j, k; - - /* Loop */ - for (i = 1; i < order; i++) { /* message */ - for (j = 1; j < order; j++) { /* key */ - for (k = 1; k < order; k++) { /* nonce */ - const int starting_k = k; - secp256k1_ecdsa_signature sig; - secp256k1_scalar sk, msg, r, s, expected_r; - unsigned char sk32[32], msg32[32]; - secp256k1_scalar_set_int(&msg, i); - secp256k1_scalar_set_int(&sk, j); - secp256k1_scalar_get_b32(sk32, &sk); - secp256k1_scalar_get_b32(msg32, &msg); - - secp256k1_ecdsa_sign(ctx, &sig, msg32, sk32, secp256k1_nonce_function_smallint, &k); - - secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); - /* Note that we compute expected_r *after* signing -- this is important - * because our nonce-computing function function might change k during - * signing. */ - r_from_k(&expected_r, group, k); - CHECK(r == expected_r); - CHECK((k * s) % order == (i + r * j) % order || - (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); - - /* Overflow means we've tried every possible nonce */ - if (k < starting_k) { - break; - } - } - } - } - - /* We would like to verify zero-knowledge here by counting how often every - * possible (s, r) tuple appears, but because the group order is larger - * than the field order, when coercing the x-values to scalar values, some - * appear more often than others, so we are actually not zero-knowledge. - * (This effect also appears in the real code, but the difference is on the - * order of 1/2^128th the field order, so the deviation is not useful to a - * computationally bounded attacker.) - */ -} - -#ifdef ENABLE_MODULE_RECOVERY -void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { - int i, j, k; - - /* Loop */ - for (i = 1; i < order; i++) { /* message */ - for (j = 1; j < order; j++) { /* key */ - for (k = 1; k < order; k++) { /* nonce */ - const int starting_k = k; - secp256k1_fe r_dot_y_normalized; - secp256k1_ecdsa_recoverable_signature rsig; - secp256k1_ecdsa_signature sig; - secp256k1_scalar sk, msg, r, s, expected_r; - unsigned char sk32[32], msg32[32]; - int expected_recid; - int recid; - secp256k1_scalar_set_int(&msg, i); - secp256k1_scalar_set_int(&sk, j); - secp256k1_scalar_get_b32(sk32, &sk); - secp256k1_scalar_get_b32(msg32, &msg); - - secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k); - - /* Check directly */ - secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig); - r_from_k(&expected_r, group, k); - CHECK(r == expected_r); - CHECK((k * s) % order == (i + r * j) % order || - (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); - /* In computing the recid, there is an overflow condition that is disabled in - * scalar_low_impl.h `secp256k1_scalar_set_b32` because almost every r.y value - * will exceed the group order, and our signing code always holds out for r - * values that don't overflow, so with a proper overflow check the tests would - * loop indefinitely. */ - r_dot_y_normalized = group[k].y; - secp256k1_fe_normalize(&r_dot_y_normalized); - /* Also the recovery id is flipped depending if we hit the low-s branch */ - if ((k * s) % order == (i + r * j) % order) { - expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 1 : 0; - } else { - expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 0 : 1; - } - CHECK(recid == expected_recid); - - /* Convert to a standard sig then check */ - secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); - secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); - /* Note that we compute expected_r *after* signing -- this is important - * because our nonce-computing function function might change k during - * signing. */ - r_from_k(&expected_r, group, k); - CHECK(r == expected_r); - CHECK((k * s) % order == (i + r * j) % order || - (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); - - /* Overflow means we've tried every possible nonce */ - if (k < starting_k) { - break; - } - } - } - } -} - -void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { - /* This is essentially a copy of test_exhaustive_verify, with recovery added */ - int s, r, msg, key; - for (s = 1; s < order; s++) { - for (r = 1; r < order; r++) { - for (msg = 1; msg < order; msg++) { - for (key = 1; key < order; key++) { - secp256k1_ge nonconst_ge; - secp256k1_ecdsa_recoverable_signature rsig; - secp256k1_ecdsa_signature sig; - secp256k1_pubkey pk; - secp256k1_scalar sk_s, msg_s, r_s, s_s; - secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; - int recid = 0; - int k, should_verify; - unsigned char msg32[32]; - - secp256k1_scalar_set_int(&s_s, s); - secp256k1_scalar_set_int(&r_s, r); - secp256k1_scalar_set_int(&msg_s, msg); - secp256k1_scalar_set_int(&sk_s, key); - secp256k1_scalar_get_b32(msg32, &msg_s); - - /* Verify by hand */ - /* Run through every k value that gives us this r and check that *one* works. - * Note there could be none, there could be multiple, ECDSA is weird. */ - should_verify = 0; - for (k = 0; k < order; k++) { - secp256k1_scalar check_x_s; - r_from_k(&check_x_s, group, k); - if (r_s == check_x_s) { - secp256k1_scalar_set_int(&s_times_k_s, k); - secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); - secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); - secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); - should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); - } - } - /* nb we have a "high s" rule */ - should_verify &= !secp256k1_scalar_is_high(&s_s); - - /* We would like to try recovering the pubkey and checking that it matches, - * but pubkey recovery is impossible in the exhaustive tests (the reason - * being that there are 12 nonzero r values, 12 nonzero points, and no - * overlap between the sets, so there are no valid signatures). */ - - /* Verify by converting to a standard signature and calling verify */ - secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); - secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); - memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); - secp256k1_pubkey_save(&pk, &nonconst_ge); - CHECK(should_verify == - secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); - } - } - } - } -} -#endif - -int main(void) { - int i; - secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER]; - secp256k1_ge group[EXHAUSTIVE_TEST_ORDER]; - - /* Build context */ - secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - /* TODO set z = 1, then do num_tests runs with random z values */ - - /* Generate the entire group */ - secp256k1_gej_set_infinity(&groupj[0]); - secp256k1_ge_set_gej(&group[0], &groupj[0]); - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { - /* Set a different random z-value for each Jacobian point */ - secp256k1_fe z; - random_fe(&z); - - secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g); - secp256k1_ge_set_gej(&group[i], &groupj[i]); - secp256k1_gej_rescale(&groupj[i], &z); - - /* Verify against ecmult_gen */ - { - secp256k1_scalar scalar_i; - secp256k1_gej generatedj; - secp256k1_ge generated; - - secp256k1_scalar_set_int(&scalar_i, i); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); - secp256k1_ge_set_gej(&generated, &generatedj); - - CHECK(group[i].infinity == 0); - CHECK(generated.infinity == 0); - CHECK(secp256k1_fe_equal_var(&generated.x, &group[i].x)); - CHECK(secp256k1_fe_equal_var(&generated.y, &group[i].y)); - } - } - - /* Run the tests */ -#ifdef USE_ENDOMORPHISM - test_exhaustive_endomorphism(group, EXHAUSTIVE_TEST_ORDER); -#endif - test_exhaustive_addition(group, groupj, EXHAUSTIVE_TEST_ORDER); - test_exhaustive_ecmult(ctx, group, groupj, EXHAUSTIVE_TEST_ORDER); - test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); - test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); - -#ifdef ENABLE_MODULE_RECOVERY - test_exhaustive_recovery_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); - test_exhaustive_recovery_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); -#endif - - secp256k1_context_destroy(ctx); - return 0; -} - diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h deleted file mode 100644 index b0441d8e30..0000000000 --- a/src/secp256k1/src/util.h +++ /dev/null @@ -1,113 +0,0 @@ -/********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_UTIL_H -#define SECP256K1_UTIL_H - -#if defined HAVE_CONFIG_H -#include "libsecp256k1-config.h" -#endif - -#include -#include -#include - -typedef struct { - void (*fn)(const char *text, void* data); - const void* data; -} secp256k1_callback; - -static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * const cb, const char * const text) { - cb->fn(text, (void*)cb->data); -} - -#ifdef DETERMINISTIC -#define TEST_FAILURE(msg) do { \ - fprintf(stderr, "%s\n", msg); \ - abort(); \ -} while(0); -#else -#define TEST_FAILURE(msg) do { \ - fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, msg); \ - abort(); \ -} while(0) -#endif - -#ifdef HAVE_BUILTIN_EXPECT -#define EXPECT(x,c) __builtin_expect((x),(c)) -#else -#define EXPECT(x,c) (x) -#endif - -#ifdef DETERMINISTIC -#define CHECK(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - TEST_FAILURE("test condition failed"); \ - } \ -} while(0) -#else -#define CHECK(cond) do { \ - if (EXPECT(!(cond), 0)) { \ - TEST_FAILURE("test condition failed: " #cond); \ - } \ -} while(0) -#endif - -/* Like assert(), but when VERIFY is defined, and side-effect safe. */ -#if defined(COVERAGE) -#define VERIFY_CHECK(check) -#define VERIFY_SETUP(stmt) -#elif defined(VERIFY) -#define VERIFY_CHECK CHECK -#define VERIFY_SETUP(stmt) do { stmt; } while(0) -#else -#define VERIFY_CHECK(cond) do { (void)(cond); } while(0) -#define VERIFY_SETUP(stmt) -#endif - -static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { - void *ret = malloc(size); - if (ret == NULL) { - secp256k1_callback_call(cb, "Out of memory"); - } - return ret; -} - -/* Macro for restrict, when available and not in a VERIFY build. */ -#if defined(SECP256K1_BUILD) && defined(VERIFY) -# define SECP256K1_RESTRICT -#else -# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) -# if SECP256K1_GNUC_PREREQ(3,0) -# define SECP256K1_RESTRICT __restrict__ -# elif (defined(_MSC_VER) && _MSC_VER >= 1400) -# define SECP256K1_RESTRICT __restrict -# else -# define SECP256K1_RESTRICT -# endif -# else -# define SECP256K1_RESTRICT restrict -# endif -#endif - -#if defined(_WIN32) -# define I64FORMAT "I64d" -# define I64uFORMAT "I64u" -#else -# define I64FORMAT "lld" -# define I64uFORMAT "llu" -#endif - -#if defined(HAVE___INT128) -# if defined(__GNUC__) -# define SECP256K1_GNUC_EXT __extension__ -# else -# define SECP256K1_GNUC_EXT -# endif -SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; -#endif - -#endif /* SECP256K1_UTIL_H */ From 731319635106d97fbbed89377ac0b13e7b1d055d Mon Sep 17 00:00:00 2001 From: Navia Bheeman Date: Tue, 18 Jan 2022 01:12:11 +0530 Subject: [PATCH 02/11] new submodule src/secp256k1 --- .gitmodules | 3 +++ src/secp256k1 | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 src/secp256k1 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..3500cc22d8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/secp256k1"] + path = src/secp256k1 + url = https://github.com/chaintope/secp256k1.git diff --git a/src/secp256k1 b/src/secp256k1 new file mode 160000 index 0000000000..05950ac83c --- /dev/null +++ b/src/secp256k1 @@ -0,0 +1 @@ +Subproject commit 05950ac83c48610709b2144cab18feca9d334b8b From 1daab397a0f9fe7806920730a18e14a7a04feb8b Mon Sep 17 00:00:00 2001 From: Navia Bheeman Date: Tue, 14 Jun 2022 19:36:26 +0530 Subject: [PATCH 03/11] fixed build on macos and renamed bitcoin to tapyrus where applicable --- src/CMakeLists.txt | 6 +-- src/config/CMakeLists.txt | 7 +++ src/config/bitcoin-config.h.cmake.in | 1 + src/qt/CMakeLists.txt | 42 +++++++++++------ src/qt/README.md | 2 +- src/qt/clientmodel.cpp | 10 ++-- src/qt/coincontroldialog.cpp | 16 +++---- src/qt/guiutil.cpp | 4 +- src/qt/optionsdialog.cpp | 2 +- src/qt/optionsmodel.cpp | 2 +- src/qt/optionsmodel.h | 2 +- src/qt/overviewpage.cpp | 16 +++---- src/qt/receiverequestdialog.cpp | 2 +- src/qt/recentrequeststablemodel.cpp | 6 +-- src/qt/sendcoinsdialog.cpp | 22 ++++----- src/qt/splashscreen.cpp | 6 +-- src/qt/tapyrus.cpp | 70 ++++++++++++---------------- src/qt/tapyrusamountfield.cpp | 20 ++++---- src/qt/tapyrusgui.cpp | 25 ++++++---- src/qt/tapyrusunits.cpp | 49 ++++++++++--------- src/qt/tapyrusunits.h | 13 +++--- src/qt/test/wallettests.cpp | 2 +- src/qt/trafficgraphwidget.cpp | 2 +- src/qt/transactiondesc.cpp | 26 +++++------ src/qt/transactiontablemodel.cpp | 18 +++---- src/qt/transactiontablemodel.h | 2 +- src/qt/transactionview.cpp | 4 +- src/qt/walletmodel.cpp | 14 +++--- 28 files changed, 209 insertions(+), 182 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e10770814a..b13ca3b93c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,9 +15,7 @@ option(BUILD_TAPYRUS_SEEDER "Build tapyrus-seeder" ON) option(BUILD_TAPYRUS_CLI "Build tapyrus-cli" ON) option(BUILD_TAPYRUS_GENESIS "Build tapyrus-genesis" ON) option(BUILD_TAPYRUS_TX "Build tapyrus-tx" ON) - -# TODO: Fix qt building problem and turn ON. -option(BUILD_TAPYRUS_QT "Build tapyrus-qt" ON) +option(ENABLE_QRCODE "Build QR support in wallet" OFF) # Ensure that WINDRES_PREPROC is enabled when using windres. if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") @@ -308,4 +306,4 @@ if(BUILD_TAPYRUS_QT) add_subdirectory(qt) endif() -message(status "BUILD_TAPYRUS_QT=${BUILD_TAPYRUS_QT}") \ No newline at end of file +message(STATUS "BUILD_TAPYRUS_QT=${BUILD_TAPYRUS_QT}") \ No newline at end of file diff --git a/src/config/CMakeLists.txt b/src/config/CMakeLists.txt index 0293f3b631..82f9e2ea92 100644 --- a/src/config/CMakeLists.txt +++ b/src/config/CMakeLists.txt @@ -150,5 +150,12 @@ set(ENABLE_WALLET ${BUILD_TAPYRUS_WALLET}) # Activate ZeroMQ set(ENABLE_ZMQ ${BUILD_TAPYRUS_ZMQ}) +# Try to find libqrencode + # Only used in the wallet GUI + if(ENABLE_QRCODE AND BUILD_BITCOIN_WALLET AND BUILD_BITCOIN_QT) + find_package(QREncode REQUIRED) + set(USE_QRCODE 1 CACHE INTERNAL "QR code is enabled") + endif() + # Generate the config configure_file(bitcoin-config.h.cmake.in bitcoin-config.h ESCAPE_QUOTES) diff --git a/src/config/bitcoin-config.h.cmake.in b/src/config/bitcoin-config.h.cmake.in index 0acdedcd99..249deccfb2 100644 --- a/src/config/bitcoin-config.h.cmake.in +++ b/src/config/bitcoin-config.h.cmake.in @@ -60,5 +60,6 @@ #cmakedefine ENABLE_WALLET 1 #cmakedefine ENABLE_ZMQ 1 +#cmakedefine ENABLE_QRCODE 0 #endif // BITCOIN_BITCOIN_CONFIG_H diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 4a394bafab..d870153e4e 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -3,7 +3,7 @@ project(tapyrus-qt) # This ensure that AUTOMOC doesn't run on generated files. -cmake_policy(SET CMP0071 OLD) +cmake_policy(SET CMP0071 NEW) include(BrewHelper) find_brew_prefix(QT5_PREFIX qt5) @@ -11,8 +11,6 @@ find_brew_prefix(QT5_PREFIX qt5) set(QT_REQUIRED_COMPONENTS Core Widgets Network DBus Test) find_package(Qt5 COMPONENTS ${QT_REQUIRED_COMPONENTS} REQUIRED HINTS "${QT5_PREFIX}") -find_package(QREncode REQUIRED) - # Find out more about Qt. This is similar to # http://code.qt.io/cgit/qt/qtwebkit.git/tree/Source/cmake/OptionsQt.cmake get_target_property(QT_CORE_TYPE Qt5::Core TYPE) @@ -157,17 +155,32 @@ add_library(tapyrus-qt-base qrc_tapyrus_locale.cpp ) +# Linux support +if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + list(APPEND QT_PLUGIN_COMPONENTS QXcbIntegrationPlugin) + list(APPEND QT_PLUGIN_PLATFORM_DEFINITIONS -DQT_QPA_PLATFORM_XCB=1) +endif() # Windows support if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + list(APPEND QT_PLUGIN_COMPONENTS QWindowsIntegrationPlugin) + list(APPEND QT_PLUGIN_PLATFORM_DEFINITIONS -DQT_QPA_PLATFORM_WINDOWS=1) target_sources(tapyrus-qt-base PRIVATE winshutdownmonitor.cpp) endif() - -target_include_directories(tapyrus-qt-base - PUBLIC - . - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_BINARY_DIR}/forms -) +# OSX support +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + list(APPEND QT_PLUGIN_COMPONENTS QCocoaIntegrationPlugin) + list(APPEND QT_PLUGIN_PLATFORM_DEFINITIONS -DQT_QPA_PLATFORM_COCOA=1) + target_sources(tapyrus-qt-base PRIVATE + macdockiconhandler.mm + macnotificationhandler.mm + ) + set_property(TARGET tapyrus-qt-base PROPERTY AUTOMOC_MOC_OPTIONS "-DQ_OS_MAC") + target_link_libraries(tapyrus-qt-base + "-framework Foundation" + "-framework ApplicationServices" + "-framework AppKit" + ) +endif() target_link_libraries(tapyrus-qt-base server @@ -175,12 +188,8 @@ target_link_libraries(tapyrus-qt-base Qt5::Widgets Qt5::Network Qt5::DBus - qrencode ) -if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set_property(TARGET tapyrus-qt-base PROPERTY AUTOMOC_MOC_OPTIONS "-DQ_OS_MAC") -endif() # Wallet if(BUILD_TAPYRUS_WALLET) @@ -218,6 +227,11 @@ if(BUILD_TAPYRUS_WALLET) ) target_link_libraries(tapyrus-qt-base wallet) + + if(ENABLE_QRCODE) + find_package(QREncode REQUIRED) + target_link_libraries(tapyrus-qt-base QREncode::qrencode) + endif() endif() # The executable diff --git a/src/qt/README.md b/src/qt/README.md index 1acd71b48d..3c8cd5335e 100644 --- a/src/qt/README.md +++ b/src/qt/README.md @@ -60,7 +60,7 @@ Represents the view to a single wallet. * UI elements like BitcoinAmountField, which inherit from QWidget. * `bitcoinstrings.cpp`: automatically generated -* `bitcoinunits.(h/cpp)`: TPC / mTPC / etc handling +* `TapyrusUnits.(h/cpp)`: TPC / mTPC / etc handling * `callback.h` * `guiconstants.h`: UI colors, app name, etc * `guiutil.h`: several helper functions diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 7154ac14be..c40a6703a7 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -247,13 +247,13 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int heig void ClientModel::subscribeToCoreSignals() { // Connect signals to client - m_handler_show_progress = m_node.handleShowProgress(boost::bind(ShowProgress, this, _1, _2)); - m_handler_notify_num_connections_changed = m_node.handleNotifyNumConnectionsChanged(boost::bind(NotifyNumConnectionsChanged, this, _1)); - m_handler_notify_network_active_changed = m_node.handleNotifyNetworkActiveChanged(boost::bind(NotifyNetworkActiveChanged, this, _1)); + m_handler_show_progress = m_node.handleShowProgress(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); + m_handler_notify_num_connections_changed = m_node.handleNotifyNumConnectionsChanged(boost::bind(NotifyNumConnectionsChanged, this, boost::placeholders::_1)); + m_handler_notify_network_active_changed = m_node.handleNotifyNetworkActiveChanged(boost::bind(NotifyNetworkActiveChanged, this, boost::placeholders::_1)); m_handler_notify_alert_changed = m_node.handleNotifyAlertChanged(boost::bind(NotifyAlertChanged, this)); m_handler_banned_list_changed = m_node.handleBannedListChanged(boost::bind(BannedListChanged, this)); - m_handler_notify_block_tip = m_node.handleNotifyBlockTip(boost::bind(BlockTipChanged, this, _1, _2, _3, _4, false)); - m_handler_notify_header_tip = m_node.handleNotifyHeaderTip(boost::bind(BlockTipChanged, this, _1, _2, _3, _4, true)); + m_handler_notify_block_tip = m_node.handleNotifyBlockTip(boost::bind(BlockTipChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, false)); + m_handler_notify_header_tip = m_node.handleNotifyHeaderTip(boost::bind(BlockTipChanged, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, true)); } void ClientModel::unsubscribeFromCoreSignals() diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 14edf39052..178b7a938f 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -233,7 +233,7 @@ void CoinControlDialog::showMenu(const QPoint &point) // context menu action: copy amount void CoinControlDialog::copyAmount() { - GUIUtil::setClipboard(BitcoinUnits::removeSpaces(contextMenuItem->text(COLUMN_AMOUNT))); + GUIUtil::setClipboard(TapyrusUnits::removeSpaces(contextMenuItem->text(COLUMN_AMOUNT))); } // context menu action: copy label @@ -535,7 +535,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) } // actually update labels - int nDisplayUnit = BitcoinUnits::TPC; + int nDisplayUnit = TapyrusUnits::TPC; if (model && model->getOptionsModel()) nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); @@ -555,12 +555,12 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) // stats l1->setText(QString::number(nQuantity)); // Quantity - l2->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAmount)); // Amount - l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee - l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee + l2->setText(TapyrusUnits::formatWithUnit(nDisplayUnit, nAmount)); // Amount + l3->setText(TapyrusUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee + l4->setText(TapyrusUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee l5->setText(((nBytes > 0) ? ASYMP_UTF8 : "") + QString::number(nBytes)); // Bytes l7->setText(fDust ? tr("yes") : tr("no")); // Dust - l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change + l8->setText(TapyrusUnits::formatWithUnit(nDisplayUnit, nChange)); // Change if (nPayFee > 0) { l3->setText(ASYMP_UTF8 + l3->text()); @@ -682,7 +682,7 @@ void CoinControlDialog::updateView() } // amount - itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.txout.nValue)); + itemOutput->setText(COLUMN_AMOUNT, TapyrusUnits::format(nDisplayUnit, out.txout.nValue)); itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.txout.nValue)); // padding so that sorting works correctly // date @@ -716,7 +716,7 @@ void CoinControlDialog::updateView() if (treeMode) { itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")"); - itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); + itemWalletAddress->setText(COLUMN_AMOUNT, TapyrusUnits::format(nDisplayUnit, nSum)); itemWalletAddress->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)nSum)); } } diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 1537c93e24..c4e4cfb515 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -158,7 +158,7 @@ bool parseTapyrusURI(const QUrl &uri, SendCoinsRecipient *out) { if(!i->second.isEmpty()) { - if(!BitcoinUnits::parse(BitcoinUnits::TPC, i->second, &rv.amount)) + if(!TapyrusUnits::parse(TapyrusUnits::TPC, i->second, &rv.amount)) { return false; } @@ -189,7 +189,7 @@ QString formatTapyrusURI(const SendCoinsRecipient &info) if (info.amount) { - ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnits::TPC, info.amount, false, BitcoinUnits::separatorNever)); + ret += QString("?amount=%1").arg(TapyrusUnits::format(TapyrusUnits::TPC, info.amount, false, TapyrusUnits::separatorNever)); paramCount++; } diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index cd4687fbd1..aae3e629a9 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -108,7 +108,7 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : } ui->thirdPartyTxUrls->setPlaceholderText("https://example.com/tx/%s"); - ui->unit->setModel(new BitcoinUnits(this)); + ui->unit->setModel(new TapyrusUnits(this)); /* Widget-to-option mapper */ mapper = new QDataWidgetMapper(this); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index fb265a93b7..5fc79789db 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -67,7 +67,7 @@ void OptionsModel::Init(bool resetSettings) // Display if (!settings.contains("nDisplayUnit")) - settings.setValue("nDisplayUnit", BitcoinUnits::TPC); + settings.setValue("nDisplayUnit", TapyrusUnits::TPC); nDisplayUnit = settings.value("nDisplayUnit").toInt(); if (!settings.contains("strThirdPartyTxUrls")) diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index f2ef5acbf0..3bde9cddc4 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -44,7 +44,7 @@ class OptionsModel : public QAbstractListModel ProxyUseTor, // bool ProxyIPTor, // QString ProxyPortTor, // int - DisplayUnit, // BitcoinUnits::Unit + DisplayUnit, // TapyrusUnits::Unit ThirdPartyTxUrls, // QString Language, // QString CoinControlFeatures, // bool diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index aa3b817677..dc0b490cb6 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -28,7 +28,7 @@ class TxViewDelegate : public QAbstractItemDelegate Q_OBJECT public: explicit TxViewDelegate(const PlatformStyle *_platformStyle, QObject *parent=nullptr): - QAbstractItemDelegate(parent), unit(BitcoinUnits::TPC), + QAbstractItemDelegate(parent), unit(TapyrusUnits::TPC), platformStyle(_platformStyle) { @@ -86,7 +86,7 @@ class TxViewDelegate : public QAbstractItemDelegate foreground = option.palette.color(QPalette::Text); } painter->setPen(foreground); - QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true, BitcoinUnits::separatorAlways); + QString amountText = TapyrusUnits::formatWithUnit(unit, amount, true, TapyrusUnits::separatorAlways); if(!confirmed) { amountText = QString("[") + amountText + QString("]"); @@ -167,12 +167,12 @@ void OverviewPage::setBalance(const interfaces::WalletBalances& balances) CAmount watch_only_balance = balances.getWatchOnlyBalance(); CAmount unconfirmed_watch_only_balance = balances.getUnconfirmedWatchOnlyBalance(); - ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::separatorAlways)); - ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::separatorAlways)); - ui->labelTotal->setText(BitcoinUnits::formatWithUnit(unit, balance + unconfirmed_balance, false, BitcoinUnits::separatorAlways)); - ui->labelWatchAvailable->setText(BitcoinUnits::formatWithUnit(unit, watch_only_balance, false, BitcoinUnits::separatorAlways)); - ui->labelWatchPending->setText(BitcoinUnits::formatWithUnit(unit, unconfirmed_watch_only_balance, false, BitcoinUnits::separatorAlways)); - ui->labelWatchTotal->setText(BitcoinUnits::formatWithUnit(unit, watch_only_balance + unconfirmed_watch_only_balance, false, BitcoinUnits::separatorAlways)); + ui->labelBalance->setText(TapyrusUnits::formatWithUnit(unit, balance, false, TapyrusUnits::separatorAlways)); + ui->labelUnconfirmed->setText(TapyrusUnits::formatWithUnit(unit, balance, false, TapyrusUnits::separatorAlways)); + ui->labelTotal->setText(TapyrusUnits::formatWithUnit(unit, balance + unconfirmed_balance, false, TapyrusUnits::separatorAlways)); + ui->labelWatchAvailable->setText(TapyrusUnits::formatWithUnit(unit, watch_only_balance, false, TapyrusUnits::separatorAlways)); + ui->labelWatchPending->setText(TapyrusUnits::formatWithUnit(unit, unconfirmed_watch_only_balance, false, TapyrusUnits::separatorAlways)); + ui->labelWatchTotal->setText(TapyrusUnits::formatWithUnit(unit, watch_only_balance + unconfirmed_watch_only_balance, false, TapyrusUnits::separatorAlways)); } // show/hide watch-only labels diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index 6ac2f2c694..02c5563257 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -140,7 +140,7 @@ void ReceiveRequestDialog::update() html += "" + GUIUtil::HtmlEscape(uri) + "
"; html += ""+tr("Address")+": " + GUIUtil::HtmlEscape(info.address) + "
"; if(info.amount) - html += ""+tr("Amount")+": " + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), info.amount) + "
"; + html += ""+tr("Amount")+": " + TapyrusUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), info.amount) + "
"; if(!info.label.isEmpty()) html += ""+tr("Label")+": " + GUIUtil::HtmlEscape(info.label) + "
"; if(!info.message.isEmpty()) diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 9eb6ff1c29..732ff944d0 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -82,9 +82,9 @@ QVariant RecentRequestsTableModel::data(const QModelIndex &index, int role) cons if (rec->recipient.amount == 0 && role == Qt::DisplayRole) return tr("(no amount requested)"); else if (role == Qt::EditRole) - return BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount, false, BitcoinUnits::separatorNever); + return TapyrusUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount, false, TapyrusUnits::separatorNever); else - return BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount); + return TapyrusUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount); } } else if (role == Qt::TextAlignmentRole) @@ -122,7 +122,7 @@ void RecentRequestsTableModel::updateAmountColumnTitle() /** Gets title for amount column including current display unit if optionsModel reference available. */ QString RecentRequestsTableModel::getAmountTitle() { - return (this->walletModel->getOptionsModel() != nullptr) ? tr("Requested") + " ("+BitcoinUnits::shortName(this->walletModel->getOptionsModel()->getDisplayUnit()) + ")" : ""; + return (this->walletModel->getOptionsModel() != nullptr) ? tr("Requested") + " ("+TapyrusUnits::shortName(this->walletModel->getOptionsModel()->getDisplayUnit()) + ")" : ""; } QModelIndex RecentRequestsTableModel::index(int row, int column, const QModelIndex &parent) const diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index d3a789bbe2..2bf685df19 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -269,7 +269,7 @@ void SendCoinsDialog::on_sendButton_clicked() // process prepareStatus and on error generate message shown to user processSendCoinsReturn(prepareStatus, - BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), currentTransaction.getTransactionFee())); + TapyrusUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), currentTransaction.getTransactionFee())); if(prepareStatus.status != WalletModel::OK) { fNewRecipientAllowed = true; @@ -283,7 +283,7 @@ void SendCoinsDialog::on_sendButton_clicked() for (const SendCoinsRecipient &rcp : currentTransaction.getRecipients()) { // generate bold amount string with wallet name in case of multiwallet - QString amount = "" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount); + QString amount = "" + TapyrusUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount); if (model->isMultiwallet()) { amount.append(" "+tr("from wallet %1").arg(GUIUtil::HtmlEscape(model->getWalletName()))+" "); } @@ -327,7 +327,7 @@ void SendCoinsDialog::on_sendButton_clicked() // append transaction fee value questionString.append(""); - questionString.append(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), txFee)); + questionString.append(TapyrusUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), txFee)); questionString.append("
"); // append RBF message according to transaction's signalling @@ -344,13 +344,13 @@ void SendCoinsDialog::on_sendButton_clicked() questionString.append("
"); CAmount totalAmount = currentTransaction.getTotalTransactionAmount() + txFee; QStringList alternativeUnits; - for (BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) + for (TapyrusUnits::Unit u : TapyrusUnits::availableUnits()) { if(u != model->getOptionsModel()->getDisplayUnit()) - alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount)); + alternativeUnits.append(TapyrusUnits::formatHtmlWithUnit(u, totalAmount)); } questionString.append(QString("%1: %2").arg(tr("Total Amount")) - .arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount))); + .arg(TapyrusUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount))); questionString.append(QString("
(=%1)") .arg(alternativeUnits.join(" " + tr("or") + " "))); @@ -522,7 +522,7 @@ void SendCoinsDialog::setBalance(const interfaces::WalletBalances& balances) { if(model && model->getOptionsModel()) { - ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), balances.getBalance())); + ui->labelBalance->setText(TapyrusUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), balances.getBalance())); } } @@ -569,7 +569,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn msgParams.second = CClientUIInterface::MSG_ERROR; break; case WalletModel::AbsurdFee: - msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->node().getMaxTxFee())); + msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(TapyrusUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->node().getMaxTxFee())); break; case WalletModel::PaymentRequestExpired: msgParams.first = tr("Payment request expired."); @@ -656,7 +656,7 @@ void SendCoinsDialog::updateFeeMinimizedLabel() if (ui->radioSmartFee->isChecked()) ui->labelFeeMinimized->setText(ui->labelSmartFee->text()); else { - ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) + "/kB"); + ui->labelFeeMinimized->setText(TapyrusUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) + "/kB"); } } @@ -664,7 +664,7 @@ void SendCoinsDialog::updateMinFeeLabel() { if (model && model->getOptionsModel()) ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg( - BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->wallet().getRequiredFee(1000)) + "/kB") + TapyrusUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->wallet().getRequiredFee(1000)) + "/kB") ); } @@ -692,7 +692,7 @@ void SendCoinsDialog::updateSmartFeeLabel() FeeReason reason; CFeeRate feeRate = CFeeRate(model->wallet().getMinimumFee(1000, coin_control, &returned_target, &reason)); - ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB"); + ui->labelSmartFee->setText(TapyrusUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB"); if (reason == FeeReason::FALLBACK) { ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...) diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index e438d22919..3620186f7b 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -178,7 +178,7 @@ static void ShowProgress(SplashScreen *splash, const std::string &title, int nPr #ifdef ENABLE_WALLET void SplashScreen::ConnectWallet(std::unique_ptr wallet) { - m_connected_wallet_handlers.emplace_back(wallet->handleShowProgress(boost::bind(ShowProgress, this, _1, _2, false))); + m_connected_wallet_handlers.emplace_back(wallet->handleShowProgress(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2, false))); m_connected_wallets.emplace_back(std::move(wallet)); } #endif @@ -186,8 +186,8 @@ void SplashScreen::ConnectWallet(std::unique_ptr wallet) void SplashScreen::subscribeToCoreSignals() { // Connect signals to client - m_handler_init_message = m_node.handleInitMessage(boost::bind(InitMessage, this, _1)); - m_handler_show_progress = m_node.handleShowProgress(boost::bind(ShowProgress, this, _1, _2, _3)); + m_handler_init_message = m_node.handleInitMessage(boost::bind(InitMessage, this, boost::placeholders::_1)); + m_handler_show_progress = m_node.handleShowProgress(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); #ifdef ENABLE_WALLET m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr wallet) { ConnectWallet(std::move(wallet)); }); #endif diff --git a/src/qt/tapyrus.cpp b/src/qt/tapyrus.cpp index ad169a7224..f733ecc752 100644 --- a/src/qt/tapyrus.cpp +++ b/src/qt/tapyrus.cpp @@ -152,11 +152,11 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons /** Class encapsulating Bitcoin Core startup and shutdown. * Allows running startup and shutdown in a different thread from the UI thread. */ -class BitcoinCore: public QObject +class TapyrusCore: public QObject { Q_OBJECT public: - explicit BitcoinCore(interfaces::Node& node); + explicit TapyrusCore(interfaces::Node& node); public Q_SLOTS: void initialize(); @@ -174,13 +174,13 @@ public Q_SLOTS: interfaces::Node& m_node; }; -/** Main Bitcoin application object */ -class BitcoinApplication: public QApplication +/** Main Tapyrus application object */ +class TapyrusApplication: public QApplication { Q_OBJECT public: - explicit BitcoinApplication(interfaces::Node& node, int &argc, char **argv); - ~BitcoinApplication(); + explicit TapyrusApplication(interfaces::Node& node, int &argc, char **argv); + ~TapyrusApplication(); #ifdef ENABLE_WALLET /// Create payment server @@ -244,18 +244,18 @@ public Q_SLOTS: #include -BitcoinCore::BitcoinCore(interfaces::Node& node) : +TapyrusCore::TapyrusCore(interfaces::Node& node) : QObject(), m_node(node) { } -void BitcoinCore::handleRunawayException(const std::exception *e) +void TapyrusCore::handleRunawayException(const std::exception *e) { PrintExceptionContinue(e, "Runaway exception"); Q_EMIT runawayException(QString::fromStdString(m_node.getWarnings("gui"))); } -void BitcoinCore::initialize() +void TapyrusCore::initialize() { try { @@ -269,7 +269,7 @@ void BitcoinCore::initialize() } } -void BitcoinCore::shutdown() +void TapyrusCore::shutdown() { try { @@ -284,7 +284,7 @@ void BitcoinCore::shutdown() } } -BitcoinApplication::BitcoinApplication(interfaces::Node& node, int &argc, char **argv): +TapyrusApplication::TapyrusApplication(interfaces::Node& node, int &argc, char **argv): QApplication(argc, argv), coreThread(0), m_node(node), @@ -302,10 +302,10 @@ BitcoinApplication::BitcoinApplication(interfaces::Node& node, int &argc, char * setQuitOnLastWindowClosed(false); } -void BitcoinApplication::setupPlatformStyle() +void TapyrusApplication::setupPlatformStyle() { // UI per-platform customization - // This must be done inside the BitcoinApplication constructor, or after it, because + // This must be done inside the TapyrusApplication constructor, or after it, because // PlatformStyle::instantiate requires a QApplication std::string platformName; platformName = gArgs.GetArg("-uiplatform", BitcoinGUI::DEFAULT_UIPLATFORM); @@ -315,7 +315,7 @@ void BitcoinApplication::setupPlatformStyle() assert(platformStyle); } -BitcoinApplication::~BitcoinApplication() +TapyrusApplication::~TapyrusApplication() { if(coreThread) { @@ -338,18 +338,18 @@ BitcoinApplication::~BitcoinApplication() } #ifdef ENABLE_WALLET -void BitcoinApplication::createPaymentServer() +void TapyrusApplication::createPaymentServer() { paymentServer = new PaymentServer(this); } #endif -void BitcoinApplication::createOptionsModel(bool resetSettings) +void TapyrusApplication::createOptionsModel(bool resetSettings) { optionsModel = new OptionsModel(m_node, nullptr, resetSettings); } -void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) +void TapyrusApplication::createWindow(const NetworkStyle *networkStyle) { window = new BitcoinGUI(m_node, platformStyle, networkStyle, 0); @@ -357,7 +357,7 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown())); } -void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) +void TapyrusApplication::createSplashScreen(const NetworkStyle *networkStyle) { SplashScreen *splash = new SplashScreen(m_node, 0, networkStyle); // We don't hold a direct pointer to the splash screen after creation, but the splash @@ -367,12 +367,12 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) connect(this, SIGNAL(requestedShutdown()), splash, SLOT(close())); } -void BitcoinApplication::startThread() +void TapyrusApplication::startThread() { if(coreThread) return; coreThread = new QThread(this); - BitcoinCore *executor = new BitcoinCore(m_node); + TapyrusCore *executor = new TapyrusCore(m_node); executor->moveToThread(coreThread); /* communication to and from thread */ @@ -388,7 +388,7 @@ void BitcoinApplication::startThread() coreThread->start(); } -void BitcoinApplication::parameterSetup() +void TapyrusApplication::parameterSetup() { // Default printtoconsole to false for the GUI. GUI programs should not // print to the console unnecessarily. @@ -398,14 +398,14 @@ void BitcoinApplication::parameterSetup() m_node.initParameterInteraction(); } -void BitcoinApplication::requestInitialize() +void TapyrusApplication::requestInitialize() { qDebug() << __func__ << ": Requesting initialize"; startThread(); Q_EMIT requestedInitialize(); } -void BitcoinApplication::requestShutdown() +void TapyrusApplication::requestShutdown() { // Show a simple window indicating shutdown status // Do this first as some of the steps may take some time below, @@ -434,7 +434,7 @@ void BitcoinApplication::requestShutdown() Q_EMIT requestedShutdown(); } -void BitcoinApplication::addWallet(WalletModel* walletModel) +void TapyrusApplication::addWallet(WalletModel* walletModel) { #ifdef ENABLE_WALLET window->addWallet(walletModel); @@ -442,15 +442,13 @@ void BitcoinApplication::addWallet(WalletModel* walletModel) if (m_wallet_models.empty()) { window->setCurrentWallet(walletModel->getWalletName()); } - connect(walletModel, SIGNAL(coinsSent(WalletModel*, SendCoinsRecipient, QByteArray)), - paymentServer, SLOT(fetchPaymentACK(WalletModel*, const SendCoinsRecipient&, QByteArray))); connect(walletModel, SIGNAL(unload()), this, SLOT(removeWallet())); m_wallet_models.push_back(walletModel); #endif } -void BitcoinApplication::removeWallet() +void TapyrusApplication::removeWallet() { #ifdef ENABLE_WALLET WalletModel* walletModel = static_cast(sender()); @@ -460,7 +458,7 @@ void BitcoinApplication::removeWallet() #endif } -void BitcoinApplication::initializeResult(bool success) +void TapyrusApplication::initializeResult(bool success) { qDebug() << __func__ << ": Initialization result: " << success; // Set exit result. @@ -518,18 +516,18 @@ void BitcoinApplication::initializeResult(bool success) } } -void BitcoinApplication::shutdownResult() +void TapyrusApplication::shutdownResult() { quit(); // Exit second main loop invocation after shutdown finished } -void BitcoinApplication::handleRunawayException(const QString &message) +void TapyrusApplication::handleRunawayException(const QString &message) { QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Tapyrus can no longer continue safely and will quit.") + QString("\n\n") + message); ::exit(EXIT_FAILURE); } -WId BitcoinApplication::getMainWinId() const +WId TapyrusApplication::getMainWinId() const { if (!window) return 0; @@ -561,17 +559,11 @@ int main(int argc, char *argv[]) Q_INIT_RESOURCE(tapyrus); Q_INIT_RESOURCE(tapyrus_locale); - BitcoinApplication app(*node, argc, argv); -#if QT_VERSION > 0x050100 // Generate high-dpi pixmaps QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); -#endif -#if QT_VERSION >= 0x050600 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); -#endif -#ifdef Q_OS_MAC - QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); -#endif + + TapyrusApplication app(*node, argc, argv); // Register meta types used for QMetaObject::invokeMethod qRegisterMetaType< bool* >(); diff --git a/src/qt/tapyrusamountfield.cpp b/src/qt/tapyrusamountfield.cpp index 14c5bdb4ed..64d5048bc1 100644 --- a/src/qt/tapyrusamountfield.cpp +++ b/src/qt/tapyrusamountfield.cpp @@ -24,7 +24,7 @@ class AmountSpinBox: public QAbstractSpinBox public: explicit AmountSpinBox(QWidget *parent): QAbstractSpinBox(parent), - currentUnit(BitcoinUnits::TPC), + currentUnit(TapyrusUnits::TPC), singleStep(100000) // tapyrus { setAlignment(Qt::AlignRight); @@ -48,7 +48,7 @@ class AmountSpinBox: public QAbstractSpinBox CAmount val = parse(input, &valid); if(valid) { - input = BitcoinUnits::format(currentUnit, val, false, BitcoinUnits::separatorAlways); + input = TapyrusUnits::format(currentUnit, val, false, TapyrusUnits::separatorAlways); lineEdit()->setText(input); } } @@ -60,7 +60,7 @@ class AmountSpinBox: public QAbstractSpinBox void setValue(const CAmount& value) { - lineEdit()->setText(BitcoinUnits::format(currentUnit, value, false, BitcoinUnits::separatorAlways)); + lineEdit()->setText(TapyrusUnits::format(currentUnit, value, false, TapyrusUnits::separatorAlways)); Q_EMIT valueChanged(); } @@ -69,7 +69,7 @@ class AmountSpinBox: public QAbstractSpinBox bool valid = false; CAmount val = value(&valid); val = val + steps * singleStep; - val = qMin(qMax(val, CAmount(0)), BitcoinUnits::maxMoney()); + val = qMin(qMax(val, CAmount(0)), TapyrusUnits::maxMoney()); setValue(val); } @@ -99,7 +99,7 @@ class AmountSpinBox: public QAbstractSpinBox const QFontMetrics fm(fontMetrics()); int h = lineEdit()->minimumSizeHint().height(); - int w = fm.width(BitcoinUnits::format(BitcoinUnits::TPC, BitcoinUnits::maxMoney(), false, BitcoinUnits::separatorAlways)); + int w = fm.width(TapyrusUnits::format(TapyrusUnits::TPC, TapyrusUnits::maxMoney(), false, TapyrusUnits::separatorAlways)); w += 2; // cursor blinking space QStyleOptionSpinBox opt; @@ -137,10 +137,10 @@ class AmountSpinBox: public QAbstractSpinBox CAmount parse(const QString &text, bool *valid_out=0) const { CAmount val = 0; - bool valid = BitcoinUnits::parse(currentUnit, text, &val); + bool valid = TapyrusUnits::parse(currentUnit, text, &val); if(valid) { - if(val < 0 || val > BitcoinUnits::maxMoney()) + if(val < 0 || val > TapyrusUnits::maxMoney()) valid = false; } if(valid_out) @@ -178,7 +178,7 @@ class AmountSpinBox: public QAbstractSpinBox { if(val > 0) rv |= StepDownEnabled; - if(val < BitcoinUnits::maxMoney()) + if(val < TapyrusUnits::maxMoney()) rv |= StepUpEnabled; } return rv; @@ -202,7 +202,7 @@ BitcoinAmountField::BitcoinAmountField(QWidget *parent) : QHBoxLayout *layout = new QHBoxLayout(this); layout->addWidget(amount); unit = new QValueComboBox(this); - unit->setModel(new BitcoinUnits(this)); + unit->setModel(new TapyrusUnits(this)); layout->addWidget(unit); layout->addStretch(1); layout->setContentsMargins(0,0,0,0); @@ -286,7 +286,7 @@ void BitcoinAmountField::unitChanged(int idx) unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString()); // Determine new unit ID - int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt(); + int newUnit = unit->itemData(idx, TapyrusUnits::UnitRole).toInt(); amount->setDisplayUnit(newUnit); } diff --git a/src/qt/tapyrusgui.cpp b/src/qt/tapyrusgui.cpp index fb82a358fc..9de68764fd 100644 --- a/src/qt/tapyrusgui.cpp +++ b/src/qt/tapyrusgui.cpp @@ -995,7 +995,7 @@ void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmoun { // On new transaction, make an info balloon QString msg = tr("Date: %1\n").arg(date) + - tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(unit, amount, true)); + tr("Amount: %1\n").arg(TapyrusUnits::formatWithUnit(unit, amount, true)); if (m_node.getWallets().size() > 1 && !walletName.isEmpty()) { msg += tr("Wallet: %1\n").arg(walletName); } @@ -1221,8 +1221,8 @@ static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, co void BitcoinGUI::subscribeToCoreSignals() { // Connect signals to client - m_handler_message_box = m_node.handleMessageBox(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3)); - m_handler_question = m_node.handleQuestion(boost::bind(ThreadSafeMessageBox, this, _1, _3, _4)); + m_handler_message_box = m_node.handleMessageBox(boost::bind(ThreadSafeMessageBox, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)); + m_handler_question = m_node.handleQuestion(boost::bind(ThreadSafeMessageBox, this, boost::placeholders::_1, boost::placeholders::_3, boost::placeholders::_4)); } void BitcoinGUI::unsubscribeFromCoreSignals() @@ -1243,12 +1243,12 @@ UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *pl { createContextMenu(); setToolTip(tr("Unit to show amounts in. Click to select another unit.")); - QList units = BitcoinUnits::availableUnits(); + QList units = TapyrusUnits::availableUnits(); int max_width = 0; const QFontMetrics fm(font()); - for (const BitcoinUnits::Unit unit : units) + for (const TapyrusUnits::Unit unit : units) { - max_width = qMax(max_width, fm.width(BitcoinUnits::longName(unit))); + max_width = qMax(max_width, fm.width(TapyrusUnits::longName(unit))); } setMinimumSize(max_width, 0); setAlignment(Qt::AlignRight | Qt::AlignVCenter); @@ -1265,12 +1265,19 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event) void UnitDisplayStatusBarControl::createContextMenu() { menu = new QMenu(this); - for (BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) + for (TapyrusUnits::Unit u : TapyrusUnits::availableUnits()) { - QAction *menuAction = new QAction(QString(BitcoinUnits::longName(u)), this); + QAction *menuAction = new QAction(QString(TapyrusUnits::longName(u)), this); menuAction->setData(QVariant(u)); menu->addAction(menuAction); } + /*for (auto tokenAmtPair: model->wallet()->getT Balances().balances ) + { + QString longName = QString(tokenAmtPair.first().toHexString()); + QAction *menuAction = new QAction(longName, this); + menuAction->setData(QVariant(longName)); + menu->addAction(menuAction); + }*/ connect(menu,SIGNAL(triggered(QAction*)),this,SLOT(onMenuSelection(QAction*))); } @@ -1292,7 +1299,7 @@ void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *_optionsModel) /** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */ void UnitDisplayStatusBarControl::updateDisplayUnit(int newUnits) { - setText(BitcoinUnits::longName(newUnits)); + setText(TapyrusUnits::longName(newUnits)); } /** Shows context menu with Display Unit options by the mouse coordinates */ diff --git a/src/qt/tapyrusunits.cpp b/src/qt/tapyrusunits.cpp index 9d1d83404c..4b905b8295 100644 --- a/src/qt/tapyrusunits.cpp +++ b/src/qt/tapyrusunits.cpp @@ -8,23 +8,24 @@ #include -BitcoinUnits::BitcoinUnits(QObject *parent): +TapyrusUnits::TapyrusUnits(QObject *parent): QAbstractListModel(parent), unitlist(availableUnits()) { } -QList BitcoinUnits::availableUnits() +QList TapyrusUnits::availableUnits() { - QList unitlist; + QList unitlist; unitlist.append(TPC); unitlist.append(mTPC); unitlist.append(uTPC); unitlist.append(TAP); + unitlist.append(TOKEN); return unitlist; } -bool BitcoinUnits::valid(int unit) +bool TapyrusUnits::valid(int unit) { switch(unit) { @@ -32,13 +33,14 @@ bool BitcoinUnits::valid(int unit) case mTPC: case uTPC: case TAP: + case TOKEN: return true; default: return false; } } -QString BitcoinUnits::longName(int unit) +QString TapyrusUnits::longName(int unit) { switch(unit) { @@ -46,21 +48,23 @@ QString BitcoinUnits::longName(int unit) case mTPC: return QString("mTPC"); case uTPC: return QString::fromUtf8("µTPC (tpcs)"); case TAP: return QString("Tapyrus (tap)"); + case TOKEN: return QString("TOKEN"); default: return QString("???"); } } -QString BitcoinUnits::shortName(int unit) +QString TapyrusUnits::shortName(int unit) { switch(unit) { case uTPC: return QString::fromUtf8("tpcs"); case TAP: return QString("tap"); + case TOKEN: return QString("token"); default: return longName(unit); } } -QString BitcoinUnits::description(int unit) +QString TapyrusUnits::description(int unit) { switch(unit) { @@ -68,35 +72,38 @@ QString BitcoinUnits::description(int unit) case mTPC: return QString("Milli-TPC (1 / 1" THIN_SP_UTF8 "000)"); case uTPC: return QString("Micro-TPC (tpcs) (1 / 1" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)"); case TAP: return QString("Tapyrus (tap) (1 / 100" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)"); + case TOKEN: return QString("Tapyrus token"); default: return QString("???"); } } -qint64 BitcoinUnits::factor(int unit) +qint64 TapyrusUnits::factor(int unit) { switch(unit) { case TPC: return 100000000; case mTPC: return 100000; case uTPC: return 100; - case TAP: return 1; + case TAP: + case TOKEN: return 1; default: return 100000000; } } -int BitcoinUnits::decimals(int unit) +int TapyrusUnits::decimals(int unit) { switch(unit) { case TPC: return 8; case mTPC: return 5; case uTPC: return 2; - case TAP: return 0; + case TAP: + case TOKEN: return 0; default: return 0; } } -QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators) +QString TapyrusUnits::format(int unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators) { // Note: not using straight sprintf here because we do NOT want // localized number formatting. @@ -140,12 +147,12 @@ QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, Separator // Please take care to use formatHtmlWithUnit instead, when // appropriate. -QString BitcoinUnits::formatWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators) +QString TapyrusUnits::formatWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators) { return format(unit, amount, plussign, separators) + QString(" ") + shortName(unit); } -QString BitcoinUnits::formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators) +QString TapyrusUnits::formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators) { QString str(formatWithUnit(unit, amount, plussign, separators)); str.replace(QChar(THIN_SP_CP), QString(THIN_SP_HTML)); @@ -153,7 +160,7 @@ QString BitcoinUnits::formatHtmlWithUnit(int unit, const CAmount& amount, bool p } -bool BitcoinUnits::parse(int unit, const QString &value, CAmount *val_out) +bool TapyrusUnits::parse(int unit, const QString &value, CAmount *val_out) { if(!valid(unit) || value.isEmpty()) return false; // Refuse to parse invalid unit or empty string @@ -192,23 +199,23 @@ bool BitcoinUnits::parse(int unit, const QString &value, CAmount *val_out) return ok; } -QString BitcoinUnits::getAmountColumnTitle(int unit) +QString TapyrusUnits::getAmountColumnTitle(int unit) { QString amountTitle = QObject::tr("Amount"); - if (BitcoinUnits::valid(unit)) + if (TapyrusUnits::valid(unit)) { - amountTitle += " ("+BitcoinUnits::shortName(unit) + ")"; + amountTitle += " ("+TapyrusUnits::shortName(unit) + ")"; } return amountTitle; } -int BitcoinUnits::rowCount(const QModelIndex &parent) const +int TapyrusUnits::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return unitlist.size(); } -QVariant BitcoinUnits::data(const QModelIndex &index, int role) const +QVariant TapyrusUnits::data(const QModelIndex &index, int role) const { int row = index.row(); if(row >= 0 && row < unitlist.size()) @@ -228,7 +235,7 @@ QVariant BitcoinUnits::data(const QModelIndex &index, int role) const return QVariant(); } -CAmount BitcoinUnits::maxMoney() +CAmount TapyrusUnits::maxMoney() { return MAX_MONEY; } diff --git a/src/qt/tapyrusunits.h b/src/qt/tapyrusunits.h index c0c4028b7f..673a64e604 100644 --- a/src/qt/tapyrusunits.h +++ b/src/qt/tapyrusunits.h @@ -44,14 +44,14 @@ /** Bitcoin unit definitions. Encapsulates parsing and formatting and serves as list model for drop-down selection boxes. */ -class BitcoinUnits: public QAbstractListModel +class TapyrusUnits: public QAbstractListModel { Q_OBJECT public: - explicit BitcoinUnits(QObject *parent); + explicit TapyrusUnits(QObject *parent); - /** Bitcoin units. + /** Tapyrus units. @note Source: https://en.bitcoin.it/wiki/Units . Please add only sensible ones */ enum Unit @@ -59,7 +59,8 @@ class BitcoinUnits: public QAbstractListModel TPC, mTPC, uTPC, - TAP + TAP, + TOKEN }; enum SeparatorStyle @@ -124,8 +125,8 @@ class BitcoinUnits: public QAbstractListModel static CAmount maxMoney(); private: - QList unitlist; + QList unitlist; }; -typedef BitcoinUnits::Unit BitcoinUnit; +typedef TapyrusUnits::Unit TapyrusUnit; #endif // TAPYRUS_QT_TAPYRUSUNITS_H diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 987cc69ad6..cf10a1cee6 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -188,7 +188,7 @@ void TestGUI() QString balanceText = balanceLabel->text(); int unit = walletModel.getOptionsModel()->getDisplayUnit(); CAmount balance = walletModel.wallet().getBalance(); - QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::separatorAlways); + QString balanceComparison = TapyrusUnits::formatWithUnit(unit, balance, false, TapyrusUnits::separatorAlways); QCOMPARE(balanceText, balanceComparison); // Check Request Payment button diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp index 35569149fc..2c7b8c9609 100644 --- a/src/qt/trafficgraphwidget.cpp +++ b/src/qt/trafficgraphwidget.cpp @@ -9,7 +9,7 @@ #include #include #include - +#include #include #define DESIRED_SAMPLES 800 diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 2a2461b19d..d9626e29e5 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -141,7 +141,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall nUnmatured += wallet.getCredit(txout, ISMINE_ALL); strHTML += "" + tr("Credit") + ": "; if (status.is_in_main_chain) - strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured); + strHTML += TapyrusUnits::formatHtmlWithUnit(unit, nUnmatured); else strHTML += "(" + tr("not accepted") + ")"; strHTML += "
"; @@ -151,7 +151,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall // // Credit // - strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, nNet) + "
"; + strHTML += "" + tr("Credit") + ": " + TapyrusUnits::formatHtmlWithUnit(unit, nNet) + "
"; } else { @@ -203,9 +203,9 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall } } - strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -txout.nValue) + "
"; + strHTML += "" + tr("Debit") + ": " + TapyrusUnits::formatHtmlWithUnit(unit, -txout.nValue) + "
"; if(toSelf) - strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, txout.nValue) + "
"; + strHTML += "" + tr("Credit") + ": " + TapyrusUnits::formatHtmlWithUnit(unit, txout.nValue) + "
"; } if (fAllToMe) @@ -213,13 +213,13 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall // Payment to self CAmount nChange = wtx.getChange(); CAmount nValue = nCredit - nChange; - strHTML += "" + tr("Total debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -nValue) + "
"; - strHTML += "" + tr("Total credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "
"; + strHTML += "" + tr("Total debit") + ": " + TapyrusUnits::formatHtmlWithUnit(unit, -nValue) + "
"; + strHTML += "" + tr("Total credit") + ": " + TapyrusUnits::formatHtmlWithUnit(unit, nValue) + "
"; } CAmount nTxFee = nDebit - wtx.tx->GetValueOut(ColorIdentifier()); if (nTxFee > 0) - strHTML += "" + tr("Transaction fee") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -nTxFee) + "
"; + strHTML += "" + tr("Transaction fee") + ": " + TapyrusUnits::formatHtmlWithUnit(unit, -nTxFee) + "
"; } else { @@ -229,19 +229,19 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall auto mine = wtx.txin_is_mine.begin(); for (const CTxIn& txin : wtx.tx->vin) { if (*(mine++)) { - strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin, ISMINE_ALL)) + "
"; + strHTML += "" + tr("Debit") + ": " + TapyrusUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin, ISMINE_ALL)) + "
"; } } mine = wtx.txout_is_mine.begin(); for (const CTxOut& txout : wtx.tx->vout) { if (*(mine++)) { - strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout, ISMINE_ALL)) + "
"; + strHTML += "" + tr("Credit") + ": " + TapyrusUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout, ISMINE_ALL)) + "
"; } } } } - strHTML += "" + tr("Net amount") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, nNet, true) + "
"; + strHTML += "" + tr("Net amount") + ": " + TapyrusUnits::formatHtmlWithUnit(unit, nNet, true) + "
"; // // Message @@ -274,10 +274,10 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall strHTML += "

" + tr("Debug information") + "

"; for (const CTxIn& txin : wtx.tx->vin) if(wallet.txinIsMine(txin)) - strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin, ISMINE_ALL)) + "
"; + strHTML += "" + tr("Debit") + ": " + TapyrusUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin, ISMINE_ALL)) + "
"; for (const CTxOut& txout : wtx.tx->vout) if(wallet.txoutIsMine(txout)) - strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout, ISMINE_ALL)) + "
"; + strHTML += "" + tr("Credit") + ": " + TapyrusUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout, ISMINE_ALL)) + "
"; strHTML += "
" + tr("Transaction") + ":
"; strHTML += GUIUtil::HtmlEscape(wtx.tx->ToString(), true); @@ -303,7 +303,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall strHTML += GUIUtil::HtmlEscape(name) + " "; strHTML += QString::fromStdString(EncodeDestination(address)); } - strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue); + strHTML = strHTML + " " + tr("Amount") + "=" + TapyrusUnits::formatHtmlWithUnit(unit, vout.nValue); strHTML = strHTML + " IsMine=" + (wallet.txoutIsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + ""; strHTML = strHTML + " IsWatchOnly=" + (wallet.txoutIsMine(vout) & ISMINE_WATCH_ONLY ? tr("true") : tr("false")) + ""; } diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index c2f3c61a9a..e787de0302 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -223,7 +223,7 @@ TransactionTableModel::TransactionTableModel(const PlatformStyle *_platformStyle fProcessingQueuedTransactions(false), platformStyle(_platformStyle) { - columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); + columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << TapyrusUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); priv->refreshWallet(walletModel->wallet()); connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); @@ -240,7 +240,7 @@ TransactionTableModel::~TransactionTableModel() /** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */ void TransactionTableModel::updateAmountColumnTitle() { - columns[Amount] = BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); + columns[Amount] = TapyrusUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); Q_EMIT headerDataChanged(Qt::Horizontal,Amount,Amount); } @@ -418,9 +418,9 @@ QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const return QVariant(); } -QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed, BitcoinUnits::SeparatorStyle separators) const +QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed, TapyrusUnits::SeparatorStyle separators) const { - QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit, false, separators); + QString str = TapyrusUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit, false, separators); if(showUnconfirmed) { if(!wtx->status.countsForBalance) @@ -515,7 +515,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const case ToAddress: return formatTxToAddress(rec, false); case Amount: - return formatTxAmount(rec, true, BitcoinUnits::separatorAlways); + return formatTxAmount(rec, true, TapyrusUnits::separatorAlways); } break; case Qt::EditRole: @@ -605,14 +605,14 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const details.append(QString::fromStdString(rec->address)); details.append(" "); } - details.append(formatTxAmount(rec, false, BitcoinUnits::separatorNever)); + details.append(formatTxAmount(rec, false, TapyrusUnits::separatorNever)); return details; } case ConfirmedRole: return rec->status.countsForBalance; case FormattedAmountRole: // Used for copy/export, so don't include separators - return formatTxAmount(rec, false, BitcoinUnits::separatorNever); + return formatTxAmount(rec, false, TapyrusUnits::separatorNever); case StatusRole: return rec->status.status; } @@ -736,8 +736,8 @@ static void ShowProgress(TransactionTableModel *ttm, const std::string &title, i void TransactionTableModel::subscribeToCoreSignals() { // Connect signals to wallet - m_handler_transaction_changed = walletModel->wallet().handleTransactionChanged(boost::bind(NotifyTransactionChanged, this, _1, _2)); - m_handler_show_progress = walletModel->wallet().handleShowProgress(boost::bind(ShowProgress, this, _1, _2)); + m_handler_transaction_changed = walletModel->wallet().handleTransactionChanged(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2)); + m_handler_show_progress = walletModel->wallet().handleShowProgress(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); } void TransactionTableModel::unsubscribeFromCoreSignals() diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index 3754ec37f1..74eb65e01f 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -101,7 +101,7 @@ class TransactionTableModel : public QAbstractTableModel QString formatTxDate(const TransactionRecord *wtx) const; QString formatTxType(const TransactionRecord *wtx) const; QString formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const; - QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true, BitcoinUnits::SeparatorStyle separators=BitcoinUnits::separatorStandard) const; + QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true, TapyrusUnits::SeparatorStyle separators=TapyrusUnits::separatorStandard) const; QString formatTooltip(const TransactionRecord *rec) const; QVariant txStatusDecoration(const TransactionRecord *wtx) const; QVariant txWatchonlyDecoration(const TransactionRecord *wtx) const; diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 0a2663274e..d91d4735cb 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -332,7 +332,7 @@ void TransactionView::changedAmount() if(!transactionProxyModel) return; CAmount amount_parsed = 0; - if (BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amountWidget->text(), &amount_parsed)) { + if (TapyrusUnits::parse(model->getOptionsModel()->getDisplayUnit(), amountWidget->text(), &amount_parsed)) { transactionProxyModel->setMinAmount(amount_parsed); } else @@ -366,7 +366,7 @@ void TransactionView::exportClicked() writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole); writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole); writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole); - writer.addColumn(BitcoinUnits::getAmountColumnTitle(model->getOptionsModel()->getDisplayUnit()), 0, TransactionTableModel::FormattedAmountRole); + writer.addColumn(TapyrusUnits::getAmountColumnTitle(model->getOptionsModel()->getDisplayUnit()), 0, TransactionTableModel::FormattedAmountRole); writer.addColumn(tr("ID"), 0, TransactionTableModel::TxHashRole); if(!writer.write()) { diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 3748ecbaf9..2a6075f465 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -389,10 +389,10 @@ void WalletModel::subscribeToCoreSignals() // Connect signals to wallet m_handler_unload = m_wallet->handleUnload(boost::bind(&NotifyUnload, this)); m_handler_status_changed = m_wallet->handleStatusChanged(boost::bind(&NotifyKeyStoreStatusChanged, this)); - m_handler_address_book_changed = m_wallet->handleAddressBookChanged(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5)); - m_handler_transaction_changed = m_wallet->handleTransactionChanged(boost::bind(NotifyTransactionChanged, this, _1, _2)); - m_handler_show_progress = m_wallet->handleShowProgress(boost::bind(ShowProgress, this, _1, _2)); - m_handler_watch_only_changed = m_wallet->handleWatchOnlyChanged(boost::bind(NotifyWatchonlyChanged, this, _1)); + m_handler_address_book_changed = m_wallet->handleAddressBookChanged(boost::bind(NotifyAddressBookChanged, this,boost::placeholders:: _1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5)); + m_handler_transaction_changed = m_wallet->handleTransactionChanged(boost::bind(NotifyTransactionChanged, this, boost::placeholders::_1, boost::placeholders::_2)); + m_handler_show_progress = m_wallet->handleShowProgress(boost::bind(ShowProgress, this, boost::placeholders::_1, boost::placeholders::_2)); + m_handler_watch_only_changed = m_wallet->handleWatchOnlyChanged(boost::bind(NotifyWatchonlyChanged, this, boost::placeholders::_1)); } void WalletModel::unsubscribeFromCoreSignals() @@ -483,15 +483,15 @@ bool WalletModel::bumpFee(uint256 hash) questionString.append(""); questionString.append(tr("Current fee:")); questionString.append(""); - questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), old_fee)); + questionString.append(TapyrusUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), old_fee)); questionString.append(""); questionString.append(tr("Increase:")); questionString.append(""); - questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), new_fee - old_fee)); + questionString.append(TapyrusUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), new_fee - old_fee)); questionString.append(""); questionString.append(tr("New fee:")); questionString.append(""); - questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), new_fee)); + questionString.append(TapyrusUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), new_fee)); questionString.append(""); SendConfirmationDialog confirmationDialog(tr("Confirm fee bump"), questionString); confirmationDialog.exec(); From 83d6c7e72ee4b7d56723595cfd6809c20204bfa0 Mon Sep 17 00:00:00 2001 From: Navia Bheeman Date: Tue, 14 Jun 2022 20:08:29 +0530 Subject: [PATCH 04/11] Overview page with colored coin support --- doc/tapyrus/colored_coin_gui.md | 8 + doc/tapyrus/images/Tapyrus-overview-token.png | Bin 0 -> 195580 bytes src/interfaces/wallet.cpp | 6 +- src/interfaces/wallet.h | 70 +++++- src/key_io.cpp | 18 ++ src/key_io.h | 1 + src/qt/forms/overviewpage.ui | 213 ++++++++++++------ src/qt/overviewpage.cpp | 43 +++- src/qt/overviewpage.h | 7 + src/qt/walletmodel.cpp | 12 + src/qt/walletmodel.h | 4 + 11 files changed, 292 insertions(+), 90 deletions(-) create mode 100644 doc/tapyrus/colored_coin_gui.md create mode 100644 doc/tapyrus/images/Tapyrus-overview-token.png diff --git a/doc/tapyrus/colored_coin_gui.md b/doc/tapyrus/colored_coin_gui.md new file mode 100644 index 0000000000..0b979dd5c8 --- /dev/null +++ b/doc/tapyrus/colored_coin_gui.md @@ -0,0 +1,8 @@ +## Tapyrus core GUI + + Tapyrus GUI has been enhanced to allow Token transactions. Following are the changes made + + ### Overview Page + Overview in the new Tapyrus GUI shows tokens as well. TPC is in view when the gui starts. _Prev_ and _Next_ buttons can be used to scroll through all the available tokens. When no other tokens are available only TPC is visible. + + ![Overview Page with token](./images/Tapyrus-overview-token.png) \ No newline at end of file diff --git a/doc/tapyrus/images/Tapyrus-overview-token.png b/doc/tapyrus/images/Tapyrus-overview-token.png new file mode 100644 index 0000000000000000000000000000000000000000..9e60ece5246ba032027587d394620a1b7eea24d5 GIT binary patch literal 195580 zcma%i1zeQP_Wu$JN`ruaw2Fd&bhAi@uyl8KcP)r?2}s8xNJ@7jjf8YJNO#A=?ti`a zzP{dj-~0al8=sw>XU@z#GiPSb`JV3+DlaF2^^o)-006*}k`z@00Pev6091PP`-mJO zYFi!v0Mpt+L_}UnM1)G-(azMu+5`ZQ42@SqQ&##$nxPf@;lnU8-Uob70#QrAOX@0g zWW{@A)DND1d`$2zgj`42exD|cP=`>#+2x+G0v<+AGg{eserFsCpi`TfDq|LOV14D(9JhR z%mGNkP2!0 zCtrz=QE?fJC}UFjR6_fyYl3eSLk#%+;$e}41FbV4%8H>i6Kn$&U6d?5ngkgqcQ)A2 z=&jwiK?Tg4vcO3CSh3ERr@c9r~K+Bl>I{=0=o*%WgOQ7t_`)s3~j4ODF+CiiRSMFq_3Xd zUk$F;PYlF&UCku_08X#ab6jLI4mNID4}DQ&$Z;m_Em90_Z}7%FoQQ{S1b+Z=$_w+@dLKU?q)dvz z$`DS&pm~FRTl_fb8OcckYKD;bEzTkT^wsOdC(|F-;2D(0t*q9)q6H*fnG(4dna^21 zJ{FFk3c@3|H{u6ec4RNJp>uMj1wt`5j#VH>ABV-=MeF3u>E<(Nm|}g1*VTuy_k#

ql3e=vPPamsQ^ZVFUb&TsH0!*R_aSK6$% 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%0D5XZ!+1Ajg#$5&1_kE_iYkVoP3o5r84!I~S)>#m0 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 literal 0 HcmV?d00001 diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index ef6d0a1b80..886ec04d96 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -358,10 +358,10 @@ class WalletImpl : public Wallet num_blocks = ::chainActive.Height(); return true; } - CAmount getBalance() override { return m_wallet.GetBalance()[ColorIdentifier()]; } - CAmount getAvailableBalance(const CCoinControl& coin_control) override + CAmount getBalance(ColorIdentifier colorId) override { return m_wallet.GetBalance()[colorId]; } + CAmount getAvailableBalance(const CCoinControl& coin_control, ColorIdentifier colorId) override { - return m_wallet.GetAvailableBalance(&coin_control)[ColorIdentifier()]; + return m_wallet.GetAvailableBalance(&coin_control)[colorId]; } isminetype txinIsMine(const CTxIn& txin) override { diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 7a1c3efec5..91fa6e9fe6 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -192,10 +192,10 @@ class Wallet virtual bool tryGetBalances(WalletBalances& balances, int& num_blocks) = 0; //! Get balance. - virtual CAmount getBalance() = 0; + virtual CAmount getBalance(ColorIdentifier colorId = ColorIdentifier()) = 0; //! Get available balance. - virtual CAmount getAvailableBalance(const CCoinControl& coin_control) = 0; + virtual CAmount getAvailableBalance(const CCoinControl& coin_control, ColorIdentifier colorId = ColorIdentifier()) = 0; //! Return whether transaction input belongs to wallet. virtual isminetype txinIsMine(const CTxIn& txin) = 0; @@ -311,32 +311,35 @@ struct WalletBalances bool have_watch_only; TxColoredCoinBalancesMap watch_only_balances; TxColoredCoinBalancesMap unconfirmed_watch_only_balances; + std::set tokens; + std::set::iterator tokenIndex; WalletBalances(){ have_watch_only = false; + tokenIndex = tokens.begin(); } - CAmount getBalance(const ColorIdentifier& colorId = ColorIdentifier()) const + CAmount getBalance() const { - auto it = balances.find(colorId); + auto it = balances.find(*tokenIndex); return it != balances.end() ? it->second : 0; } - CAmount getUnconfirmedBalance(const ColorIdentifier& colorId = ColorIdentifier()) const + CAmount getUnconfirmedBalance() const { - auto it = unconfirmed_balances.find(colorId); + auto it = unconfirmed_balances.find(*tokenIndex); return it != unconfirmed_balances.end() ? it->second : 0; } - CAmount getWatchOnlyBalance(const ColorIdentifier& colorId = ColorIdentifier()) const + CAmount getWatchOnlyBalance() const { - auto it = watch_only_balances.find(colorId); + auto it = watch_only_balances.find(*tokenIndex); return it != watch_only_balances.end() ? it->second : 0; } - CAmount getUnconfirmedWatchOnlyBalance(const ColorIdentifier& colorId = ColorIdentifier()) const + CAmount getUnconfirmedWatchOnlyBalance() const { - auto it = unconfirmed_watch_only_balances.find(colorId); + auto it = unconfirmed_watch_only_balances.find(*tokenIndex); return it != unconfirmed_watch_only_balances.end() ? it->second : 0; } @@ -346,6 +349,53 @@ struct WalletBalances watch_only_balances != prev.watch_only_balances || unconfirmed_watch_only_balances != prev.unconfirmed_watch_only_balances; } + + //collect all tokens in the wallet from all the balance lists + void refreshTokens() { + tokens.clear(); + + for(auto pair:balances) + tokens.insert(pair.first); + for(auto pair:unconfirmed_balances) + tokens.insert(pair.first); + for(auto pair:watch_only_balances) + tokens.insert(pair.first); + for(auto pair:unconfirmed_watch_only_balances) + tokens.insert(pair.first); + + tokenIndex = tokens.begin(); + } + + void prev() + { + if(tokenIndex != tokens.begin()) + tokenIndex--; + else + { + tokenIndex = tokens.end(); + tokenIndex--; + } + } + + void next() + { + if(tokenIndex != tokens.end()) + { + tokenIndex++; + if(tokenIndex == tokens.end()) + tokenIndex = tokens.begin(); + } + } + + bool isToken() + { + return (*tokenIndex).type != TokenTypes::NONE; + } + + std::string getTokenName() + { + return (*tokenIndex).toHexString(); + } }; // Wallet transaction information. diff --git a/src/key_io.cpp b/src/key_io.cpp index 2f4b76d6bc..f8c9d489a6 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -213,3 +213,21 @@ bool IsValidDestinationString(const std::string& str) { return IsValidDestinationString(str, Params()); } + +bool IsColoredDestination(const std::string& str, ColorIdentifier* colorId) +{ + CTxDestination dest = DecodeDestination(str, Params()); + if(dest.which() == 3) + { + if(colorId) + *colorId = boost::get(dest).color; + return true; + } + else if(dest.which() == 4) + { + if(colorId) + *colorId = boost::get(dest).color; + return true; + } + return false; +} \ No newline at end of file diff --git a/src/key_io.h b/src/key_io.h index d80c08f49c..eba5c58ce7 100644 --- a/src/key_io.h +++ b/src/key_io.h @@ -25,5 +25,6 @@ std::string EncodeDestination(const CTxDestination& dest); CTxDestination DecodeDestination(const std::string& str); bool IsValidDestinationString(const std::string& str); bool IsValidDestinationString(const std::string& str, const CChainParams& params); +bool IsColoredDestination(const std::string& str, ColorIdentifier* colorId); #endif // BITCOIN_KEY_IO_H diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index d311344bd4..11ab97b9c8 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -114,9 +114,19 @@ 12 - - - + + + + Token: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 75 true @@ -126,10 +136,10 @@ IBeamCursor - Unconfirmed transactions to watch-only addresses + Color of the Token or TPC - 0.000 000 00 TPC + TPC Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -139,8 +149,25 @@ - - + + + + Watch-only: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Available: + + + + + 75 @@ -151,7 +178,7 @@ IBeamCursor - Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance + Your current spendable balance 0.000 000 00 TPC @@ -164,54 +191,33 @@ - - - - Qt::Horizontal - - - - - - - - 0 - 0 - + + + + + 75 + true + - - - 140 - 0 - + + IBeamCursor - - Qt::Horizontal + + Your current balance in watch-only addresses - - - - - Total: + 0.000 000 00 TPC - - - - - - Qt::Horizontal + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 40 - 20 - + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - + - - + + 75 @@ -222,7 +228,7 @@ IBeamCursor - Your current total balance + Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance 0.000 000 00 TPC @@ -235,8 +241,8 @@ - - + + 75 @@ -247,7 +253,7 @@ IBeamCursor - Current total balance in watch-only addresses + Unconfirmed transactions to watch-only addresses 0.000 000 00 TPC @@ -260,25 +266,54 @@ - - - - Watch-only: + + + + Qt::Horizontal - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 40 + 20 + + + + + + + + Qt::Horizontal - - + + + + + 0 + 0 + + + + + 140 + 0 + + + + Qt::Horizontal + + + + + - Available: + Total: - - + + 75 @@ -289,7 +324,7 @@ IBeamCursor - Your current spendable balance + Your current total balance 0.000 000 00 TPC @@ -302,8 +337,8 @@ - - + + 75 @@ -314,7 +349,7 @@ IBeamCursor - Your current balance in watch-only addresses + Current total balance in watch-only addresses 0.000 000 00 TPC @@ -327,6 +362,50 @@ + + + + true + + + + 300 + 16777215 + + + + Click to view next token balance. + + + Prev + + + false + + + + + + + true + + + + 300 + 16777215 + + + + Click to view next token balance. + + + Next + + + false + + + diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index dc0b490cb6..9679842f49 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -14,7 +14,6 @@ #include #include #include - #include #include @@ -119,8 +118,6 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) { ui->setupUi(this); - m_balances.balances[ColorIdentifier()] = -1; - // use a SingleColorIcon for the "out of sync warning" icon QIcon icon = platformStyle->SingleColorIcon(":/icons/warning"); icon.addPixmap(icon.pixmap(QSize(64,64), QIcon::Normal), QIcon::Disabled); // also set the disabled icon because we are using a disabled QPushButton to work around missing HiDPI support of QLabel (https://bugreports.qt.io/browse/QTBUG-42503) @@ -139,6 +136,9 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) showOutOfSyncWarning(true); connect(ui->labelWalletStatus, SIGNAL(clicked()), this, SLOT(handleOutOfSyncWarningClicks())); connect(ui->labelTransactionsStatus, SIGNAL(clicked()), this, SLOT(handleOutOfSyncWarningClicks())); + connect(ui->nextButton, SIGNAL(clicked()), this, SLOT(next())); + connect(ui->prevButton, SIGNAL(clicked()), this, SLOT(prev())); + } void OverviewPage::handleTransactionClicked(const QModelIndex &index) @@ -157,24 +157,46 @@ OverviewPage::~OverviewPage() delete ui; } -void OverviewPage::setBalance(const interfaces::WalletBalances& balances) +void OverviewPage::updateBalances() { int unit = walletModel->getOptionsModel()->getDisplayUnit(); - m_balances = balances; + CAmount balance = m_balances.getBalance(); + CAmount unconfirmed_balance = m_balances.getUnconfirmedBalance(); + CAmount watch_only_balance = m_balances.getWatchOnlyBalance(); + CAmount unconfirmed_watch_only_balance = m_balances.getUnconfirmedWatchOnlyBalance(); - CAmount balance = balances.getBalance(); - CAmount unconfirmed_balance = balances.getUnconfirmedBalance(); - CAmount watch_only_balance = balances.getWatchOnlyBalance(); - CAmount unconfirmed_watch_only_balance = balances.getUnconfirmedWatchOnlyBalance(); + if(m_balances.isToken()) + unit = TapyrusUnits::TOKEN; + ui->labelTokenName->setText(QString(m_balances.getTokenName().c_str())); ui->labelBalance->setText(TapyrusUnits::formatWithUnit(unit, balance, false, TapyrusUnits::separatorAlways)); - ui->labelUnconfirmed->setText(TapyrusUnits::formatWithUnit(unit, balance, false, TapyrusUnits::separatorAlways)); + ui->labelUnconfirmed->setText(TapyrusUnits::formatWithUnit(unit, unconfirmed_balance, false, TapyrusUnits::separatorAlways)); ui->labelTotal->setText(TapyrusUnits::formatWithUnit(unit, balance + unconfirmed_balance, false, TapyrusUnits::separatorAlways)); ui->labelWatchAvailable->setText(TapyrusUnits::formatWithUnit(unit, watch_only_balance, false, TapyrusUnits::separatorAlways)); ui->labelWatchPending->setText(TapyrusUnits::formatWithUnit(unit, unconfirmed_watch_only_balance, false, TapyrusUnits::separatorAlways)); ui->labelWatchTotal->setText(TapyrusUnits::formatWithUnit(unit, watch_only_balance + unconfirmed_watch_only_balance, false, TapyrusUnits::separatorAlways)); } +void OverviewPage::prev() +{ + m_balances.prev(); + updateBalances(); +} + +void OverviewPage::next() +{ + m_balances.next(); + updateBalances(); +} + +void OverviewPage::setBalance(const interfaces::WalletBalances& balances) +{ + m_balances = balances; + m_balances.refreshTokens(); + + updateBalances(); +} + // show/hide watch-only labels void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly) { @@ -236,6 +258,7 @@ void OverviewPage::updateDisplayUnit() { if (m_balances.getBalance() != -1) { setBalance(m_balances); + m_balances.refreshTokens(); } // Update txdelegate->unit with the current unit diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 75100ae6f7..2857b071db 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -36,9 +36,12 @@ class OverviewPage : public QWidget void setClientModel(ClientModel *clientModel); void setWalletModel(WalletModel *walletModel); void showOutOfSyncWarning(bool fShow); + void updateBalances(); public Q_SLOTS: void setBalance(const interfaces::WalletBalances& balances); + void prev(); + void next(); Q_SIGNALS: void transactionClicked(const QModelIndex &index); @@ -53,6 +56,10 @@ public Q_SLOTS: TxViewDelegate *txdelegate; std::unique_ptr filter; + //list of tokens in the wallet for easy display. + std::set m_tokens; + std::set::iterator m_index; + private Q_SLOTS: void updateDisplayUnit(); void handleTransactionClicked(const QModelIndex &index); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 2a6075f465..8638c63f9d 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -125,6 +125,18 @@ bool WalletModel::validateAddress(const QString &address) return IsValidDestinationString(address.toStdString()); } +bool WalletModel::isColoredAddress(const QString &address) +{ + return IsColoredDestination(address.toStdString(), nullptr); +} + +ColorIdentifier WalletModel::getColorFromAddress(const QString &address) +{ + ColorIdentifier colorId; + if(IsColoredDestination(address.toStdString(), &colorId)) + return colorId; +} + WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl) { CAmount total = 0; diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 0579b372b0..e5a17542d2 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -139,6 +139,10 @@ class WalletModel : public QObject // Check address for validity bool validateAddress(const QString &address); + //check if the address is a token + bool isColoredAddress(const QString &address); + ColorIdentifier getColorFromAddress(const QString &address); + // Return status record for SendCoins, contains error id + information struct SendCoinsReturn { From 4e2c5ce5991d99c6c4c227497de0fa04ae26d804 Mon Sep 17 00:00:00 2001 From: Navia Bheeman Date: Tue, 14 Jun 2022 23:53:29 +0530 Subject: [PATCH 05/11] added support to send colored coins from gui --- doc/tapyrus/colored_coin_gui.md | 10 +++++- doc/tapyrus/images/Tapyrus-send-token.png | Bin 0 -> 192807 bytes src/qt/forms/sendcoinsentry.ui | 39 +++++++++++++++++++--- src/qt/sendcoinsdialog.cpp | 8 ++--- src/qt/sendcoinsentry.cpp | 26 +++++++++++++++ src/qt/sendcoinsentry.h | 1 + src/qt/walletmodel.cpp | 7 ++++ src/qt/walletmodel.h | 8 +++-- 8 files changed, 86 insertions(+), 13 deletions(-) create mode 100644 doc/tapyrus/images/Tapyrus-send-token.png diff --git a/doc/tapyrus/colored_coin_gui.md b/doc/tapyrus/colored_coin_gui.md index 0b979dd5c8..a82d5ec473 100644 --- a/doc/tapyrus/colored_coin_gui.md +++ b/doc/tapyrus/colored_coin_gui.md @@ -5,4 +5,12 @@ ### Overview Page Overview in the new Tapyrus GUI shows tokens as well. TPC is in view when the gui starts. _Prev_ and _Next_ buttons can be used to scroll through all the available tokens. When no other tokens are available only TPC is visible. - ![Overview Page with token](./images/Tapyrus-overview-token.png) \ No newline at end of file + ![Overview Page with token](./images/Tapyrus-overview-token.png) + + ### Send Token + Sending a token is the same as sending TPC except that the new address must have been generated with the colorid + + > ./src/tapyrus-cli -conf=~/.tapyrus/ getnewaddress "NFT" c3b8b7e3a2684c746d367420bd0899104005cfeeb59705a3f402fa37312f402624 + Then the token lable would be populated automatically and "TOKEN" would be set in the token type drop down. + ![Send coin page with token](./images/Tapyrus-send-token.png) + \ No newline at end of file diff --git a/doc/tapyrus/images/Tapyrus-send-token.png b/doc/tapyrus/images/Tapyrus-send-token.png new file mode 100644 index 0000000000000000000000000000000000000000..8ce67bfbcc93f190dbd14fff654ecd2f0d904ba7 GIT binary patch literal 192807 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 literal 0 HcmV?d00001 diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui index a216fa5251..e8ed3fe6e1 100644 --- a/src/qt/forms/sendcoinsentry.ui +++ b/src/qt/forms/sendcoinsentry.ui @@ -150,6 +150,35 @@ + + + &Token: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + labelTokenName + + + + + + + & + + + Qt::AlignLeft|Qt::AlignTrailing|Qt::AlignVCenter + + + labelToken + + + Token type of the address + + + + A&mount: @@ -162,7 +191,7 @@ - + @@ -173,7 +202,7 @@ The fee will be deducted from the amount being sent. The recipient will receive less tpc than you enter in the amount field. If multiple recipients are selected, the fee is split equally. - S&ubtract fee from amount + Subtract fee from amount @@ -186,7 +215,7 @@ - + Message: @@ -196,7 +225,7 @@ - + A message that was attached to the tapyrus coin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Tapyrus network. @@ -206,7 +235,7 @@ - + Qt::Horizontal diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 2bf685df19..9d6f69de00 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -283,7 +283,7 @@ void SendCoinsDialog::on_sendButton_clicked() for (const SendCoinsRecipient &rcp : currentTransaction.getRecipients()) { // generate bold amount string with wallet name in case of multiwallet - QString amount = "" + TapyrusUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount); + QString amount = "" + model->isColoredAddress(rcp.address) ? TapyrusUnits::formatHtmlWithUnit(TapyrusUnits::TOKEN, rcp.amount) : TapyrusUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount); if (model->isMultiwallet()) { amount.append(" "+tr("from wallet %1").arg(GUIUtil::HtmlEscape(model->getWalletName()))+" "); } @@ -613,8 +613,8 @@ void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry) coin_control = *CoinControlDialog::coinControl(); } - // Calculate available amount to send. - CAmount amount = model->wallet().getAvailableBalance(coin_control); + // get available amount to send from the entry + CAmount amount = entry->getAvailableBalance(coin_control); for (int i = 0; i < ui->entries->count(); ++i) { SendCoinsEntry* e = qobject_cast(ui->entries->itemAt(i)->widget()); if (e && !e->isHidden() && e != entry) { @@ -623,7 +623,7 @@ void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry) } if (amount > 0) { - entry->checkSubtractFeeFromAmount(); + //entry->checkSubtractFeeFromAmount(); entry->setAmount(amount); } else { entry->setAmount(0); diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index d56656362c..1abad64f42 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -79,6 +80,23 @@ void SendCoinsEntry::on_addressBookButton_clicked() void SendCoinsEntry::on_payTo_textChanged(const QString &address) { updateLabel(address); + if(model && model->isColoredAddress(address)) + { + //unit is TOKEN + ui->payAmount->setDisplayUnit(TapyrusUnits::TOKEN); + ui->payAmount_is->setDisplayUnit(TapyrusUnits::TOKEN); + ui->payAmount_s->setDisplayUnit(TapyrusUnits::TOKEN); + ui->labelTokenName->setText(model->getColorFromAddress(address).toHexString().c_str()); + ui->checkboxSubtractFeeFromAmount->setEnabled(false); + ui->checkboxSubtractFeeFromAmount->setCheckState(Qt::Unchecked); + } + else + { + updateDisplayUnit(); + ui->labelTokenName->clear(); + ui->checkboxSubtractFeeFromAmount->setEnabled(true); + ui->checkboxSubtractFeeFromAmount->setCheckState(Qt::Unchecked); + } } void SendCoinsEntry::setModel(WalletModel *_model) @@ -96,6 +114,7 @@ void SendCoinsEntry::clear() // clear UI elements for normal payment ui->payTo->clear(); ui->addAsLabel->clear(); + ui->labelTokenName->clear(); ui->payAmount->clear(); ui->checkboxSubtractFeeFromAmount->setCheckState(Qt::Unchecked); ui->messageTextLabel->clear(); @@ -252,3 +271,10 @@ bool SendCoinsEntry::updateLabel(const QString &address) return false; } + +CAmount SendCoinsEntry::getAvailableBalance(CCoinControl& coin_control) +{ + const QString address = ui->payTo->text(); + ColorIdentifier colorId = model->getColorFromAddress(address); + return model->wallet().getAvailableBalance(coin_control, colorId); +} \ No newline at end of file diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h index 582516bac2..cf0ce90110 100644 --- a/src/qt/sendcoinsentry.h +++ b/src/qt/sendcoinsentry.h @@ -32,6 +32,7 @@ class SendCoinsEntry : public QStackedWidget void setModel(WalletModel *model); bool validate(interfaces::Node& node); SendCoinsRecipient getValue(); + CAmount getAvailableBalance(CCoinControl& coin_control); /** Return whether the entry is still empty and unedited */ bool isClear(); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 8638c63f9d..4134607d99 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -554,3 +554,10 @@ bool WalletModel::isMultiwallet() { return m_node.getWallets().size() > 1; } + +//Constructor definition moved here to initialize colorid +SendCoinsRecipient::SendCoinsRecipient(const QString &addr, const QString &_label, const CAmount& _amount, const QString &_message): + address(addr), label(_label), amount(_amount), message(_message), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) + { + IsColoredDestination(address.toStdString(), &colorid); + } \ No newline at end of file diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index e5a17542d2..129deac7cc 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -51,9 +51,9 @@ QT_END_NAMESPACE class SendCoinsRecipient { public: - explicit SendCoinsRecipient() : amount(0), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) { } - explicit SendCoinsRecipient(const QString &addr, const QString &_label, const CAmount& _amount, const QString &_message): - address(addr), label(_label), amount(_amount), message(_message), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) {} + explicit SendCoinsRecipient() : amount(0), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION), colorid() { } + //only decleration is here + explicit SendCoinsRecipient(const QString &addr, const QString &_label, const CAmount& _amount, const QString &_message); // If from an unauthenticated payment request, this is used for storing // the addresses, e.g. address-A
address-B
address-C. @@ -62,6 +62,7 @@ class SendCoinsRecipient // Todo: This is a hack, should be replaced with a cleaner solution! QString address; QString label; + ColorIdentifier colorid; CAmount amount; // If from a payment request, this is used for storing the memo QString message; @@ -86,6 +87,7 @@ class SendCoinsRecipient READWRITE(this->nVersion); READWRITE(sAddress); READWRITE(sLabel); + READWRITE(colorid); READWRITE(amount); READWRITE(sMessage); READWRITE(sPaymentRequest); From 83615696fb22b0fa4bb02851447c1c3500a58ddd Mon Sep 17 00:00:00 2001 From: Navia Bheeman Date: Wed, 15 Jun 2022 00:23:24 +0530 Subject: [PATCH 06/11] receive coins dialog with colored coin support using a new address type --- src/outputtype.cpp | 7 ++- src/outputtype.h | 6 +-- src/qt/addresstablemodel.cpp | 5 +- src/qt/addresstablemodel.h | 2 +- src/qt/editaddressdialog.cpp | 2 +- src/qt/forms/receivecoinsdialog.ui | 80 +++++++++++++++++++---------- src/qt/receivecoinsdialog.cpp | 10 ++-- src/qt/receiverequestdialog.cpp | 4 +- src/qt/recentrequeststablemodel.cpp | 15 +++--- src/qt/recentrequeststablemodel.h | 3 +- src/qt/test/addressbooktests.cpp | 2 +- src/qt/test/wallettests.cpp | 2 +- src/rpc/misc.cpp | 2 +- src/script/standard.cpp | 1 + src/script/standard.h | 1 + src/wallet/rpcdump.cpp | 2 +- src/wallet/rpcwallet.cpp | 6 +-- src/wallet/wallet.cpp | 8 +-- 18 files changed, 98 insertions(+), 60 deletions(-) diff --git a/src/outputtype.cpp b/src/outputtype.cpp index a6ad092812..0e367a5dbd 100644 --- a/src/outputtype.cpp +++ b/src/outputtype.cpp @@ -15,11 +15,12 @@ #include -CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type) +CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type, const ColorIdentifier& colorId) { switch (type) { case OutputType::CHANGE_AUTO: case OutputType::LEGACY: return key.GetID(); + case OutputType::TOKEN: return CColorKeyID(key.GetID(), colorId); default: assert(false); } } @@ -35,7 +36,7 @@ std::vector GetAllDestinationsForKey(const CPubKey& key) } } -CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript& script, OutputType type) +CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript& script, OutputType type, const ColorIdentifier& colorId) { // Add script to keystore keystore.AddCScript(script); @@ -43,6 +44,8 @@ CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript& switch (type) { case OutputType::LEGACY: return CScriptID(script); + case OutputType::TOKEN: + return CColorScriptID(script, colorId); default: assert(false); } } diff --git a/src/outputtype.h b/src/outputtype.h index 0dcf0b3367..69957d7eb1 100644 --- a/src/outputtype.h +++ b/src/outputtype.h @@ -14,14 +14,14 @@ enum class OutputType { LEGACY, - + TOKEN, CHANGE_AUTO, }; /** * Get a destination of the requested type (if possible) to the specified key. */ -CTxDestination GetDestinationForKey(const CPubKey& key, OutputType); +CTxDestination GetDestinationForKey(const CPubKey& key, OutputType, const ColorIdentifier& colorId); /** Get all destinations (potentially) supported by the wallet for the given key. */ std::vector GetAllDestinationsForKey(const CPubKey& key); @@ -31,7 +31,7 @@ std::vector GetAllDestinationsForKey(const CPubKey& key); * This function will automatically add the script (and any other * necessary scripts) to the keystore. */ -CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript& script, OutputType); +CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript& script, OutputType, const ColorIdentifier& colorId); #endif // BITCOIN_OUTPUTTYPE_H diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index ac500bd5ad..036d106908 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -336,7 +336,7 @@ void AddressTableModel::updateEntry(const QString &address, priv->updateEntry(address, label, isMine, purpose, status); } -QString AddressTableModel::addRow(const QString &type, const QString &label, const QString &address, const OutputType address_type) +QString AddressTableModel::addRow(const QString &type, const QString &label, const QString &address, const QString &colorin, const OutputType address_type) { std::string strLabel = label.toStdString(); std::string strAddress = address.toStdString(); @@ -363,6 +363,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con else if(type == Receive) { // Generate a new address to associate with given label + ColorIdentifier colorId(ParseHex(colorin.toStdString().c_str())); CPubKey newKey; if(!walletModel->wallet().getKeyFromPool(false /* internal */, newKey)) { @@ -379,7 +380,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con return QString(); } } - strAddress = EncodeDestination(GetDestinationForKey(newKey, address_type)); + strAddress = EncodeDestination(GetDestinationForKey(newKey, address_type, colorId)); } else { diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index 41bed4e290..6e3176d5a8 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -65,7 +65,7 @@ class AddressTableModel : public QAbstractTableModel /* Add an address to the model. Returns the added address on success, and an empty string otherwise. */ - QString addRow(const QString &type, const QString &label, const QString &address, const OutputType address_type); + QString addRow(const QString &type, const QString &label, const QString &address, const QString &colorid, const OutputType address_type); /** Look up label for address in address book, if not found return empty string. */ QString labelForAddress(const QString &address) const; diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index 613733dda4..0de6e95cbf 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -78,7 +78,7 @@ bool EditAddressDialog::saveCurrentRow() address = model->addRow( AddressTableModel::Send, ui->labelEdit->text(), - ui->addressEdit->text(), + ui->addressEdit->text(), "", model->GetDefaultAddressType()); break; case EditReceivingAddress: diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui index d02f2615c1..176639c97e 100644 --- a/src/qt/forms/receivecoinsdialog.ui +++ b/src/qt/forms/receivecoinsdialog.ui @@ -28,6 +28,36 @@ + + + + Use this form to request payments. All fields are <b>optional</b>. + + + + + + + An optional label to associate with the new receiving address. + + + &Label: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + reqLabel + + + + + + + An optional label to associate with the new receiving address. + + + @@ -45,59 +75,59 @@ - + - An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Tapyrus network. + A token name/color to receive tokens with the new receiving address. - &Message: + &Token: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - reqMessage + tokenName - - + + - An optional label to associate with the new receiving address. - - - - - - - Use this form to request payments. All fields are <b>optional</b>. + A token name/color to receive tokens with the new receiving address. - - + + - An optional label to associate with the new receiving address. + An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Tapyrus network. - &Label: + &Message: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - reqLabel + reqMessage - + An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Tapyrus network. - + + + + + + + + @@ -154,13 +184,7 @@ - - - - - - - + diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index aca9f1a9e6..03344ba904 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -110,6 +110,7 @@ void ReceiveCoinsDialog::clear() ui->reqAmount->clear(); ui->reqLabel->setText(""); ui->reqMessage->setText(""); + ui->tokenName->setText(""); updateDisplayUnit(); } @@ -138,12 +139,13 @@ void ReceiveCoinsDialog::on_receiveButton_clicked() QString address; QString label = ui->reqLabel->text(); + const ColorIdentifier colorid(ParseHex(ui->tokenName->text().toStdString().c_str())); /* Generate new receiving address */ - OutputType address_type = model->wallet().getDefaultAddressType(); + OutputType address_type = ui->tokenName->text().isEmpty() ? model->wallet().getDefaultAddressType() : OutputType::TOKEN; - address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", address_type); - SendCoinsRecipient info(address, label, - ui->reqAmount->value(), ui->reqMessage->text()); + address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", ui->tokenName->text(), address_type); + SendCoinsRecipient info(address, label, ui->reqAmount->value(), ui->reqMessage->text()); + info.colorid = colorid; ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setModel(model); diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index 02c5563257..346c24c00b 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -139,8 +139,10 @@ void ReceiveRequestDialog::update() html += ""+tr("URI")+": "; html += "
" + GUIUtil::HtmlEscape(uri) + "
"; html += ""+tr("Address")+": " + GUIUtil::HtmlEscape(info.address) + "
"; + if(info.colorid.type != TokenTypes::NONE) + html += ""+tr("Token")+": " + info.colorid.toHexString().c_str() + "
"; if(info.amount) - html += ""+tr("Amount")+": " + TapyrusUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), info.amount) + "
"; + html += ""+tr("Amount")+": " + ((info.colorid.type != TokenTypes::NONE) ?TapyrusUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), info.amount):TapyrusUnits::formatHtmlWithUnit(TapyrusUnits::TOKEN, info.amount) )+ "
"; if(!info.label.isEmpty()) html += ""+tr("Label")+": " + GUIUtil::HtmlEscape(info.label) + "
"; if(!info.message.isEmpty()) diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 732ff944d0..ab226fa7c3 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -18,16 +18,14 @@ RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) : nReceiveRequestsMaxId = 0; // Load entries from wallet - std::vector vReceiveRequests; - parent->loadReceiveRequests(vReceiveRequests); + std::vector vReceiveRequests; for (const std::string& request : vReceiveRequests) addNewRequest(request); /* These columns must match the indices in the ColumnIndex enumeration */ - columns << tr("Date") << tr("Label") << tr("Message") << getAmountTitle(); - - connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); -} + columns << tr("Date") << tr("Label") << tr("Message") << tr("Token") << getAmountTitle(); + ; +} RecentRequestsTableModel::~RecentRequestsTableModel() { @@ -78,6 +76,9 @@ QVariant RecentRequestsTableModel::data(const QModelIndex &index, int role) cons { return rec->recipient.message; } + case Token: + return QVariant(rec->recipient.colorid.toHexString().c_str()); + case Amount: if (rec->recipient.amount == 0 && role == Qt::DisplayRole) return tr("(no amount requested)"); @@ -228,6 +229,8 @@ bool RecentRequestEntryLessThan::operator()(RecentRequestEntry &left, RecentRequ return pLeft->recipient.label < pRight->recipient.label; case RecentRequestsTableModel::Message: return pLeft->recipient.message < pRight->recipient.message; + case RecentRequestsTableModel::Token: + return pLeft->recipient.colorid < pRight->recipient.colorid; case RecentRequestsTableModel::Amount: return pLeft->recipient.amount < pRight->recipient.amount; default: diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h index 67d8aa114c..710f33d340 100644 --- a/src/qt/recentrequeststablemodel.h +++ b/src/qt/recentrequeststablemodel.h @@ -65,7 +65,8 @@ class RecentRequestsTableModel: public QAbstractTableModel Date = 0, Label = 1, Message = 2, - Amount = 3, + Token = 3, + Amount = 4, NUMBER_OF_COLUMNS }; diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index cae480f8d4..2f5c563085 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -67,7 +67,7 @@ void TestAddAddressesToSendBook() CKey key; key.MakeNewKey(true); CTxDestination dest(GetDestinationForKey( - key.GetPubKey(), wallet->m_default_address_type)); + key.GetPubKey(), wallet->m_default_address_type, ColorIdentifier())); return std::make_pair(dest, QString::fromStdString(EncodeDestination(dest))); }; diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index cf10a1cee6..18eb141933 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -143,7 +143,7 @@ void TestGUI() wallet->LoadWallet(firstRun); { LOCK(wallet->cs_wallet); - wallet->SetAddressBook(GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type), "", "receive"); + wallet->SetAddressBook(GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type, ColorIdentifier()), "", "receive"); wallet->AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey()); } { diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 5dc9771206..c5baad47f7 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -136,7 +136,7 @@ static UniValue createmultisig(const JSONRPCRequest& request) // Construct using pay-to-script-hash: const CScript inner = CreateMultisigRedeemscript(required, pubkeys); CBasicKeyStore keystore; - const CTxDestination dest = AddAndGetDestinationForScript(keystore, inner, output_type); + const CTxDestination dest = AddAndGetDestinationForScript(keystore, inner, output_type, ColorIdentifier()); UniValue result(UniValue::VOBJ); result.pushKV("address", EncodeDestination(dest)); diff --git a/src/script/standard.cpp b/src/script/standard.cpp index db103feeb7..1bd70d2eb5 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -23,6 +23,7 @@ unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY; CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} +CColorScriptID::CColorScriptID(const CScript& in, const ColorIdentifier& colorin): uint160(Hash160(in.begin(), in.end())), color(colorin) {} const char* GetTxnOutputType(txnouttype t) { diff --git a/src/script/standard.h b/src/script/standard.h index c4c6a77410..cb3a513cec 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -33,6 +33,7 @@ class CColorScriptID : public uint160 public: ColorIdentifier color; explicit CColorScriptID(const ColorIdentifier& colorin) : uint160(), color(colorin) {} + explicit CColorScriptID(const CScript& in, const ColorIdentifier& colorin); explicit CColorScriptID(const uint160& in, const ColorIdentifier& colorin) : uint160(in), color(colorin) {} }; /** diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 29ce064967..c2572c187d 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -82,7 +82,7 @@ static bool GetWalletAddressesForKey(CWallet * const pwallet, const CKeyID &keyi } } if (!fLabelFound) { - strAddr = EncodeDestination(GetDestinationForKey(key.GetPubKey(), pwallet->m_default_address_type)); + strAddr = EncodeDestination(GetDestinationForKey(key.GetPubKey(), pwallet->m_default_address_type, ColorIdentifier())); } return fLabelFound; } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 54234fcb98..ba2c097c94 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -218,7 +218,7 @@ static UniValue getnewaddress(const JSONRPCRequest& request) OutputType output_type = pwallet->m_default_address_type; if (colorId.type == TokenTypes::NONE) - dest = GetDestinationForKey(newKey, output_type); + dest = GetDestinationForKey(newKey, output_type, colorId); else dest = CColorKeyID(newKey.GetID(), colorId); @@ -285,7 +285,7 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request) CTxDestination dest; OutputType output_type = pwallet->m_default_change_type; if (colorId.type == TokenTypes::NONE) - dest = GetDestinationForKey(vchPubKey, output_type); + dest = GetDestinationForKey(vchPubKey, output_type, colorId); else dest = CColorKeyID(vchPubKey.GetID(), colorId); @@ -1054,7 +1054,7 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request) // Construct using pay-to-script-hash: CScript inner = CreateMultisigRedeemscript(required, pubkeys); - CTxDestination dest = AddAndGetDestinationForScript(*pwallet, inner, output_type); + CTxDestination dest = AddAndGetDestinationForScript(*pwallet, inner, output_type, ColorIdentifier()); pwallet->SetAddressBook(dest, label, "send"); UniValue result(UniValue::VOBJ); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8dcb1b1d40..30ec2d065a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -856,7 +856,7 @@ bool CWallet::GetLabelDestination(CTxDestination &dest, const std::string& label bForceNew = true; else { // Check if the current key has been used (TODO: check other addresses with the same key) - CScript scriptPubKey = GetScriptForDestination(GetDestinationForKey(account.vchPubKey, m_default_address_type)); + CScript scriptPubKey = GetScriptForDestination(GetDestinationForKey(account.vchPubKey, m_default_address_type, ColorIdentifier())); for (std::map::iterator it = mapWallet.begin(); it != mapWallet.end() && account.vchPubKey.IsValid(); ++it) @@ -873,11 +873,11 @@ bool CWallet::GetLabelDestination(CTxDestination &dest, const std::string& label if (!GetKeyFromPool(account.vchPubKey, false)) return false; - dest = GetDestinationForKey(account.vchPubKey, m_default_address_type); + dest = GetDestinationForKey(account.vchPubKey, m_default_address_type, ColorIdentifier()); SetAddressBook(dest, label, "receive"); batch.WriteAccount(label, account); } else { - dest = GetDestinationForKey(account.vchPubKey, m_default_address_type); + dest = GetDestinationForKey(account.vchPubKey, m_default_address_type, ColorIdentifier()); } return true; @@ -2727,7 +2727,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CTransac const OutputType change_type = m_default_change_type; - scriptChange = GetScriptForDestination(GetDestinationForKey(vchPubKey, change_type)); + scriptChange = GetScriptForDestination(GetDestinationForKey(vchPubKey, change_type, ColorIdentifier())); } CTxOut change_prototype_txout(0, scriptChange); coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout, SER_DISK, 0); From 28e776ec0d3172477363a8644ca43c7e91fcba9d Mon Sep 17 00:00:00 2001 From: Navia Bheeman Date: Wed, 15 Jun 2022 17:55:10 +0530 Subject: [PATCH 07/11] fixed token formatting in receive coins dialog and table --- src/qt/receiverequestdialog.cpp | 2 +- src/qt/recentrequeststablemodel.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index 346c24c00b..b1e1a482a2 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -142,7 +142,7 @@ void ReceiveRequestDialog::update() if(info.colorid.type != TokenTypes::NONE) html += ""+tr("Token")+": " + info.colorid.toHexString().c_str() + "
"; if(info.amount) - html += ""+tr("Amount")+": " + ((info.colorid.type != TokenTypes::NONE) ?TapyrusUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), info.amount):TapyrusUnits::formatHtmlWithUnit(TapyrusUnits::TOKEN, info.amount) )+ "
"; + html += ""+tr("Amount")+": " + (info.colorid.type == TokenTypes::NONE ? TapyrusUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), info.amount): TapyrusUnits::formatHtmlWithUnit(TapyrusUnits::TOKEN, info.amount) ) + "
"; if(!info.label.isEmpty()) html += ""+tr("Label")+": " + GUIUtil::HtmlEscape(info.label) + "
"; if(!info.message.isEmpty()) diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index ab226fa7c3..2bd7ea59a6 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -83,9 +83,9 @@ QVariant RecentRequestsTableModel::data(const QModelIndex &index, int role) cons if (rec->recipient.amount == 0 && role == Qt::DisplayRole) return tr("(no amount requested)"); else if (role == Qt::EditRole) - return TapyrusUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount, false, TapyrusUnits::separatorNever); + return rec->recipient.colorid.type == TokenTypes::NONE ? TapyrusUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount, false, TapyrusUnits::separatorNever) : TapyrusUnits::formatWithUnit(TapyrusUnits::TOKEN, rec->recipient.amount); else - return TapyrusUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount); + return rec->recipient.colorid.type == TokenTypes::NONE ? TapyrusUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount) : TapyrusUnits::formatWithUnit(TapyrusUnits::TOKEN, rec->recipient.amount); } } else if (role == Qt::TextAlignmentRole) From bf8f1de59a4068dc2268368eaf1240739a37b1e8 Mon Sep 17 00:00:00 2001 From: Navia Bheeman Date: Wed, 15 Jun 2022 23:33:09 +0530 Subject: [PATCH 08/11] differentiate platforms in test --- src/qt/test/wallettests.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 18eb141933..199cbec394 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -155,7 +155,11 @@ void TestGUI() wallet->SetBroadcastTransactions(true); // Create widgets for sending coins and listing transactions. +#if defined(MAC_OSX) + std::unique_ptr platformStyle(PlatformStyle::instantiate("macosx")); +#else std::unique_ptr platformStyle(PlatformStyle::instantiate("other")); +#endif SendCoinsDialog sendCoinsDialog(platformStyle.get()); TransactionView transactionView(platformStyle.get()); auto node = interfaces::MakeNode(); From c48da8ecdd88972eadadf6a1c69525f13542ca15 Mon Sep 17 00:00:00 2001 From: Navia Bheeman Date: Wed, 15 Jun 2022 23:49:10 +0530 Subject: [PATCH 09/11] added documentation for receive dialog --- doc/tapyrus/colored_coin_gui.md | 27 ++++++++++++------- doc/tapyrus/images/Tapyrus-receive-token.png | Bin 0 -> 166645 bytes 2 files changed, 17 insertions(+), 10 deletions(-) create mode 100644 doc/tapyrus/images/Tapyrus-receive-token.png diff --git a/doc/tapyrus/colored_coin_gui.md b/doc/tapyrus/colored_coin_gui.md index a82d5ec473..3fc9ea5d97 100644 --- a/doc/tapyrus/colored_coin_gui.md +++ b/doc/tapyrus/colored_coin_gui.md @@ -1,16 +1,23 @@ ## Tapyrus core GUI - Tapyrus GUI has been enhanced to allow Token transactions. Following are the changes made +Tapyrus GUI has been enhanced to allow Token transactions. Following are the changes made - ### Overview Page - Overview in the new Tapyrus GUI shows tokens as well. TPC is in view when the gui starts. _Prev_ and _Next_ buttons can be used to scroll through all the available tokens. When no other tokens are available only TPC is visible. +### Overview Page +Overview in the new Tapyrus GUI shows tokens as well. _Prev_ and _Next_ buttons can be used to scroll through all the available tokens. Only TPC is shown when no other tokens are available. - ![Overview Page with token](./images/Tapyrus-overview-token.png) +![Overview Page with token](./images/Tapyrus-overview-token.png) - ### Send Token - Sending a token is the same as sending TPC except that the new address must have been generated with the colorid +### Send Token +Sending a token is the same as sending TPC except that the new address must have been generated with the colorid - > ./src/tapyrus-cli -conf=~/.tapyrus/ getnewaddress "NFT" c3b8b7e3a2684c746d367420bd0899104005cfeeb59705a3f402fa37312f402624 - Then the token lable would be populated automatically and "TOKEN" would be set in the token type drop down. - ![Send coin page with token](./images/Tapyrus-send-token.png) - \ No newline at end of file +> ./src/tapyrus-cli -conf=~/.tapyrus/ getnewaddress "NFT" c3b8b7e3a2684c746d367420bd0899104005cfeeb59705a3f402fa37312f402624 + +Then the token lable would be populated automatically and "TOKEN" would be set in the token type drop down. +![Send coin page with token](./images/Tapyrus-send-token.png) + +### Receive Token +Receiving tokens is also similar to receiving TPC. In addition to lable, message and amount, Token should also be populated. +![Receive token page](./images/Tapyrus-receive-token.png) + +A new entry is added to the payment history table after the address is generated. +![Received payment dialog](./images/Tapyrus-receive-dialog.png) diff --git a/doc/tapyrus/images/Tapyrus-receive-token.png b/doc/tapyrus/images/Tapyrus-receive-token.png new file mode 100644 index 0000000000000000000000000000000000000000..7af9ae3ed59be2b1d40ba6a0b6caac29bd13da1b GIT binary patch literal 166645 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%0AUuikv)8lBn`7BUb`1!&ty2%*L- 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%0Aob+Y|sj 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 MU0DlRjxZ1UA9<~fmjD0& literal 0 HcmV?d00001 From 1783d043017e7bfcdc4b60562075bac9e225d6a3 Mon Sep 17 00:00:00 2001 From: Navia Bheeman Date: Mon, 20 Jun 2022 18:19:38 +0530 Subject: [PATCH 10/11] fixed crash in coloredCoin constructor when the text bas has empty string in the GUI --- src/qt/addresstablemodel.cpp | 2 +- src/qt/receivecoinsdialog.cpp | 5 +++-- src/qt/walletmodel.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 036d106908..03880ebc88 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -363,7 +363,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con else if(type == Receive) { // Generate a new address to associate with given label - ColorIdentifier colorId(ParseHex(colorin.toStdString().c_str())); + ColorIdentifier colorId(colorin.length() ? ParseHex(colorin.toStdString().c_str()) : ColorIdentifier()); CPubKey newKey; if(!walletModel->wallet().getKeyFromPool(false /* internal */, newKey)) { diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 03344ba904..33f04bed67 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -139,11 +139,12 @@ void ReceiveCoinsDialog::on_receiveButton_clicked() QString address; QString label = ui->reqLabel->text(); - const ColorIdentifier colorid(ParseHex(ui->tokenName->text().toStdString().c_str())); + QString color = ui->tokenName->text(); + const ColorIdentifier colorid(color.length() ? ParseHex(color.toStdString().c_str()) : ColorIdentifier()); /* Generate new receiving address */ OutputType address_type = ui->tokenName->text().isEmpty() ? model->wallet().getDefaultAddressType() : OutputType::TOKEN; - address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", ui->tokenName->text(), address_type); + address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", color, address_type); SendCoinsRecipient info(address, label, ui->reqAmount->value(), ui->reqMessage->text()); info.colorid = colorid; ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 129deac7cc..1b8fd97192 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -51,7 +51,7 @@ QT_END_NAMESPACE class SendCoinsRecipient { public: - explicit SendCoinsRecipient() : amount(0), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION), colorid() { } + explicit SendCoinsRecipient() : amount(0), fSubtractFeeFromAmount(false), colorid(), nVersion(SendCoinsRecipient::CURRENT_VERSION) { } //only decleration is here explicit SendCoinsRecipient(const QString &addr, const QString &_label, const CAmount& _amount, const QString &_message); From 504ebe59fea4004ef772bc1e63d4cdf3406dfe36 Mon Sep 17 00:00:00 2001 From: Navia Bheeman Date: Thu, 16 Jun 2022 00:07:59 +0530 Subject: [PATCH 11/11] colored coin support in transaction page in tapyrus qt gui --- doc/tapyrus/colored_coin_gui.md | 4 + .../images/Tapyrus-transaction-page.png | Bin 0 -> 278664 bytes src/interfaces/node.h | 2 +- src/interfaces/wallet.cpp | 24 +- src/interfaces/wallet.h | 45 +++- src/qt/test_tapyrus_qt | Bin 0 -> 11906576 bytes src/qt/transactiondesc.cpp | 213 +++++++++--------- src/qt/transactionrecord.cpp | 196 +++++++++------- src/qt/transactionrecord.h | 11 +- src/qt/transactiontablemodel.cpp | 88 +++++--- src/qt/transactiontablemodel.h | 6 +- src/qt/transactionview.cpp | 11 +- 12 files changed, 353 insertions(+), 247 deletions(-) create mode 100644 doc/tapyrus/images/Tapyrus-transaction-page.png create mode 100755 src/qt/test_tapyrus_qt diff --git a/doc/tapyrus/colored_coin_gui.md b/doc/tapyrus/colored_coin_gui.md index 3fc9ea5d97..e9b8a2461d 100644 --- a/doc/tapyrus/colored_coin_gui.md +++ b/doc/tapyrus/colored_coin_gui.md @@ -21,3 +21,7 @@ Receiving tokens is also similar to receiving TPC. In addition to lable, message A new entry is added to the payment history table after the address is generated. ![Received payment dialog](./images/Tapyrus-receive-dialog.png) + +A new column called Token is added to the transaction table. It shows the token name or TPC for every transaction output. Amount column for TPC is formatted according to wallet setting. For tokens, it is always the number of tokens. + +![Transaction page](./images/Tapyrus-transaction-page.png) \ No newline at end of file diff --git a/doc/tapyrus/images/Tapyrus-transaction-page.png b/doc/tapyrus/images/Tapyrus-transaction-page.png new file mode 100644 index 0000000000000000000000000000000000000000..ee9553779ad72febcb90ab1693cba70ecdcf69ab GIT binary patch literal 278664 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

kL3ATMU39ewpQ_Ve-4zn^ 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 literal 0 HcmV?d00001 diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 77f587e33b..f5f7f09f33 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -9,6 +9,7 @@ #include // For CAmount #include // For CConnman::NumConnections #include // For Network +#include #include #include @@ -21,7 +22,6 @@ class CCoinControl; class CFeeRate; class CNodeStats; -class Coin; class RPCTimerInterface; class UniValue; class proxyType; diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 886ec04d96..3a15be24a4 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -58,7 +58,7 @@ class PendingWalletTxImpl : public PendingWalletTx }; //! Construct wallet tx struct. -WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) +WalletTx MakeWalletTx(Node& node, CWallet& wallet, const CWalletTx& wtx) { WalletTx result; result.tx = wtx.tx; @@ -83,11 +83,13 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) result.time = wtx.GetTxTime(); result.value_map = wtx.mapValue; result.is_coinbase = wtx.IsCoinBase(); + result.is_tokenInput = result.isTokenInput(node); + result.is_tokenOutput = result.isTokenOutput(); return result; } //! Construct wallet tx status struct. -WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx) +WalletTxStatus MakeWalletTxStatus(Node& node, const CWalletTx& wtx) { WalletTxStatus result; auto mi = ::mapBlockIndex.find(wtx.hashBlock); @@ -274,26 +276,26 @@ class WalletImpl : public Wallet } return {}; } - WalletTx getWalletTx(const uint256& txid) override + WalletTx getWalletTx(Node& node, const uint256& txid) override { LOCK2(::cs_main, m_wallet.cs_wallet); auto mi = m_wallet.mapWallet.find(txid); if (mi != m_wallet.mapWallet.end()) { - return MakeWalletTx(m_wallet, mi->second); + return MakeWalletTx(node, m_wallet, mi->second); } return {}; } - std::vector getWalletTxs() override + std::vector getWalletTxs(Node& node) override { LOCK2(::cs_main, m_wallet.cs_wallet); std::vector result; result.reserve(m_wallet.mapWallet.size()); for (const auto& entry : m_wallet.mapWallet) { - result.emplace_back(MakeWalletTx(m_wallet, entry.second)); + result.emplace_back(MakeWalletTx(node, m_wallet, entry.second)); } return result; } - bool tryGetTxStatus(const uint256& txid, + bool tryGetTxStatus(Node& node, const uint256& txid, interfaces::WalletTxStatus& tx_status, int& num_blocks, int64_t& adjusted_time) override @@ -312,10 +314,10 @@ class WalletImpl : public Wallet } num_blocks = ::chainActive.Height(); adjusted_time = GetAdjustedTime(); - tx_status = MakeWalletTxStatus(mi->second); + tx_status = MakeWalletTxStatus(node, mi->second); return true; } - WalletTx getWalletTxDetails(const uint256& txid, + WalletTx getWalletTxDetails(Node& node, const uint256& txid, WalletTxStatus& tx_status, WalletOrderForm& order_form, bool& in_mempool, @@ -329,8 +331,8 @@ class WalletImpl : public Wallet adjusted_time = GetAdjustedTime(); in_mempool = mi->second.InMempool(); order_form = mi->second.vOrderForm; - tx_status = MakeWalletTxStatus(mi->second); - return MakeWalletTx(m_wallet, mi->second); + tx_status = MakeWalletTxStatus(node, mi->second); + return MakeWalletTx(node, m_wallet, mi->second); } return {}; } diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 91fa6e9fe6..9f337c65c4 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -11,6 +11,7 @@ #include