Merge pull request #100 from aayanl/zcl-v1.0.10-1
Merge v1.0.10-1 from zcash
This commit is contained in:
commit
f94256c806
|
@ -1,5 +1,4 @@
|
|||
Zclassic v1.0.9
|
||||
===========
|
||||
Zclassic v1.0.10-1
|
||||
|
||||
NOTICE, the default ports have changed! The p2p port is now 8033 and rpcport is 8023
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
|
|||
AC_PREREQ([2.60])
|
||||
define(_CLIENT_VERSION_MAJOR, 1)
|
||||
define(_CLIENT_VERSION_MINOR, 0)
|
||||
define(_CLIENT_VERSION_REVISION, 9)
|
||||
define(_CLIENT_VERSION_REVISION, 10)
|
||||
define(_CLIENT_VERSION_BUILD, 51)
|
||||
define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50)))
|
||||
define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1)))
|
||||
|
@ -993,7 +993,7 @@ PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR"
|
|||
unset PKG_CONFIG_LIBDIR
|
||||
PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP"
|
||||
|
||||
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no"
|
||||
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery"
|
||||
AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue])
|
||||
|
||||
AC_OUTPUT
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
zcash (1.0.10+1) stable; urgency=medium
|
||||
|
||||
* 1.0.10-1 release.
|
||||
|
||||
-- Zcash Company <team@z.cash> Fri, 23 Jun 2017 19:50:41 -0700
|
||||
|
||||
zcash (1.0.10) stable; urgency=medium
|
||||
|
||||
* 1.0.10 release.
|
||||
|
||||
-- Zcash Company <team@z.cash> Thu, 22 Jun 2017 15:13:04 +1200
|
||||
|
||||
zcash (1.0.9) stable; urgency=medium
|
||||
|
||||
* 1.0.9 release.
|
||||
|
|
|
@ -63,6 +63,14 @@ Files: depends/sources/qpid-proton-*.tar.gz
|
|||
Copyright: 2012-2017 The Apache Software Foundation
|
||||
License: Apache-Qpid-Proton-with-BSD-Subcomponents
|
||||
|
||||
Files: src/secp256k1/build-aux/m4/ax_jni_include_dir.m4
|
||||
Copyright: 2008 Don Anderson <dda@sleepycat.com>
|
||||
License: GNU-All-permissive-License
|
||||
|
||||
Files: src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4
|
||||
Copyright: 2008 Paolo Bonzini <bonzini@gnu.org>
|
||||
License: GNU-All-permissive-License
|
||||
|
||||
License: Boost-Software-License-1.0
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
|
@ -1312,3 +1320,9 @@ License: Apache-Qpid-Proton-with-BSD-Subcomponents
|
|||
conditions in the license:
|
||||
proton-c/bindings/python/setuputils/PYZMQ_LICENSE.BSD.
|
||||
|
||||
License: GNU-All-permissive-License
|
||||
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.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
name: "zcash-1.0.9"
|
||||
name: "zcash-1.0.10-1"
|
||||
enable_cache: true
|
||||
distro: "debian"
|
||||
suites:
|
||||
|
@ -85,7 +85,7 @@ script: |
|
|||
BASEPREFIX=`pwd`/depends
|
||||
# Build dependencies for each host
|
||||
for i in $HOSTS; do
|
||||
make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}"
|
||||
NO_PROTON="x" make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}"
|
||||
done
|
||||
|
||||
# Faketime for binaries
|
||||
|
|
|
@ -5,7 +5,7 @@ BASE_CACHE ?= $(BASEDIR)/built
|
|||
SDK_PATH ?= $(BASEDIR)/SDKs
|
||||
NO_WALLET ?=
|
||||
NO_UPNP ?=
|
||||
FALLBACK_DOWNLOAD_PATH ?= https://z.cash/depends-sources
|
||||
PRIORITY_DOWNLOAD_PATH ?= https://z.cash/depends-sources
|
||||
|
||||
BUILD ?= $(shell ./config.guess)
|
||||
HOST ?= $(BUILD)
|
||||
|
|
|
@ -33,7 +33,7 @@ The following can be set when running make: make FOO=bar
|
|||
SOURCES_PATH: downloaded sources will be placed here
|
||||
BASE_CACHE: built packages will be placed here
|
||||
SDK_PATH: Path where sdk's can be found (used by OSX)
|
||||
FALLBACK_DOWNLOAD_PATH: If a source file can't be fetched, try here before giving up
|
||||
PRIORITY_DOWNLOAD_PATH: Try fetching source files from here before using their own URLs
|
||||
NO_WALLET: Don't download/build/cache libs needed to enable the wallet
|
||||
NO_UPNP: Don't download/build/cache packages needed for enabling upnp
|
||||
DEBUG: disable some optimizations and enable more runtime checking
|
||||
|
|
|
@ -22,7 +22,7 @@ endef
|
|||
define fetch_file
|
||||
(test -f $$($(1)_source_dir)/$(4) || \
|
||||
( mkdir -p $$($(1)_download_dir) && echo Fetching $(1)... && \
|
||||
( $(build_DOWNLOAD) "$$($(1)_download_dir)/$(4).temp" "$(FALLBACK_DOWNLOAD_PATH)/$(4)" || \
|
||||
( $(build_DOWNLOAD) "$$($(1)_download_dir)/$(4).temp" "$(PRIORITY_DOWNLOAD_PATH)/$(4)" || \
|
||||
$(build_DOWNLOAD) "$$($(1)_download_dir)/$(4).temp" "$(2)/$(3)" ) && \
|
||||
echo "$(5) $$($(1)_download_dir)/$(4).temp" > $$($(1)_download_dir)/.$(4).hash && \
|
||||
$(build_SHA256SUM) -c $$($(1)_download_dir)/.$(4).hash && \
|
||||
|
@ -43,6 +43,10 @@ $(eval $(1)_build_id_long:=$(1)-$($(1)_version)-$($(1)_recipe_hash)-$(release_ty
|
|||
$(eval $(1)_build_id:=$(shell echo -n "$($(1)_build_id_long)" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH)))
|
||||
final_build_id_long+=$($(package)_build_id_long)
|
||||
|
||||
#override platform specific files and hashes
|
||||
$(eval $(1)_file_name=$(if $($(1)_file_name_$(host_os)),$($(1)_file_name_$(host_os)),$($(1)_file_name)))
|
||||
$(eval $(1)_sha256_hash=$(if $($(1)_sha256_hash_$(host_os)),$($(1)_sha256_hash_$(host_os)),$($(1)_sha256_hash)))
|
||||
|
||||
#compute package-specific paths
|
||||
$(1)_build_subdir?=.
|
||||
$(1)_download_file?=$($(1)_file_name)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package=rust
|
||||
$(package)_version=1.16.0
|
||||
$(package)_download_path=https://static.rust-lang.org/dist
|
||||
$(package)_file_name=rust-$($(package)_version)-x86_64-unknown-linux-gnu.tar.gz
|
||||
$(package)_sha256_hash=48621912c242753ba37cad5145df375eeba41c81079df46f93ffb4896542e8fd
|
||||
$(package)_file_name_linux=rust-$($(package)_version)-x86_64-unknown-linux-gnu.tar.gz
|
||||
$(package)_sha256_hash_linux=48621912c242753ba37cad5145df375eeba41c81079df46f93ffb4896542e8fd
|
||||
$(package)_file_name_darwin=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz
|
||||
$(package)_sha256_hash_darwin=2d08259ee038d3a2c77a93f1a31fc59e7a1d6d1bbfcba3dba3c8213b2e5d1926
|
||||
|
||||
define $(package)_stage_cmds
|
||||
./install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
Zcash Contributors
|
||||
==================
|
||||
|
||||
Jack Grigg (407)
|
||||
Simon Liu (259)
|
||||
Sean Bowe (186)
|
||||
Daira Hopwood (87)
|
||||
Jack Grigg (428)
|
||||
Simon Liu (266)
|
||||
Sean Bowe (188)
|
||||
Daira Hopwood (95)
|
||||
Taylor Hornby (65)
|
||||
Wladimir J. van der Laan (58)
|
||||
Wladimir J. van der Laan (60)
|
||||
Nathan Wilcox (51)
|
||||
Jay Graber (49)
|
||||
Jonas Schnelli (48)
|
||||
Kevin Gallagher (38)
|
||||
Pieter Wuille (16)
|
||||
Cory Fields (15)
|
||||
Pieter Wuille (14)
|
||||
nomnombtc (9)
|
||||
Paige Peterson (9)
|
||||
fanquake (5)
|
||||
|
@ -28,6 +28,7 @@ Jeff Garzik (4)
|
|||
David Mercer (4)
|
||||
Daniel Cousens (4)
|
||||
lpescher (3)
|
||||
kozyilmaz (3)
|
||||
Pavel Janík (3)
|
||||
Alfie John (3)
|
||||
str4d (2)
|
||||
|
@ -65,6 +66,7 @@ Matt Quinn (1)
|
|||
Louis Nyffenegger (1)
|
||||
Leo Arias (1)
|
||||
Lars-Magnus Skog (1)
|
||||
Kevin Pan (1)
|
||||
Jorge Timón (1)
|
||||
Jeffrey Walton (1)
|
||||
Ian Kelling (1)
|
||||
|
@ -79,6 +81,7 @@ Chirag Davé (1)
|
|||
Casey Rodarmor (1)
|
||||
Cameron Boehmer (1)
|
||||
Bryan Stitt (1)
|
||||
Boris Hajduk (1)
|
||||
Bob McElrath (1)
|
||||
Bitcoin Error Log (1)
|
||||
Allan Niemerg (1)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4.
|
||||
.TH ZCASH-CLI "1" "May 2017" "zcash-cli v1.0.9" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
|
||||
.TH ZCASH-CLI "1" "June 2017" "zcash-cli v1.0.10-1" "User Commands"
|
||||
.SH NAME
|
||||
zcash-cli \- manual page for zcash-cli v1.0.9
|
||||
zcash-cli \- manual page for zcash-cli v1.0.10-1
|
||||
.SH DESCRIPTION
|
||||
Zcash RPC client version v1.0.9
|
||||
Zcash RPC client version v1.0.10\-1
|
||||
.PP
|
||||
In order to ensure you are adequately protecting your privacy when using Zclassic,
|
||||
please see <https://z.cash/support/security/index.html>.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4.
|
||||
.TH ZCASH-TX "1" "May 2017" "zcash-tx v1.0.9" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
|
||||
.TH ZCASH-TX "1" "June 2017" "zcash-tx v1.0.10-1" "User Commands"
|
||||
.SH NAME
|
||||
zcash-tx \- manual page for zcash-tx v1.0.9
|
||||
zcash-tx \- manual page for zcash-tx v1.0.10-1
|
||||
.SH DESCRIPTION
|
||||
Zcash zcash\-tx utility version v1.0.9
|
||||
Zcash zcash\-tx utility version v1.0.10\-1
|
||||
.SS "Usage:"
|
||||
.TP
|
||||
zcash\-tx [options] <hex\-tx> [commands]
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4.
|
||||
.TH ZCASHD "1" "May 2017" "zcashd v1.0.9" "User Commands"
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
|
||||
.TH ZCASHD "1" "June 2017" "zcashd v1.0.10-1" "User Commands"
|
||||
.SH NAME
|
||||
zcashd \- manual page for zcashd v1.0.9
|
||||
zcashd \- manual page for zcashd v1.0.10-1
|
||||
.SH DESCRIPTION
|
||||
Zcash Daemon version v1.0.9
|
||||
Zcash Daemon version v1.0.10\-1
|
||||
.PP
|
||||
In order to ensure you are adequately protecting your privacy when using Zclassic,
|
||||
please see <https://z.cash/support/security/index.html>.
|
||||
|
@ -54,7 +54,7 @@ Specify data directory
|
|||
\fB\-disabledeprecation=\fR<version>
|
||||
.IP
|
||||
Disable block\-height node deprecation and automatic shutdown (example:
|
||||
\fB\-disabledeprecation\fR=\fI\,1\/\fR.0.9)
|
||||
\fB\-disabledeprecation\fR=\fI\,1\/\fR.0.10\-1)
|
||||
.HP
|
||||
\fB\-exportdir=\fR<dir>
|
||||
.IP
|
||||
|
@ -72,6 +72,11 @@ Imports blocks from external blk000??.dat file on startup
|
|||
.IP
|
||||
Keep at most <n> unconnectable transactions in memory (default: 100)
|
||||
.HP
|
||||
\fB\-mempooltxinputlimit=\fR<n>
|
||||
.IP
|
||||
Set the maximum number of transparent inputs in a transaction that the
|
||||
mempool will accept (default: 0 = no limit applied)
|
||||
.HP
|
||||
\fB\-par=\fR<n>
|
||||
.IP
|
||||
Set the number of script verification threads (\fB\-4\fR to 16, 0 = auto, <0 =
|
||||
|
|
|
@ -55,7 +55,7 @@ Command | Parameters | Description
|
|||
--- | --- | ---
|
||||
z_getnewaddress | | Return a new zaddr for sending and receiving payments. The spending key for this zaddr will be added to the node’s wallet.<br><br>Output:<br>zN68D8hSs3...
|
||||
z_listaddresses | | Returns a list of all the zaddrs in this node’s wallet for which you have a spending key.<br><br>Output:<br>{ [“z123…”, “z456...”, “z789...”] }
|
||||
z_validateaddress | | Return information about a given zaddr.<br><br>Output:<br>{"isvalid" : true,<br>"address" : "zcWsmq...",<br>"payingkey" : "f5bb3c...",<br>"transmissionkey" : "7a58c7...",<br>"ismine" : true}
|
||||
z_validateaddress | zaddr | Return information about a given zaddr.<br><br>Output:<br>{"isvalid" : true,<br>"address" : "zcWsmq...",<br>"payingkey" : "f5bb3c...",<br>"transmissionkey" : "7a58c7...",<br>"ismine" : true}
|
||||
|
||||
### Key Management
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
(note: this is a temporary file, to be added-to by anybody, and moved to
|
||||
release-notes at release time)
|
||||
|
||||
Notable changes
|
||||
===============
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
Jack Grigg (1):
|
||||
Disable building Proton in Gitian
|
||||
|
||||
Sean Bowe (2):
|
||||
Revert "Remove an unneeded version workaround as per @str4d's review comment."
|
||||
Revert "Delete old protocol version constants and simplify code that used them."
|
||||
|
||||
Simon Liu (2):
|
||||
make-release.py: Versioning changes for 1.0.10-1.
|
||||
make-release.py: Updated manpages for 1.0.10-1.
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
Notable changes
|
||||
===============
|
||||
|
||||
Signature validation using libsecp256k1
|
||||
---------------------------------------
|
||||
|
||||
ECDSA signatures inside Zcash transactions now use validation using
|
||||
[https://github.com/bitcoin/secp256k1](libsecp256k1) instead of OpenSSL.
|
||||
|
||||
Depending on the platform, this means a significant speedup for raw signature
|
||||
validation speed. The advantage is largest on x86_64, where validation is over
|
||||
five times faster. In practice, this translates to a raw reindexing and new
|
||||
block validation times that are less than half of what it was before.
|
||||
|
||||
Libsecp256k1 has undergone very extensive testing and validation upstream.
|
||||
|
||||
A side effect of this change is that libconsensus no longer depends on OpenSSL.
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
Boris Hajduk (1):
|
||||
documentatin z_validateaddress was missing param
|
||||
|
||||
Daira Hopwood (8):
|
||||
Delete old protocol version constants and simplify code that used them. fixes #2244
|
||||
Remove an unneeded version workaround as per @str4d's review comment.
|
||||
Remove unneeded lax ECDSA signature verification.
|
||||
Strict DER signatures are always enforced; remove the flag and code that used it.
|
||||
Repair tests for strict DER signatures. While we're at it, repair a similar test for CLTV, and make the repaired RPC tests run by default.
|
||||
Make transaction test failures print the comments preceding the test JSON.
|
||||
Fix a comment that was made stale before launch by #1016 (commit 542da61).
|
||||
Delete test that is redundant and inapplicable to Zcash.
|
||||
|
||||
Jack Grigg (20):
|
||||
Fix incorrect locking in CCryptoKeyStore
|
||||
Use AtomicTimer for metrics screen thread count
|
||||
Revert "Fix secp256k1 test compilation"
|
||||
Squashed 'src/secp256k1/' changes from 22f60a6..84973d3
|
||||
Fix potential overflows in ECDSA DER parsers
|
||||
Rename FALLBACK_DOWNLOAD_PATH to PRIORITY_DOWNLOAD_PATH
|
||||
Add test for incorrect consensus logic
|
||||
Correct consensus logic in ContextualCheckInputs
|
||||
Add comments
|
||||
Update Debian copyright list
|
||||
Specify ECDSA constant sizes as constants
|
||||
Remove redundant `= 0` initialisations
|
||||
Ensure that ECDSA constant sizes are correctly-sized
|
||||
Add test for -mempooltxinputlimit
|
||||
Hold an ECCVerifyHandle in zcash-gtest
|
||||
Additional testing of -mempooltxinputlimit
|
||||
Fix comment
|
||||
Use sendfrom for both t-addr calls
|
||||
make-release.py: Versioning changes for 1.0.10.
|
||||
make-release.py: Updated manpages for 1.0.10.
|
||||
|
||||
Kevin Pan (1):
|
||||
"getblocktemplate" could work without wallet
|
||||
|
||||
Pieter Wuille (2):
|
||||
Update key.cpp to new secp256k1 API
|
||||
Switch to libsecp256k1-based validation for ECDSA
|
||||
|
||||
Simon Liu (5):
|
||||
Fix intermediate vpub_new leakage in multi joinsplit tx (#1360)
|
||||
Add option 'mempooltxinputlimit' so the mempool can reject a transaction based on the number of transparent inputs.
|
||||
Check mempooltxinputlimit when creating a transaction to avoid local mempool rejection.
|
||||
Partial revert & fix for commit 9e84b5a ; code block in wrong location.
|
||||
Fix #b1eb4f2 so test checks sendfrom as originally intended.
|
||||
|
||||
Wladimir J. van der Laan (2):
|
||||
Use real number of cores for default -par, ignore virtual cores
|
||||
Remove ChainParams::DefaultMinerThreads
|
||||
|
||||
kozyilmaz (3):
|
||||
[macOS] system linker does not support “--version” option but only “-v”
|
||||
option to disable building libraries (zcutil/build.sh)
|
||||
support per platform filename and hash setting for dependencies
|
||||
|
|
@ -26,6 +26,7 @@ testScripts=(
|
|||
'rest.py'
|
||||
'mempool_spendcoinbase.py'
|
||||
'mempool_coinbase_spends.py'
|
||||
'mempool_tx_input_limit.py'
|
||||
'httpbasics.py'
|
||||
'zapwallettxes.py'
|
||||
'proxy_test.py'
|
||||
|
@ -40,10 +41,10 @@ testScripts=(
|
|||
'zcjoinsplit.py'
|
||||
'zcjoinsplitdoublespend.py'
|
||||
'getblocktemplate.py'
|
||||
'bip65-cltv-p2p.py'
|
||||
'bipdersig-p2p.py'
|
||||
);
|
||||
testScriptsExt=(
|
||||
'bipdersig-p2p.py'
|
||||
'bipdersig.py'
|
||||
'getblocktemplate_longpoll.py'
|
||||
'getblocktemplate_proposals.py'
|
||||
'pruning.py'
|
||||
|
|
|
@ -5,35 +5,24 @@
|
|||
#
|
||||
|
||||
from test_framework.test_framework import ComparisonTestFramework
|
||||
from test_framework.util import *
|
||||
from test_framework.util import start_nodes
|
||||
from test_framework.mininode import CTransaction, NetworkThread
|
||||
from test_framework.blocktools import create_coinbase, create_block
|
||||
from test_framework.comptool import TestInstance, TestManager
|
||||
from test_framework.script import CScript, OP_1NEGATE, OP_NOP2, OP_DROP
|
||||
from binascii import hexlify, unhexlify
|
||||
from binascii import unhexlify
|
||||
import cStringIO
|
||||
import time
|
||||
|
||||
def cltv_invalidate(tx):
|
||||
'''Modify the signature in vin 0 of the tx to fail CLTV
|
||||
|
||||
Prepends -1 CLTV DROP in the scriptSig itself.
|
||||
'''
|
||||
tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_NOP2, OP_DROP] +
|
||||
list(CScript(tx.vin[0].scriptSig)))
|
||||
|
||||
'''
|
||||
This test is meant to exercise BIP65 (CHECKLOCKTIMEVERIFY)
|
||||
This test is meant to exercise BIP65 (CHECKLOCKTIMEVERIFY).
|
||||
Connect to a single node.
|
||||
Mine 2 (version 3) blocks (save the coinbases for later).
|
||||
Generate 98 more version 3 blocks, verify the node accepts.
|
||||
Mine 749 version 4 blocks, verify the node accepts.
|
||||
Check that the new CLTV rules are not enforced on the 750th version 4 block.
|
||||
Check that the new CLTV rules are enforced on the 751st version 4 block.
|
||||
Mine 199 new version blocks.
|
||||
Mine 1 old-version block.
|
||||
Mine 1 new version block.
|
||||
Mine 1 old version block, see that the node rejects.
|
||||
Mine a coinbase block, and then ...
|
||||
Mine 1 version 4 block.
|
||||
Check that the CLTV rules are enforced.
|
||||
|
||||
TODO: factor out common code from {bipdersig-p2p,bip65-cltv-p2p}.py.
|
||||
'''
|
||||
|
||||
class BIP65Test(ComparisonTestFramework):
|
||||
|
@ -42,14 +31,14 @@ class BIP65Test(ComparisonTestFramework):
|
|||
self.num_nodes = 1
|
||||
|
||||
def setup_network(self):
|
||||
# Must set the blockversion for this test
|
||||
self.nodes = start_nodes(1, self.options.tmpdir,
|
||||
extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=3']],
|
||||
extra_args=[['-debug', '-whitelist=127.0.0.1']],
|
||||
binary=[self.options.testbinary])
|
||||
self.is_network_split = False
|
||||
|
||||
def run_test(self):
|
||||
test = TestManager(self, self.options.tmpdir)
|
||||
test.add_all_connections(self.nodes)
|
||||
# Don't call test.add_all_connections because there is only one node.
|
||||
NetworkThread().start() # Start up network handling in another thread
|
||||
test.run()
|
||||
|
||||
|
@ -64,112 +53,40 @@ class BIP65Test(ComparisonTestFramework):
|
|||
tx.deserialize(f)
|
||||
return tx
|
||||
|
||||
def get_tests(self):
|
||||
def invalidate_transaction(self, tx):
|
||||
'''
|
||||
Modify the signature in vin 0 of the tx to fail CLTV
|
||||
|
||||
self.coinbase_blocks = self.nodes[0].generate(2)
|
||||
Prepends -1 CLTV DROP in the scriptSig itself.
|
||||
'''
|
||||
tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_NOP2, OP_DROP] +
|
||||
list(CScript(tx.vin[0].scriptSig)))
|
||||
|
||||
def get_tests(self):
|
||||
self.coinbase_blocks = self.nodes[0].generate(1)
|
||||
self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0)
|
||||
self.nodeaddress = self.nodes[0].getnewaddress()
|
||||
self.last_block_time = time.time()
|
||||
self.block_time = time.time() + 1
|
||||
|
||||
''' 98 more version 3 blocks '''
|
||||
test_blocks = []
|
||||
for i in xrange(98):
|
||||
block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1)
|
||||
block.nVersion = 3
|
||||
block.rehash()
|
||||
block.solve()
|
||||
test_blocks.append([block, True])
|
||||
self.last_block_time += 1
|
||||
self.tip = block.sha256
|
||||
yield TestInstance(test_blocks, sync_every_block=False)
|
||||
'''Check that the rules are enforced.'''
|
||||
for valid in (True, False):
|
||||
spendtx = self.create_transaction(self.nodes[0],
|
||||
self.coinbase_blocks[0],
|
||||
self.nodeaddress, 1.0)
|
||||
if not valid:
|
||||
self.invalidate_transaction(spendtx)
|
||||
spendtx.rehash()
|
||||
|
||||
''' Mine 749 version 4 blocks '''
|
||||
test_blocks = []
|
||||
for i in xrange(749):
|
||||
block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1)
|
||||
block = create_block(self.tip, create_coinbase(1), self.block_time)
|
||||
block.nVersion = 4
|
||||
block.vtx.append(spendtx)
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.rehash()
|
||||
block.solve()
|
||||
test_blocks.append([block, True])
|
||||
self.last_block_time += 1
|
||||
self.block_time += 1
|
||||
self.tip = block.sha256
|
||||
yield TestInstance(test_blocks, sync_every_block=False)
|
||||
yield TestInstance([[block, valid]])
|
||||
|
||||
'''
|
||||
Check that the new CLTV rules are not enforced in the 750th
|
||||
version 3 block.
|
||||
'''
|
||||
spendtx = self.create_transaction(self.nodes[0],
|
||||
self.coinbase_blocks[0], self.nodeaddress, 1.0)
|
||||
cltv_invalidate(spendtx)
|
||||
spendtx.rehash()
|
||||
|
||||
block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1)
|
||||
block.nVersion = 4
|
||||
block.vtx.append(spendtx)
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.rehash()
|
||||
block.solve()
|
||||
|
||||
self.last_block_time += 1
|
||||
self.tip = block.sha256
|
||||
yield TestInstance([[block, True]])
|
||||
|
||||
'''
|
||||
Check that the new CLTV rules are enforced in the 751st version 4
|
||||
block.
|
||||
'''
|
||||
spendtx = self.create_transaction(self.nodes[0],
|
||||
self.coinbase_blocks[1], self.nodeaddress, 1.0)
|
||||
cltv_invalidate(spendtx)
|
||||
spendtx.rehash()
|
||||
|
||||
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
|
||||
block.nVersion = 4
|
||||
block.vtx.append(spendtx)
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.rehash()
|
||||
block.solve()
|
||||
self.last_block_time += 1
|
||||
yield TestInstance([[block, False]])
|
||||
|
||||
''' Mine 199 new version blocks on last valid tip '''
|
||||
test_blocks = []
|
||||
for i in xrange(199):
|
||||
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
|
||||
block.nVersion = 4
|
||||
block.rehash()
|
||||
block.solve()
|
||||
test_blocks.append([block, True])
|
||||
self.last_block_time += 1
|
||||
self.tip = block.sha256
|
||||
yield TestInstance(test_blocks, sync_every_block=False)
|
||||
|
||||
''' Mine 1 old version block '''
|
||||
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
|
||||
block.nVersion = 3
|
||||
block.rehash()
|
||||
block.solve()
|
||||
self.last_block_time += 1
|
||||
self.tip = block.sha256
|
||||
yield TestInstance([[block, True]])
|
||||
|
||||
''' Mine 1 new version block '''
|
||||
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
|
||||
block.nVersion = 4
|
||||
block.rehash()
|
||||
block.solve()
|
||||
self.last_block_time += 1
|
||||
self.tip = block.sha256
|
||||
yield TestInstance([[block, True]])
|
||||
|
||||
''' Mine 1 old version block, should be invalid '''
|
||||
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
|
||||
block.nVersion = 3
|
||||
block.rehash()
|
||||
block.solve()
|
||||
self.last_block_time += 1
|
||||
yield TestInstance([[block, False]])
|
||||
|
||||
if __name__ == '__main__':
|
||||
BIP65Test().main()
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
# Copyright (c) 2015 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#
|
||||
# Test the CHECKLOCKTIMEVERIFY (BIP65) soft-fork logic
|
||||
#
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import *
|
||||
import os
|
||||
import shutil
|
||||
|
||||
class BIP65Test(BitcoinTestFramework):
|
||||
|
||||
def setup_network(self):
|
||||
self.nodes = []
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, []))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=3"]))
|
||||
self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=4"]))
|
||||
connect_nodes(self.nodes[1], 0)
|
||||
connect_nodes(self.nodes[2], 0)
|
||||
self.is_network_split = False
|
||||
self.sync_all()
|
||||
|
||||
def run_test(self):
|
||||
cnt = self.nodes[0].getblockcount()
|
||||
|
||||
# Mine some old-version blocks
|
||||
self.nodes[1].generate(100)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 100):
|
||||
raise AssertionError("Failed to mine 100 version=3 blocks")
|
||||
|
||||
# Mine 750 new-version blocks
|
||||
for i in xrange(15):
|
||||
self.nodes[2].generate(50)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 850):
|
||||
raise AssertionError("Failed to mine 750 version=4 blocks")
|
||||
|
||||
# TODO: check that new CHECKLOCKTIMEVERIFY rules are not enforced
|
||||
|
||||
# Mine 1 new-version block
|
||||
self.nodes[2].generate(1)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 851):
|
||||
raise AssertionFailure("Failed to mine a version=4 blocks")
|
||||
|
||||
# TODO: check that new CHECKLOCKTIMEVERIFY rules are enforced
|
||||
|
||||
# Mine 198 new-version blocks
|
||||
for i in xrange(2):
|
||||
self.nodes[2].generate(99)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1049):
|
||||
raise AssertionError("Failed to mine 198 version=4 blocks")
|
||||
|
||||
# Mine 1 old-version block
|
||||
self.nodes[1].generate(1)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1050):
|
||||
raise AssertionError("Failed to mine a version=3 block after 949 version=4 blocks")
|
||||
|
||||
# Mine 1 new-version blocks
|
||||
self.nodes[2].generate(1)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1051):
|
||||
raise AssertionError("Failed to mine a version=3 block")
|
||||
|
||||
# Mine 1 old-version blocks
|
||||
try:
|
||||
self.nodes[1].generate(1)
|
||||
raise AssertionError("Succeeded to mine a version=3 block after 950 version=4 blocks")
|
||||
except JSONRPCException:
|
||||
pass
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1051):
|
||||
raise AssertionError("Accepted a version=3 block after 950 version=4 blocks")
|
||||
|
||||
# Mine 1 new-version blocks
|
||||
self.nodes[2].generate(1)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1052):
|
||||
raise AssertionError("Failed to mine a version=4 block")
|
||||
|
||||
if __name__ == '__main__':
|
||||
BIP65Test().main()
|
|
@ -5,59 +5,39 @@
|
|||
#
|
||||
|
||||
from test_framework.test_framework import ComparisonTestFramework
|
||||
from test_framework.util import *
|
||||
from test_framework.util import start_nodes
|
||||
from test_framework.mininode import CTransaction, NetworkThread
|
||||
from test_framework.blocktools import create_coinbase, create_block
|
||||
from test_framework.comptool import TestInstance, TestManager
|
||||
from test_framework.script import CScript
|
||||
from binascii import hexlify, unhexlify
|
||||
from binascii import unhexlify
|
||||
import cStringIO
|
||||
import time
|
||||
|
||||
# A canonical signature consists of:
|
||||
# <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
|
||||
def unDERify(tx):
|
||||
'''
|
||||
Make the signature in vin 0 of a tx non-DER-compliant,
|
||||
by adding padding after the S-value.
|
||||
'''
|
||||
scriptSig = CScript(tx.vin[0].scriptSig)
|
||||
newscript = []
|
||||
for i in scriptSig:
|
||||
if (len(newscript) == 0):
|
||||
newscript.append(i[0:-1] + '\0' + i[-1])
|
||||
else:
|
||||
newscript.append(i)
|
||||
tx.vin[0].scriptSig = CScript(newscript)
|
||||
|
||||
'''
|
||||
This test is meant to exercise BIP66 (DER SIG).
|
||||
Connect to a single node.
|
||||
Mine 2 (version 2) blocks (save the coinbases for later).
|
||||
Generate 98 more version 2 blocks, verify the node accepts.
|
||||
Mine 749 version 3 blocks, verify the node accepts.
|
||||
Check that the new DERSIG rules are not enforced on the 750th version 3 block.
|
||||
Check that the new DERSIG rules are enforced on the 751st version 3 block.
|
||||
Mine 199 new version blocks.
|
||||
Mine 1 old-version block.
|
||||
Mine 1 new version block.
|
||||
Mine 1 old version block, see that the node rejects.
|
||||
'''
|
||||
Mine a coinbase block, and then ...
|
||||
Mine 1 version 4 block.
|
||||
Check that the DERSIG rules are enforced.
|
||||
|
||||
TODO: factor out common code from {bipdersig-p2p,bip65-cltv-p2p}.py.
|
||||
'''
|
||||
class BIP66Test(ComparisonTestFramework):
|
||||
|
||||
def __init__(self):
|
||||
self.num_nodes = 1
|
||||
|
||||
def setup_network(self):
|
||||
# Must set the blockversion for this test
|
||||
self.nodes = start_nodes(1, self.options.tmpdir,
|
||||
extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=2']],
|
||||
extra_args=[['-debug', '-whitelist=127.0.0.1']],
|
||||
binary=[self.options.testbinary])
|
||||
self.is_network_split = False
|
||||
|
||||
def run_test(self):
|
||||
test = TestManager(self, self.options.tmpdir)
|
||||
test.add_all_connections(self.nodes)
|
||||
# Don't call test.add_all_connections because there is only one node.
|
||||
NetworkThread().start() # Start up network handling in another thread
|
||||
test.run()
|
||||
|
||||
|
@ -72,112 +52,48 @@ class BIP66Test(ComparisonTestFramework):
|
|||
tx.deserialize(f)
|
||||
return tx
|
||||
|
||||
def get_tests(self):
|
||||
def invalidate_transaction(self, tx):
|
||||
'''
|
||||
Make the signature in vin 0 of a tx non-DER-compliant,
|
||||
by adding padding after the S-value.
|
||||
|
||||
self.coinbase_blocks = self.nodes[0].generate(2)
|
||||
A canonical signature consists of:
|
||||
<30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
|
||||
'''
|
||||
scriptSig = CScript(tx.vin[0].scriptSig)
|
||||
newscript = []
|
||||
for i in scriptSig:
|
||||
if (len(newscript) == 0):
|
||||
newscript.append(i[0:-1] + '\0' + i[-1])
|
||||
else:
|
||||
newscript.append(i)
|
||||
tx.vin[0].scriptSig = CScript(newscript)
|
||||
|
||||
def get_tests(self):
|
||||
self.coinbase_blocks = self.nodes[0].generate(1)
|
||||
self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0)
|
||||
self.nodeaddress = self.nodes[0].getnewaddress()
|
||||
self.last_block_time = time.time()
|
||||
self.block_time = time.time() + 1
|
||||
|
||||
''' 98 more version 2 blocks '''
|
||||
test_blocks = []
|
||||
for i in xrange(98):
|
||||
block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1)
|
||||
block.nVersion = 2
|
||||
'''Check that the rules are enforced.'''
|
||||
for valid in (True, False):
|
||||
spendtx = self.create_transaction(self.nodes[0],
|
||||
self.coinbase_blocks[0],
|
||||
self.nodeaddress, 1.0)
|
||||
if not valid:
|
||||
self.invalidate_transaction(spendtx)
|
||||
spendtx.rehash()
|
||||
|
||||
block = create_block(self.tip, create_coinbase(1), self.block_time)
|
||||
block.nVersion = 4
|
||||
block.vtx.append(spendtx)
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.rehash()
|
||||
block.solve()
|
||||
test_blocks.append([block, True])
|
||||
self.last_block_time += 1
|
||||
self.block_time += 1
|
||||
self.tip = block.sha256
|
||||
yield TestInstance(test_blocks, sync_every_block=False)
|
||||
yield TestInstance([[block, valid]])
|
||||
|
||||
''' Mine 749 version 3 blocks '''
|
||||
test_blocks = []
|
||||
for i in xrange(749):
|
||||
block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1)
|
||||
block.nVersion = 3
|
||||
block.rehash()
|
||||
block.solve()
|
||||
test_blocks.append([block, True])
|
||||
self.last_block_time += 1
|
||||
self.tip = block.sha256
|
||||
yield TestInstance(test_blocks, sync_every_block=False)
|
||||
|
||||
'''
|
||||
Check that the new DERSIG rules are not enforced in the 750th
|
||||
version 3 block.
|
||||
'''
|
||||
spendtx = self.create_transaction(self.nodes[0],
|
||||
self.coinbase_blocks[0], self.nodeaddress, 1.0)
|
||||
unDERify(spendtx)
|
||||
spendtx.rehash()
|
||||
|
||||
block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1)
|
||||
block.nVersion = 3
|
||||
block.vtx.append(spendtx)
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.rehash()
|
||||
block.solve()
|
||||
|
||||
self.last_block_time += 1
|
||||
self.tip = block.sha256
|
||||
yield TestInstance([[block, True]])
|
||||
|
||||
'''
|
||||
Check that the new DERSIG rules are enforced in the 751st version 3
|
||||
block.
|
||||
'''
|
||||
spendtx = self.create_transaction(self.nodes[0],
|
||||
self.coinbase_blocks[1], self.nodeaddress, 1.0)
|
||||
unDERify(spendtx)
|
||||
spendtx.rehash()
|
||||
|
||||
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
|
||||
block.nVersion = 3
|
||||
block.vtx.append(spendtx)
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.rehash()
|
||||
block.solve()
|
||||
self.last_block_time += 1
|
||||
yield TestInstance([[block, False]])
|
||||
|
||||
''' Mine 199 new version blocks on last valid tip '''
|
||||
test_blocks = []
|
||||
for i in xrange(199):
|
||||
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
|
||||
block.nVersion = 3
|
||||
block.rehash()
|
||||
block.solve()
|
||||
test_blocks.append([block, True])
|
||||
self.last_block_time += 1
|
||||
self.tip = block.sha256
|
||||
yield TestInstance(test_blocks, sync_every_block=False)
|
||||
|
||||
''' Mine 1 old version block '''
|
||||
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
|
||||
block.nVersion = 2
|
||||
block.rehash()
|
||||
block.solve()
|
||||
self.last_block_time += 1
|
||||
self.tip = block.sha256
|
||||
yield TestInstance([[block, True]])
|
||||
|
||||
''' Mine 1 new version block '''
|
||||
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
|
||||
block.nVersion = 3
|
||||
block.rehash()
|
||||
block.solve()
|
||||
self.last_block_time += 1
|
||||
self.tip = block.sha256
|
||||
yield TestInstance([[block, True]])
|
||||
|
||||
''' Mine 1 old version block, should be invalid '''
|
||||
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
|
||||
block.nVersion = 2
|
||||
block.rehash()
|
||||
block.solve()
|
||||
self.last_block_time += 1
|
||||
yield TestInstance([[block, False]])
|
||||
|
||||
if __name__ == '__main__':
|
||||
BIP66Test().main()
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
# Copyright (c) 2014 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#
|
||||
# Test the BIP66 changeover logic
|
||||
#
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import *
|
||||
import os
|
||||
import shutil
|
||||
|
||||
class BIP66Test(BitcoinTestFramework):
|
||||
|
||||
def setup_network(self):
|
||||
self.nodes = []
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, []))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=2"]))
|
||||
self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=3"]))
|
||||
connect_nodes(self.nodes[1], 0)
|
||||
connect_nodes(self.nodes[2], 0)
|
||||
self.is_network_split = False
|
||||
self.sync_all()
|
||||
|
||||
def run_test(self):
|
||||
cnt = self.nodes[0].getblockcount()
|
||||
|
||||
# Mine some old-version blocks
|
||||
self.nodes[1].generate(100)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 100):
|
||||
raise AssertionError("Failed to mine 100 version=2 blocks")
|
||||
|
||||
# Mine 750 new-version blocks
|
||||
for i in xrange(15):
|
||||
self.nodes[2].generate(50)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 850):
|
||||
raise AssertionError("Failed to mine 750 version=3 blocks")
|
||||
|
||||
# TODO: check that new DERSIG rules are not enforced
|
||||
|
||||
# Mine 1 new-version block
|
||||
self.nodes[2].generate(1)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 851):
|
||||
raise AssertionFailure("Failed to mine a version=3 blocks")
|
||||
|
||||
# TODO: check that new DERSIG rules are enforced
|
||||
|
||||
# Mine 198 new-version blocks
|
||||
for i in xrange(2):
|
||||
self.nodes[2].generate(99)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1049):
|
||||
raise AssertionError("Failed to mine 198 version=3 blocks")
|
||||
|
||||
# Mine 1 old-version block
|
||||
self.nodes[1].generate(1)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1050):
|
||||
raise AssertionError("Failed to mine a version=2 block after 949 version=3 blocks")
|
||||
|
||||
# Mine 1 new-version blocks
|
||||
self.nodes[2].generate(1)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1051):
|
||||
raise AssertionError("Failed to mine a version=3 block")
|
||||
|
||||
# Mine 1 old-version blocks
|
||||
try:
|
||||
self.nodes[1].generate(1)
|
||||
raise AssertionError("Succeeded to mine a version=2 block after 950 version=3 blocks")
|
||||
except JSONRPCException:
|
||||
pass
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1051):
|
||||
raise AssertionError("Accepted a version=2 block after 950 version=3 blocks")
|
||||
|
||||
# Mine 1 new-version blocks
|
||||
self.nodes[2].generate(1)
|
||||
self.sync_all()
|
||||
if (self.nodes[0].getblockcount() != cnt + 1052):
|
||||
raise AssertionError("Failed to mine a version=3 block")
|
||||
|
||||
if __name__ == '__main__':
|
||||
BIP66Test().main()
|
|
@ -0,0 +1,152 @@
|
|||
#!/usr/bin/env python2
|
||||
# Copyright (c) 2017 The Zcash developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import *
|
||||
import os
|
||||
import shutil
|
||||
from time import sleep
|
||||
|
||||
# Test -mempooltxinputlimit
|
||||
class MempoolTxInputLimitTest(BitcoinTestFramework):
|
||||
|
||||
alert_filename = None # Set by setup_network
|
||||
|
||||
def setup_network(self):
|
||||
args = ["-checkmempool", "-debug=mempool", "-mempooltxinputlimit=2"]
|
||||
self.nodes = []
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, args))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, args))
|
||||
connect_nodes(self.nodes[1], 0)
|
||||
self.is_network_split = False
|
||||
self.sync_all
|
||||
|
||||
def setup_chain(self):
|
||||
print "Initializing test directory "+self.options.tmpdir
|
||||
initialize_chain_clean(self.options.tmpdir, 2)
|
||||
|
||||
def call_z_sendmany(self, from_addr, to_addr, amount):
|
||||
recipients = []
|
||||
recipients.append({"address": to_addr, "amount": amount})
|
||||
myopid = self.nodes[0].z_sendmany(from_addr, recipients)
|
||||
return self.wait_and_assert_operationid_status(myopid)
|
||||
|
||||
def wait_and_assert_operationid_status(self, myopid, in_status='success', in_errormsg=None):
|
||||
print('waiting for async operation {}'.format(myopid))
|
||||
opids = []
|
||||
opids.append(myopid)
|
||||
timeout = 300
|
||||
status = None
|
||||
errormsg = None
|
||||
txid = None
|
||||
for x in xrange(1, timeout):
|
||||
results = self.nodes[0].z_getoperationresult(opids)
|
||||
if len(results)==0:
|
||||
sleep(1)
|
||||
else:
|
||||
status = results[0]["status"]
|
||||
if status == "failed":
|
||||
errormsg = results[0]['error']['message']
|
||||
elif status == "success":
|
||||
txid = results[0]['result']['txid']
|
||||
break
|
||||
print('...returned status: {}'.format(status))
|
||||
assert_equal(in_status, status)
|
||||
if errormsg is not None:
|
||||
assert(in_errormsg is not None)
|
||||
assert_equal(in_errormsg in errormsg, True)
|
||||
print('...returned error: {}'.format(errormsg))
|
||||
return txid
|
||||
|
||||
def run_test(self):
|
||||
start_count = self.nodes[0].getblockcount()
|
||||
|
||||
self.nodes[0].generate(100)
|
||||
self.sync_all()
|
||||
# Mine three blocks. After this, nodes[0] blocks
|
||||
# 1, 2, and 3 are spend-able.
|
||||
self.nodes[1].generate(3)
|
||||
self.sync_all()
|
||||
|
||||
# Check 1: z_sendmany is limited by -mempooltxinputlimit
|
||||
|
||||
# Add zaddr to node 0
|
||||
node0_zaddr = self.nodes[0].z_getnewaddress()
|
||||
|
||||
# Send three inputs from node 0 taddr to zaddr to get out of coinbase
|
||||
node0_taddr = self.nodes[0].getnewaddress();
|
||||
recipients = []
|
||||
recipients.append({"address":node0_zaddr, "amount":Decimal('30.0')-Decimal('0.0001')}) # utxo amount less fee
|
||||
myopid = self.nodes[0].z_sendmany(node0_taddr, recipients)
|
||||
|
||||
opids = []
|
||||
opids.append(myopid)
|
||||
|
||||
# Spend should fail due to -mempooltxinputlimit
|
||||
timeout = 120
|
||||
status = None
|
||||
for x in xrange(1, timeout):
|
||||
results = self.nodes[0].z_getoperationresult(opids)
|
||||
if len(results)==0:
|
||||
sleep(1)
|
||||
else:
|
||||
status = results[0]["status"]
|
||||
msg = results[0]["error"]["message"]
|
||||
assert_equal("failed", status)
|
||||
assert_equal("Too many transparent inputs 3 > limit 2", msg)
|
||||
break
|
||||
|
||||
# Mempool should be empty.
|
||||
assert_equal(set(self.nodes[0].getrawmempool()), set())
|
||||
|
||||
# Reduce amount to only use two inputs
|
||||
spend_zaddr_amount = Decimal('20.0') - Decimal('0.0001')
|
||||
spend_zaddr_id = self.call_z_sendmany(node0_taddr, node0_zaddr, spend_zaddr_amount) # utxo amount less fee
|
||||
self.sync_all()
|
||||
|
||||
# Spend should be in the mempool
|
||||
assert_equal(set(self.nodes[0].getrawmempool()), set([ spend_zaddr_id ]))
|
||||
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
# mempool should be empty.
|
||||
assert_equal(set(self.nodes[0].getrawmempool()), set())
|
||||
|
||||
# Check 2: sendfrom is limited by -mempooltxinputlimit
|
||||
node1_taddr = self.nodes[1].getnewaddress();
|
||||
recipients = []
|
||||
spend_taddr_amount = spend_zaddr_amount - Decimal('0.0001')
|
||||
spend_taddr_output = Decimal('8')
|
||||
|
||||
# Create three outputs
|
||||
recipients.append({"address":self.nodes[1].getnewaddress(), "amount": spend_taddr_output})
|
||||
recipients.append({"address":self.nodes[1].getnewaddress(), "amount": spend_taddr_output})
|
||||
recipients.append({"address":self.nodes[1].getnewaddress(), "amount": spend_taddr_amount - spend_taddr_output - spend_taddr_output})
|
||||
|
||||
myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients)
|
||||
self.wait_and_assert_operationid_status(myopid)
|
||||
self.nodes[1].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
# Should use three UTXOs and fail
|
||||
try:
|
||||
self.nodes[1].sendfrom("", node0_taddr, spend_taddr_amount - Decimal('1'))
|
||||
assert(False)
|
||||
except JSONRPCException,e:
|
||||
msg = e.error['message']
|
||||
assert_equal("Too many transparent inputs 3 > limit 2", msg)
|
||||
|
||||
# mempool should be empty.
|
||||
assert_equal(set(self.nodes[1].getrawmempool()), set())
|
||||
|
||||
# Should use two UTXOs and succeed
|
||||
spend_taddr_id2 = self.nodes[1].sendfrom("", node0_taddr, spend_taddr_output + spend_taddr_output - Decimal('1'))
|
||||
|
||||
# Spend should be in the mempool
|
||||
assert_equal(set(self.nodes[1].getrawmempool()), set([ spend_taddr_id2 ]))
|
||||
|
||||
if __name__ == '__main__':
|
||||
MempoolTxInputLimitTest().main()
|
|
@ -56,7 +56,6 @@ class ScriptTestFile(object):
|
|||
SCRIPT_VERIFY_NONE = 0
|
||||
SCRIPT_VERIFY_P2SH = 1
|
||||
SCRIPT_VERIFY_STRICTENC = 1 << 1
|
||||
SCRIPT_VERIFY_DERSIG = 1 << 2
|
||||
SCRIPT_VERIFY_LOW_S = 1 << 3
|
||||
SCRIPT_VERIFY_NULLDUMMY = 1 << 4
|
||||
SCRIPT_VERIFY_SIGPUSHONLY = 1 << 5
|
||||
|
@ -69,7 +68,6 @@ flag_map = {
|
|||
"NONE": SCRIPT_VERIFY_NONE,
|
||||
"P2SH": SCRIPT_VERIFY_P2SH,
|
||||
"STRICTENC": SCRIPT_VERIFY_STRICTENC,
|
||||
"DERSIG": SCRIPT_VERIFY_DERSIG,
|
||||
"LOW_S": SCRIPT_VERIFY_LOW_S,
|
||||
"NULLDUMMY": SCRIPT_VERIFY_NULLDUMMY,
|
||||
"SIGPUSHONLY": SCRIPT_VERIFY_SIGPUSHONLY,
|
||||
|
|
|
@ -124,9 +124,7 @@ BITCOIN_CORE_H = \
|
|||
consensus/validation.h \
|
||||
core_io.h \
|
||||
core_memusage.h \
|
||||
eccryptoverify.h \
|
||||
deprecation.h \
|
||||
ecwrapper.h \
|
||||
hash.h \
|
||||
httprpc.h \
|
||||
httpserver.h \
|
||||
|
@ -326,8 +324,6 @@ libbitcoin_common_a_SOURCES = \
|
|||
compressor.cpp \
|
||||
core_read.cpp \
|
||||
core_write.cpp \
|
||||
eccryptoverify.cpp \
|
||||
ecwrapper.cpp \
|
||||
hash.cpp \
|
||||
key.cpp \
|
||||
keystore.cpp \
|
||||
|
@ -505,8 +501,6 @@ libzcashconsensus_la_SOURCES = \
|
|||
crypto/sha1.cpp \
|
||||
crypto/sha256.cpp \
|
||||
crypto/sha512.cpp \
|
||||
eccryptoverify.cpp \
|
||||
ecwrapper.cpp \
|
||||
hash.cpp \
|
||||
primitives/transaction.cpp \
|
||||
pubkey.cpp \
|
||||
|
@ -521,8 +515,8 @@ if GLIBC_BACK_COMPAT
|
|||
endif
|
||||
|
||||
libzcashconsensus_la_LDFLAGS = -no-undefined $(RELDFLAGS)
|
||||
libzcashconsensus_la_LIBADD = $(CRYPTO_LIBS)
|
||||
libzcashconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCOIN_INTERNAL
|
||||
libzcashconsensus_la_LIBADD = $(LIBSECP256K1)
|
||||
libzcashconsensus_la_CPPFLAGS = -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL
|
||||
|
||||
endif
|
||||
#
|
||||
|
|
|
@ -31,6 +31,7 @@ zcash_gtest_SOURCES += \
|
|||
gtest/test_random.cpp \
|
||||
gtest/test_rpc.cpp \
|
||||
gtest/test_transaction.cpp \
|
||||
gtest/test_validation.cpp \
|
||||
gtest/test_circuit.cpp \
|
||||
gtest/test_txid.cpp \
|
||||
gtest/test_libzcash_utils.cpp \
|
||||
|
|
|
@ -445,9 +445,15 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
|
|||
|
||||
class Secp256k1Init
|
||||
{
|
||||
ECCVerifyHandle globalVerifyHandle;
|
||||
|
||||
public:
|
||||
Secp256k1Init() { ECC_Start(); }
|
||||
~Secp256k1Init() { ECC_Stop(); }
|
||||
Secp256k1Init() {
|
||||
ECC_Start();
|
||||
}
|
||||
~Secp256k1Init() {
|
||||
ECC_Stop();
|
||||
}
|
||||
};
|
||||
|
||||
static void MutateTx(CMutableTransaction& tx, const string& command,
|
||||
|
|
|
@ -59,7 +59,6 @@ public:
|
|||
pchMessageStart[3] = 0x64;
|
||||
vAlertPubKey = ParseHex("048679fb891b15d0cada9692047fd0ae26ad8bfb83fabddbb50334ee5bc0683294deb410be20513c5af6e7b9cec717ade82b27080ee6ef9a245c36a795ab044bb3");
|
||||
nDefaultPort = 8033;
|
||||
nMinerThreads = 0;
|
||||
nMaxTipAge = 24 * 60 * 60;
|
||||
nPruneAfterHeight = 100000;
|
||||
const size_t N = 200, K = 9;
|
||||
|
@ -98,7 +97,7 @@ public:
|
|||
vFixedSeeds.clear();
|
||||
vSeeds.clear();
|
||||
//vSeeds.push_back(CDNSSeedData("zclassic.org", "dnsseed.zclassic.org")); // zclassic
|
||||
vSeeds.push_back(CDNSSeedData("indieonion.org", "dnsseed.indieonion.org")); // @IndieOnion
|
||||
vSeeds.push_back(CDNSSeedData("indieonion.org", "dnsseed.indieonion.org")); // @IndieOnion
|
||||
vSeeds.push_back(CDNSSeedData("rotorproject.org", "dnsseed.rotorproject.org")); // @IndieOnion
|
||||
|
||||
// guarantees the first 2 characters, when base58 encoded, are "t1"
|
||||
|
@ -126,11 +125,12 @@ public:
|
|||
checkpointData = (Checkpoints::CCheckpointData) {
|
||||
boost::assign::map_list_of
|
||||
( 0, consensus.hashGenesisBlock)
|
||||
( 30000, uint256S("0x000000005c2ad200c3c7c8e627f67b306659efca1268c9bb014335fdadc0c392")),
|
||||
1482914970, // * UNIX timestamp of last checkpoint block
|
||||
82372, // * total number of transactions between genesis and last checkpoint
|
||||
( 30000, uint256S("0x000000005c2ad200c3c7c8e627f67b306659efca1268c9bb014335fdadc0c392"))
|
||||
( 160000, uint256S("0x000000065093005a1a46ee95d6d66c2b07008220ca64dd3b3a93bbd1945480c0")),
|
||||
1502742046, // * UNIX timestamp of last checkpoint block
|
||||
392489, // * total number of transactions between genesis and last checkpoint
|
||||
// (the tx=... number in the SetBestChain debug.log lines)
|
||||
1581 // * estimated number of transactions per day after checkpoint
|
||||
1413 // * estimated number of transactions per day after checkpoint
|
||||
// total number of tx / (checkpoint block height / (24 * 24))
|
||||
};
|
||||
|
||||
|
@ -217,7 +217,6 @@ public:
|
|||
pchMessageStart[3] = 0xbf;
|
||||
vAlertPubKey = ParseHex("048679fb891b15d0cada9692047fd0ae26ad8bfb83fabddbb50334ee5bc0683294deb410be20513c5af6e7b9cec717ade82b27080ee6ef9a245c36a795ab044bb3");
|
||||
nDefaultPort = 18233;
|
||||
nMinerThreads = 0;
|
||||
nPruneAfterHeight = 1000;
|
||||
|
||||
//! Modify the testnet genesis block so the timestamp is valid for a later start.
|
||||
|
@ -264,7 +263,7 @@ public:
|
|||
|
||||
// Founders reward script expects a vector of 2-of-3 multisig addresses
|
||||
vFoundersRewardAddress = {
|
||||
/*
|
||||
/*
|
||||
"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", "t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543", "t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2", "t27ktmq1kbeCWiQ5TZ7w5npSzcdbBmTB7v6",
|
||||
"t2GcBttAKD2WTHka8HyGc2dfvVTKYZUfHmJ", "t2Q3vxWaD9LrdqUE8Xd9Ddjpr9pUQ2aGotK", "t2TTfWDsYu998fHWzVP9Gns4fgxXXRi1Wzu", "t2KS6R4MMWdSBMjLCiw2iMyhWGRQPmyRqDn",
|
||||
"t2Q2ELrgotWv3Eec6LEtMMiiQ8dtW38u8Tj", "t2AEgJA88vTWAKqxJDFUEJWyHUtQAZi5G1D", "t2HCSdmpq1TQKksuwPQevwAzPTgfJ2rkMbG", "t2HQCPFAUQaUdJWHPhg5pPBxit7inaJzubE",
|
||||
|
@ -277,7 +276,7 @@ public:
|
|||
"t2DN7X6wDFn5hYKBiBmn3Z98st419yaTVTH", "t2QJj8HeCwQ6mHwqekxxDLZntYpZTHNU62t", "t2QdHBR1Yciqn4j8gpS8DcQZZtYetKvfNj3", "t2E5cpLA1ey5VNxFNcuopeQMq2rH2NHiPdu",
|
||||
"t2EVRGtzjFAyz8CF8ndvLuiJu7qZUfDa93H", "t2KoQDk3BSFadBkuaWdLwchFuQamzw9RE4L", "t2FnR3yhTmuiejEJeu6qpidWTghRd1HpjLt", "t2BAuBAAospDc9d1u5nNGEi6x4NRJBD2PQ2",
|
||||
"t2RtKrLCGcyPkm4a4APg1YY9Wu2m4R2PgrB", "t28aUbSteZzBq2pFgj1K1XNZRZP5mMMyakV", "t2Urdy1ERfkvsFuy6Z4BkhvYGzWdmivfAFR", "t2ADinR4JrvCMd4Q1XGALPajzFrirqvhED6",
|
||||
*/
|
||||
*/
|
||||
};
|
||||
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight());
|
||||
}
|
||||
|
@ -306,7 +305,6 @@ public:
|
|||
pchMessageStart[1] = 0xe8;
|
||||
pchMessageStart[2] = 0x3f;
|
||||
pchMessageStart[3] = 0x5f;
|
||||
nMinerThreads = 1;
|
||||
nMaxTipAge = 24 * 60 * 60;
|
||||
const size_t N = 48, K = 5;
|
||||
BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K));
|
||||
|
@ -317,8 +315,8 @@ public:
|
|||
genesis.nNonce = uint256S("0x0000000000000000000000000000000000000000000000000000000000000009");
|
||||
genesis.nSolution = ParseHex("05ffd6ad016271ade20cfce093959c3addb2079629f9f123c52ef920caa316531af5af3f");
|
||||
consensus.hashGenesisBlock = genesis.GetHash();
|
||||
nDefaultPort = 18033;
|
||||
assert(consensus.hashGenesisBlock == uint256S("0x0575f78ee8dc057deee78ef691876e3be29833aaee5e189bb0459c087451305a"));
|
||||
nDefaultPort = 18033;
|
||||
assert(consensus.hashGenesisBlock == uint256S("0x0575f78ee8dc057deee78ef691876e3be29833aaee5e189bb0459c087451305a"));
|
||||
nPruneAfterHeight = 1000;
|
||||
|
||||
vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds.
|
||||
|
@ -340,7 +338,7 @@ public:
|
|||
|
||||
// Founders reward script expects a vector of 2-of-3 multisig addresses
|
||||
//vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" };
|
||||
vFoundersRewardAddress = { };
|
||||
vFoundersRewardAddress = { };
|
||||
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -53,8 +53,6 @@ public:
|
|||
const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
|
||||
int GetDefaultPort() const { return nDefaultPort; }
|
||||
|
||||
/** Used if GenerateBitcoins is called with a negative number of threads */
|
||||
int DefaultMinerThreads() const { return nMinerThreads; }
|
||||
const CBlock& GenesisBlock() const { return genesis; }
|
||||
/** Make miner wait to have peers to avoid wasting work */
|
||||
bool MiningRequiresPeers() const { return fMiningRequiresPeers; }
|
||||
|
@ -91,7 +89,6 @@ protected:
|
|||
//! Raw pub key bytes for the broadcast alert signing key.
|
||||
std::vector<unsigned char> vAlertPubKey;
|
||||
int nDefaultPort = 0;
|
||||
int nMinerThreads = 0;
|
||||
long nMaxTipAge = 0;
|
||||
uint64_t nPruneAfterHeight = 0;
|
||||
unsigned int nEquihashN = 0;
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
|
||||
#define CLIENT_VERSION_MAJOR 1
|
||||
#define CLIENT_VERSION_MINOR 0
|
||||
#define CLIENT_VERSION_REVISION 9
|
||||
#define CLIENT_VERSION_BUILD 50
|
||||
#define CLIENT_VERSION_REVISION 10
|
||||
#define CLIENT_VERSION_BUILD 51
|
||||
|
||||
//! Set to true for release, false for prerelease or test build
|
||||
#define CLIENT_VERSION_IS_RELEASE true
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#define ZCASH_DEPRECATION_H
|
||||
|
||||
// Deprecation policy is 4th third-Tuesday after a release
|
||||
static const int APPROX_RELEASE_HEIGHT = 120500;
|
||||
static const int APPROX_RELEASE_HEIGHT = 137236;
|
||||
static const int WEEKS_UNTIL_DEPRECATION = 18;
|
||||
static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24);
|
||||
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "eccryptoverify.h"
|
||||
|
||||
namespace {
|
||||
|
||||
int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char *c2, size_t c2len) {
|
||||
while (c1len > c2len) {
|
||||
if (*c1)
|
||||
return 1;
|
||||
c1++;
|
||||
c1len--;
|
||||
}
|
||||
while (c2len > c1len) {
|
||||
if (*c2)
|
||||
return -1;
|
||||
c2++;
|
||||
c2len--;
|
||||
}
|
||||
while (c1len > 0) {
|
||||
if (*c1 > *c2)
|
||||
return 1;
|
||||
if (*c2 > *c1)
|
||||
return -1;
|
||||
c1++;
|
||||
c2++;
|
||||
c1len--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Order of secp256k1's generator minus 1. */
|
||||
const unsigned char vchMaxModOrder[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
|
||||
};
|
||||
|
||||
/** Half of the order of secp256k1's generator minus 1. */
|
||||
const unsigned char vchMaxModHalfOrder[32] = {
|
||||
0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0x5D,0x57,0x6E,0x73,0x57,0xA4,0x50,0x1D,
|
||||
0xDF,0xE9,0x2F,0x46,0x68,0x1B,0x20,0xA0
|
||||
};
|
||||
|
||||
const unsigned char vchZero[1] = {0};
|
||||
} // anon namespace
|
||||
|
||||
namespace eccrypto {
|
||||
|
||||
bool Check(const unsigned char *vch) {
|
||||
return vch &&
|
||||
CompareBigEndian(vch, 32, vchZero, 0) > 0 &&
|
||||
CompareBigEndian(vch, 32, vchMaxModOrder, 32) <= 0;
|
||||
}
|
||||
|
||||
bool CheckSignatureElement(const unsigned char *vch, int len, bool half) {
|
||||
return vch &&
|
||||
CompareBigEndian(vch, len, vchZero, 0) > 0 &&
|
||||
CompareBigEndian(vch, len, half ? vchMaxModHalfOrder : vchMaxModOrder, 32) <= 0;
|
||||
}
|
||||
|
||||
} // namespace eccrypto
|
|
@ -1,21 +0,0 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_ECCRYPTOVERIFY_H
|
||||
#define BITCOIN_ECCRYPTOVERIFY_H
|
||||
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
|
||||
class uint256;
|
||||
|
||||
namespace eccrypto {
|
||||
|
||||
bool Check(const unsigned char *vch);
|
||||
bool CheckSignatureElement(const unsigned char *vch, int len, bool half);
|
||||
|
||||
} // eccrypto namespace
|
||||
|
||||
#endif // BITCOIN_ECCRYPTOVERIFY_H
|
|
@ -1,223 +0,0 @@
|
|||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "ecwrapper.h"
|
||||
|
||||
#include "serialize.h"
|
||||
#include "uint256.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
|
||||
namespace {
|
||||
|
||||
class ecgroup_order
|
||||
{
|
||||
public:
|
||||
static const EC_GROUP* get()
|
||||
{
|
||||
static const ecgroup_order wrapper;
|
||||
return wrapper.pgroup;
|
||||
}
|
||||
|
||||
private:
|
||||
ecgroup_order()
|
||||
: pgroup(EC_GROUP_new_by_curve_name(NID_secp256k1))
|
||||
{
|
||||
}
|
||||
|
||||
~ecgroup_order()
|
||||
{
|
||||
EC_GROUP_free(pgroup);
|
||||
}
|
||||
|
||||
EC_GROUP* pgroup;
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
|
||||
* recid selects which key is recovered
|
||||
* if check is non-zero, additional checks are performed
|
||||
*/
|
||||
int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
|
||||
{
|
||||
if (!eckey) return 0;
|
||||
|
||||
int ret = 0;
|
||||
BN_CTX *ctx = NULL;
|
||||
|
||||
BIGNUM *x = NULL;
|
||||
BIGNUM *e = NULL;
|
||||
BIGNUM *order = NULL;
|
||||
BIGNUM *sor = NULL;
|
||||
BIGNUM *eor = NULL;
|
||||
BIGNUM *field = NULL;
|
||||
EC_POINT *R = NULL;
|
||||
EC_POINT *O = NULL;
|
||||
EC_POINT *Q = NULL;
|
||||
BIGNUM *rr = NULL;
|
||||
BIGNUM *zero = NULL;
|
||||
int n = 0;
|
||||
int i = recid / 2;
|
||||
|
||||
const BIGNUM *sig_r, *sig_s;
|
||||
ECDSA_SIG_get0(ecsig, &sig_r, &sig_s);
|
||||
|
||||
const EC_GROUP *group = EC_KEY_get0_group(eckey);
|
||||
if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
|
||||
BN_CTX_start(ctx);
|
||||
order = BN_CTX_get(ctx);
|
||||
if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
|
||||
x = BN_CTX_get(ctx);
|
||||
if (!BN_copy(x, order)) { ret=-1; goto err; }
|
||||
if (!BN_mul_word(x, i)) { ret=-1; goto err; }
|
||||
if (!BN_add(x, x, sig_r)) { ret=-1; goto err; }
|
||||
field = BN_CTX_get(ctx);
|
||||
if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
|
||||
if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
|
||||
if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
|
||||
if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
|
||||
if (check)
|
||||
{
|
||||
if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
|
||||
if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
|
||||
if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
|
||||
}
|
||||
if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
|
||||
n = EC_GROUP_get_degree(group);
|
||||
e = BN_CTX_get(ctx);
|
||||
if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
|
||||
if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
|
||||
zero = BN_CTX_get(ctx);
|
||||
if (!BN_zero(zero)) { ret=-1; goto err; }
|
||||
if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
|
||||
rr = BN_CTX_get(ctx);
|
||||
if (!BN_mod_inverse(rr, sig_r, order, ctx)) { ret=-1; goto err; }
|
||||
sor = BN_CTX_get(ctx);
|
||||
if (!BN_mod_mul(sor, sig_s, rr, order, ctx)) { ret=-1; goto err; }
|
||||
eor = BN_CTX_get(ctx);
|
||||
if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
|
||||
if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
|
||||
if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
if (ctx) {
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
if (R != NULL) EC_POINT_free(R);
|
||||
if (O != NULL) EC_POINT_free(O);
|
||||
if (Q != NULL) EC_POINT_free(Q);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
CECKey::CECKey() {
|
||||
pkey = EC_KEY_new();
|
||||
assert(pkey != NULL);
|
||||
int result = EC_KEY_set_group(pkey, ecgroup_order::get());
|
||||
assert(result);
|
||||
}
|
||||
|
||||
CECKey::~CECKey() {
|
||||
EC_KEY_free(pkey);
|
||||
}
|
||||
|
||||
void CECKey::GetPubKey(std::vector<unsigned char> &pubkey, bool fCompressed) {
|
||||
EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
|
||||
int nSize = i2o_ECPublicKey(pkey, NULL);
|
||||
assert(nSize);
|
||||
assert(nSize <= 65);
|
||||
pubkey.clear();
|
||||
pubkey.resize(nSize);
|
||||
unsigned char *pbegin(begin_ptr(pubkey));
|
||||
int nSize2 = i2o_ECPublicKey(pkey, &pbegin);
|
||||
assert(nSize == nSize2);
|
||||
}
|
||||
|
||||
bool CECKey::SetPubKey(const unsigned char* pubkey, size_t size) {
|
||||
return o2i_ECPublicKey(&pkey, &pubkey, size) != NULL;
|
||||
}
|
||||
|
||||
bool CECKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
|
||||
if (vchSig.empty())
|
||||
return false;
|
||||
|
||||
// New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first.
|
||||
unsigned char *norm_der = NULL;
|
||||
ECDSA_SIG *norm_sig = ECDSA_SIG_new();
|
||||
const unsigned char* sigptr = &vchSig[0];
|
||||
assert(norm_sig);
|
||||
if (d2i_ECDSA_SIG(&norm_sig, &sigptr, vchSig.size()) == NULL)
|
||||
{
|
||||
/* As of OpenSSL 1.0.0p d2i_ECDSA_SIG frees and nulls the pointer on
|
||||
* error. But OpenSSL's own use of this function redundantly frees the
|
||||
* result. As ECDSA_SIG_free(NULL) is a no-op, and in the absence of a
|
||||
* clear contract for the function behaving the same way is more
|
||||
* conservative.
|
||||
*/
|
||||
ECDSA_SIG_free(norm_sig);
|
||||
return false;
|
||||
}
|
||||
int derlen = i2d_ECDSA_SIG(norm_sig, &norm_der);
|
||||
ECDSA_SIG_free(norm_sig);
|
||||
if (derlen <= 0)
|
||||
return false;
|
||||
|
||||
// -1 = error, 0 = bad sig, 1 = good
|
||||
bool ret = ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), norm_der, derlen, pkey) == 1;
|
||||
OPENSSL_free(norm_der);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CECKey::Recover(const uint256 &hash, const unsigned char *p64, int rec)
|
||||
{
|
||||
if (rec<0 || rec>=3)
|
||||
return false;
|
||||
ECDSA_SIG *sig = ECDSA_SIG_new();
|
||||
BIGNUM *sig_r = BN_bin2bn(&p64[0], 32, nullptr);
|
||||
BIGNUM *sig_s = BN_bin2bn(&p64[32], 32, nullptr);
|
||||
assert(sig && sig_r && sig_s);
|
||||
bool ret = ECDSA_SIG_set0(sig, sig_r, sig_s);
|
||||
assert(ret);
|
||||
ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
|
||||
ECDSA_SIG_free(sig);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CECKey::TweakPublic(const unsigned char vchTweak[32]) {
|
||||
bool ret = true;
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_CTX_start(ctx);
|
||||
BIGNUM *bnTweak = BN_CTX_get(ctx);
|
||||
BIGNUM *bnOrder = BN_CTX_get(ctx);
|
||||
BIGNUM *bnOne = BN_CTX_get(ctx);
|
||||
const EC_GROUP *group = EC_KEY_get0_group(pkey);
|
||||
EC_GROUP_get_order(group, bnOrder, ctx); // what a grossly inefficient way to get the (constant) group order...
|
||||
BN_bin2bn(vchTweak, 32, bnTweak);
|
||||
if (BN_cmp(bnTweak, bnOrder) >= 0)
|
||||
ret = false; // extremely unlikely
|
||||
EC_POINT *point = EC_POINT_dup(EC_KEY_get0_public_key(pkey), group);
|
||||
BN_one(bnOne);
|
||||
EC_POINT_mul(group, point, bnTweak, point, bnOne, ctx);
|
||||
if (EC_POINT_is_at_infinity(group, point))
|
||||
ret = false; // ridiculously unlikely
|
||||
EC_KEY_set_public_key(pkey, point);
|
||||
EC_POINT_free(point);
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CECKey::SanityCheck()
|
||||
{
|
||||
const EC_GROUP *pgroup = ecgroup_order::get();
|
||||
if(pgroup == NULL)
|
||||
return false;
|
||||
// TODO Is there more EC functionality that could be missing?
|
||||
return true;
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_ECWRAPPER_H
|
||||
#define BITCOIN_ECWRAPPER_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/ec.h>
|
||||
|
||||
class uint256;
|
||||
|
||||
/** RAII Wrapper around OpenSSL's EC_KEY */
|
||||
class CECKey {
|
||||
private:
|
||||
EC_KEY *pkey;
|
||||
|
||||
public:
|
||||
CECKey();
|
||||
~CECKey();
|
||||
|
||||
void GetPubKey(std::vector<unsigned char>& pubkey, bool fCompressed);
|
||||
bool SetPubKey(const unsigned char* pubkey, size_t size);
|
||||
bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig);
|
||||
|
||||
/**
|
||||
* reconstruct public key from a compact signature
|
||||
* This is only slightly more CPU intensive than just verifying it.
|
||||
* If this function succeeds, the recovered public key is guaranteed to be valid
|
||||
* (the signature is a valid signature of the given data for that key)
|
||||
*/
|
||||
bool Recover(const uint256 &hash, const unsigned char *p64, int rec);
|
||||
|
||||
bool TweakPublic(const unsigned char vchTweak[32]);
|
||||
static bool SanityCheck();
|
||||
};
|
||||
|
||||
#endif // BITCOIN_ECWRAPPER_H
|
|
@ -1,9 +1,17 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include "crypto/common.h"
|
||||
#include "pubkey.h"
|
||||
|
||||
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
|
||||
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
|
||||
|
||||
struct ECCryptoClosure
|
||||
{
|
||||
ECCVerifyHandle handle;
|
||||
};
|
||||
|
||||
ECCryptoClosure instance_of_eccryptoclosure;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
assert(init_and_check_sodium() != -1);
|
||||
libsnark::default_r1cs_ppzksnark_pp::init_public_params();
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <gtest/gtest-spi.h>
|
||||
|
||||
#include "consensus/validation.h"
|
||||
#include "core_io.h"
|
||||
#include "main.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "txmempool.h"
|
||||
#include "policy/fees.h"
|
||||
#include "util.h"
|
||||
|
||||
// Fake the input of transaction 5295156213414ed77f6e538e7e8ebe14492156906b9fe995b242477818789364
|
||||
// - 532639cc6bebed47c1c69ae36dd498c68a012e74ad12729adbd3dbb56f8f3f4a, 0
|
||||
|
@ -87,3 +90,49 @@ TEST(Mempool, PriorityStatsDoNotCrash) {
|
|||
|
||||
EXPECT_EQ(dPriority, MAX_PRIORITY);
|
||||
}
|
||||
|
||||
TEST(Mempool, TxInputLimit) {
|
||||
CTxMemPool pool(::minRelayTxFee);
|
||||
bool missingInputs;
|
||||
|
||||
// Create an obviously-invalid transaction
|
||||
// We intentionally set tx.nVersion = 0 to reliably trigger an error, as
|
||||
// it's the first check that occurs after the -mempooltxinputlimit check,
|
||||
// and it means that we don't have to mock out a lot of global state.
|
||||
CMutableTransaction mtx;
|
||||
mtx.nVersion = 0;
|
||||
mtx.vin.resize(10);
|
||||
|
||||
// Check it fails as expected
|
||||
CValidationState state1;
|
||||
CTransaction tx1(mtx);
|
||||
EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs));
|
||||
EXPECT_EQ(state1.GetRejectReason(), "bad-txns-version-too-low");
|
||||
|
||||
// Set a limit
|
||||
mapArgs["-mempooltxinputlimit"] = "10";
|
||||
|
||||
// Check it stil fails as expected
|
||||
CValidationState state2;
|
||||
EXPECT_FALSE(AcceptToMemoryPool(pool, state2, tx1, false, &missingInputs));
|
||||
EXPECT_EQ(state2.GetRejectReason(), "bad-txns-version-too-low");
|
||||
|
||||
// Resize the transaction
|
||||
mtx.vin.resize(11);
|
||||
|
||||
// Check it now fails due to exceeding the limit
|
||||
CValidationState state3;
|
||||
CTransaction tx3(mtx);
|
||||
EXPECT_FALSE(AcceptToMemoryPool(pool, state3, tx3, false, &missingInputs));
|
||||
// The -mempooltxinputlimit check doesn't set a reason
|
||||
EXPECT_EQ(state3.GetRejectReason(), "");
|
||||
|
||||
// Clear the limit
|
||||
mapArgs.erase("-mempooltxinputlimit");
|
||||
|
||||
// Check it no longer fails due to exceeding the limit
|
||||
CValidationState state4;
|
||||
EXPECT_FALSE(AcceptToMemoryPool(pool, state4, tx3, false, &missingInputs));
|
||||
EXPECT_EQ(state4.GetRejectReason(), "bad-txns-version-too-low");
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "consensus/validation.h"
|
||||
#include "main.h"
|
||||
|
||||
// Fake an empty view
|
||||
class FakeCoinsViewDB : public CCoinsView {
|
||||
public:
|
||||
FakeCoinsViewDB() {}
|
||||
|
||||
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetNullifier(const uint256 &nf) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetCoins(const uint256 &txid, CCoins &coins) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HaveCoins(const uint256 &txid) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint256 GetBestBlock() const {
|
||||
uint256 a;
|
||||
return a;
|
||||
}
|
||||
|
||||
uint256 GetBestAnchor() const {
|
||||
uint256 a;
|
||||
return a;
|
||||
}
|
||||
|
||||
bool BatchWrite(CCoinsMap &mapCoins,
|
||||
const uint256 &hashBlock,
|
||||
const uint256 &hashAnchor,
|
||||
CAnchorsMap &mapAnchors,
|
||||
CNullifiersMap &mapNullifiers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetStats(CCoinsStats &stats) const {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Validation, ContextualCheckInputsPassesWithCoinbase) {
|
||||
// Create fake coinbase transaction
|
||||
CMutableTransaction mtx;
|
||||
mtx.vin.resize(1);
|
||||
CTransaction tx(mtx);
|
||||
ASSERT_TRUE(tx.IsCoinBase());
|
||||
|
||||
// Fake an empty view
|
||||
FakeCoinsViewDB fakeDB;
|
||||
CCoinsViewCache view(&fakeDB);
|
||||
|
||||
CValidationState state;
|
||||
EXPECT_TRUE(ContextualCheckInputs(tx, state, view, false, 0, false, Params(CBaseChainParams::MAIN).GetConsensus()));
|
||||
}
|
22
src/init.cpp
22
src/init.cpp
|
@ -161,6 +161,7 @@ public:
|
|||
|
||||
static CCoinsViewDB *pcoinsdbview = NULL;
|
||||
static CCoinsViewErrorCatcher *pcoinscatcher = NULL;
|
||||
static boost::scoped_ptr<ECCVerifyHandle> globalVerifyHandle;
|
||||
|
||||
void Interrupt(boost::thread_group& threadGroup)
|
||||
{
|
||||
|
@ -266,6 +267,7 @@ void Shutdown()
|
|||
#endif
|
||||
delete pzcashParams;
|
||||
pzcashParams = NULL;
|
||||
globalVerifyHandle.reset();
|
||||
ECC_Stop();
|
||||
LogPrintf("%s: done\n", __func__);
|
||||
}
|
||||
|
@ -350,8 +352,9 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
|
||||
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file") + " " + _("on startup"));
|
||||
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
|
||||
strUsage += HelpMessageOpt("-mempooltxinputlimit=<n>", _("Set the maximum number of transparent inputs in a transaction that the mempool will accept (default: 0 = no limit applied)"));
|
||||
strUsage += HelpMessageOpt("-par=<n>", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"),
|
||||
-(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));
|
||||
-GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));
|
||||
#ifndef WIN32
|
||||
strUsage += HelpMessageOpt("-pid=<file>", strprintf(_("Specify pid file (default: %s)"), "zcashd.pid"));
|
||||
#endif
|
||||
|
@ -661,8 +664,7 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
|
|||
bool InitSanityCheck(void)
|
||||
{
|
||||
if(!ECC_InitSanityCheck()) {
|
||||
InitError("OpenSSL appears to lack support for elliptic curve cryptography. For more "
|
||||
"information, visit https://en.bitcoin.it/wiki/OpenSSL_and_EC_Libraries");
|
||||
InitError("Elliptic curve cryptography sanity check failure. Aborting.");
|
||||
return false;
|
||||
}
|
||||
if (!glibc_sanity_test() || !glibcxx_sanity_test())
|
||||
|
@ -927,7 +929,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
|
||||
nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
|
||||
if (nScriptCheckThreads <= 0)
|
||||
nScriptCheckThreads += boost::thread::hardware_concurrency();
|
||||
nScriptCheckThreads += GetNumCores();
|
||||
if (nScriptCheckThreads <= 1)
|
||||
nScriptCheckThreads = 0;
|
||||
else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)
|
||||
|
@ -1035,6 +1037,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
}
|
||||
#endif
|
||||
|
||||
// Default value of 0 for mempooltxinputlimit means no limit is applied
|
||||
if (mapArgs.count("-mempooltxinputlimit")) {
|
||||
int64_t limit = GetArg("-mempooltxinputlimit", 0);
|
||||
if (limit < 0) {
|
||||
return InitError(_("Mempool limit on transparent inputs to a transaction cannot be negative"));
|
||||
} else if (limit > 0) {
|
||||
LogPrintf("Mempool configured to reject transactions with greater than %lld transparent inputs\n", limit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
|
||||
|
||||
// Initialize libsodium
|
||||
|
@ -1044,6 +1057,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
|
||||
// Initialize elliptic curve code
|
||||
ECC_Start();
|
||||
globalVerifyHandle.reset(new ECCVerifyHandle());
|
||||
|
||||
// Sanity check
|
||||
if (!InitSanityCheck())
|
||||
|
|
203
src/key.cpp
203
src/key.cpp
|
@ -1,4 +1,5 @@
|
|||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||
// Copyright (c) 2017 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
@ -7,17 +8,155 @@
|
|||
#include "arith_uint256.h"
|
||||
#include "crypto/common.h"
|
||||
#include "crypto/hmac_sha512.h"
|
||||
#include "eccryptoverify.h"
|
||||
#include "pubkey.h"
|
||||
#include "random.h"
|
||||
|
||||
#include <secp256k1.h>
|
||||
#include "ecwrapper.h"
|
||||
#include <secp256k1_recovery.h>
|
||||
|
||||
static secp256k1_context_t* secp256k1_context = NULL;
|
||||
static secp256k1_context* secp256k1_context_sign = NULL;
|
||||
|
||||
/** These functions are taken from the libsecp256k1 distribution and are very ugly. */
|
||||
|
||||
/**
|
||||
* This parses a format loosely based on a DER encoding of the ECPrivateKey type from
|
||||
* section C.4 of SEC 1 <http://www.secg.org/sec1-v2.pdf>, with the following caveats:
|
||||
*
|
||||
* * The octet-length of the SEQUENCE must be encoded as 1 or 2 octets. It is not
|
||||
* required to be encoded as one octet if it is less than 256, as DER would require.
|
||||
* * The octet-length of the SEQUENCE must not be greater than the remaining
|
||||
* length of the key encoding, but need not match it (i.e. the encoding may contain
|
||||
* junk after the encoded SEQUENCE).
|
||||
* * The privateKey OCTET STRING is zero-filled on the left to 32 octets.
|
||||
* * Anything after the encoding of the privateKey OCTET STRING is ignored, whether
|
||||
* or not it is validly encoded DER.
|
||||
*
|
||||
* out32 must point to an output buffer of length at least 32 bytes.
|
||||
*/
|
||||
static 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;
|
||||
memset(out32, 0, 32);
|
||||
/* sequence header */
|
||||
if (end - privkey < 1 || *privkey != 0x30u) {
|
||||
return 0;
|
||||
}
|
||||
privkey++;
|
||||
/* sequence length constructor */
|
||||
if (end - privkey < 1 || !(*privkey & 0x80u)) {
|
||||
return 0;
|
||||
}
|
||||
size_t lenb = *privkey & ~0x80u; privkey++;
|
||||
if (lenb < 1 || lenb > 2) {
|
||||
return 0;
|
||||
}
|
||||
if (end - privkey < lenb) {
|
||||
return 0;
|
||||
}
|
||||
/* sequence length */
|
||||
size_t len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0u);
|
||||
privkey += lenb;
|
||||
if (end - privkey < len) {
|
||||
return 0;
|
||||
}
|
||||
/* sequence element 0: version number (=1) */
|
||||
if (end - privkey < 3 || privkey[0] != 0x02u || privkey[1] != 0x01u || privkey[2] != 0x01u) {
|
||||
return 0;
|
||||
}
|
||||
privkey += 3;
|
||||
/* sequence element 1: octet string, up to 32 bytes */
|
||||
if (end - privkey < 2 || privkey[0] != 0x04u) {
|
||||
return 0;
|
||||
}
|
||||
size_t oslen = privkey[1];
|
||||
privkey += 2;
|
||||
if (oslen > 32 || end - privkey < oslen) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(out32 + (32 - oslen), privkey, oslen);
|
||||
if (!secp256k1_ec_seckey_verify(ctx, out32)) {
|
||||
memset(out32, 0, 32);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This serializes to a DER encoding of the ECPrivateKey type from section C.4 of SEC 1
|
||||
* <http://www.secg.org/sec1-v2.pdf>. The optional parameters and publicKey fields are
|
||||
* included.
|
||||
*
|
||||
* privkey must point to an output buffer of length at least PRIVATE_KEY_SIZE bytes.
|
||||
* privkeylen must initially be set to the size of the privkey buffer. Upon return it
|
||||
* will be set to the number of bytes used in the buffer.
|
||||
* key32 must point to a 32-byte raw private key.
|
||||
*/
|
||||
static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) {
|
||||
assert(*privkeylen >= PRIVATE_KEY_SIZE);
|
||||
static_assert(
|
||||
PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE,
|
||||
"COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE");
|
||||
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 = COMPRESSED_PUBLIC_KEY_SIZE;
|
||||
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED);
|
||||
ptr += pubkeylen;
|
||||
*privkeylen = ptr - privkey;
|
||||
assert(*privkeylen == COMPRESSED_PRIVATE_KEY_SIZE);
|
||||
} 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 = PUBLIC_KEY_SIZE;
|
||||
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
|
||||
ptr += pubkeylen;
|
||||
*privkeylen = ptr - privkey;
|
||||
assert(*privkeylen == PRIVATE_KEY_SIZE);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool CKey::Check(const unsigned char *vch) {
|
||||
return eccrypto::Check(vch);
|
||||
return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch);
|
||||
}
|
||||
|
||||
void CKey::MakeNewKey(bool fCompressedIn) {
|
||||
|
@ -29,7 +168,7 @@ void CKey::MakeNewKey(bool fCompressedIn) {
|
|||
}
|
||||
|
||||
bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
|
||||
if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size()))
|
||||
if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size()))
|
||||
return false;
|
||||
fCompressed = fCompressedIn;
|
||||
fValid = true;
|
||||
|
@ -39,10 +178,11 @@ bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
|
|||
CPrivKey CKey::GetPrivKey() const {
|
||||
assert(fValid);
|
||||
CPrivKey privkey;
|
||||
int privkeylen, ret;
|
||||
privkey.resize(279);
|
||||
privkeylen = 279;
|
||||
ret = secp256k1_ec_privkey_export(secp256k1_context, begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed);
|
||||
int ret;
|
||||
size_t privkeylen;
|
||||
privkey.resize(PRIVATE_KEY_SIZE);
|
||||
privkeylen = PRIVATE_KEY_SIZE;
|
||||
ret = ec_privkey_export_der(secp256k1_context_sign, (unsigned char*)&privkey[0], &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
|
||||
assert(ret);
|
||||
privkey.resize(privkeylen);
|
||||
return privkey;
|
||||
|
@ -50,11 +190,13 @@ CPrivKey CKey::GetPrivKey() const {
|
|||
|
||||
CPubKey CKey::GetPubKey() const {
|
||||
assert(fValid);
|
||||
secp256k1_pubkey pubkey;
|
||||
size_t clen = PUBLIC_KEY_SIZE;
|
||||
CPubKey result;
|
||||
int clen = 65;
|
||||
int ret = secp256k1_ec_pubkey_create(secp256k1_context, (unsigned char*)result.begin(), &clen, begin(), fCompressed);
|
||||
assert((int)result.size() == clen);
|
||||
int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin());
|
||||
assert(ret);
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_context_sign, (unsigned char*)result.begin(), &clen, &pubkey, fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
|
||||
assert(result.size() == clen);
|
||||
assert(result.IsValid());
|
||||
return result;
|
||||
}
|
||||
|
@ -62,12 +204,14 @@ CPubKey CKey::GetPubKey() const {
|
|||
bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_t test_case) const {
|
||||
if (!fValid)
|
||||
return false;
|
||||
vchSig.resize(72);
|
||||
int nSigLen = 72;
|
||||
vchSig.resize(SIGNATURE_SIZE);
|
||||
size_t nSigLen = SIGNATURE_SIZE;
|
||||
unsigned char extra_entropy[32] = {0};
|
||||
WriteLE32(extra_entropy, test_case);
|
||||
int ret = secp256k1_ecdsa_sign(secp256k1_context, hash.begin(), (unsigned char*)&vchSig[0], &nSigLen, begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL);
|
||||
secp256k1_ecdsa_signature sig;
|
||||
int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL);
|
||||
assert(ret);
|
||||
secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, (unsigned char*)&vchSig[0], &nSigLen, &sig);
|
||||
vchSig.resize(nSigLen);
|
||||
return true;
|
||||
}
|
||||
|
@ -89,9 +233,12 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const {
|
|||
bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
|
||||
if (!fValid)
|
||||
return false;
|
||||
vchSig.resize(65);
|
||||
vchSig.resize(COMPACT_SIGNATURE_SIZE);
|
||||
int rec = -1;
|
||||
int ret = secp256k1_ecdsa_sign_compact(secp256k1_context, hash.begin(), &vchSig[1], begin(), secp256k1_nonce_function_rfc6979, NULL, &rec);
|
||||
secp256k1_ecdsa_recoverable_signature sig;
|
||||
int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, NULL);
|
||||
assert(ret);
|
||||
secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, (unsigned char*)&vchSig[1], &rec, &sig);
|
||||
assert(ret);
|
||||
assert(rec != -1);
|
||||
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
|
||||
|
@ -99,7 +246,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
|
|||
}
|
||||
|
||||
bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
|
||||
if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size()))
|
||||
if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size()))
|
||||
return false;
|
||||
fCompressed = vchPubKey.IsCompressed();
|
||||
fValid = true;
|
||||
|
@ -117,15 +264,15 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
|
|||
LockObject(out);
|
||||
if ((nChild >> 31) == 0) {
|
||||
CPubKey pubkey = GetPubKey();
|
||||
assert(pubkey.begin() + 33 == pubkey.end());
|
||||
assert(pubkey.size() == COMPRESSED_PUBLIC_KEY_SIZE);
|
||||
BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, out);
|
||||
} else {
|
||||
assert(begin() + 32 == end());
|
||||
assert(size() == 32);
|
||||
BIP32Hash(cc, nChild, 0, begin(), out);
|
||||
}
|
||||
memcpy(ccChild.begin(), out+32, 32);
|
||||
memcpy((unsigned char*)keyChild.begin(), begin(), 32);
|
||||
bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context, (unsigned char*)keyChild.begin(), out);
|
||||
bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), out);
|
||||
UnlockObject(out);
|
||||
keyChild.fCompressed = true;
|
||||
keyChild.fValid = ret;
|
||||
|
@ -183,20 +330,16 @@ void CExtKey::Decode(const unsigned char code[74]) {
|
|||
}
|
||||
|
||||
bool ECC_InitSanityCheck() {
|
||||
if (!CECKey::SanityCheck()) {
|
||||
return false;
|
||||
}
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
return key.VerifyPubKey(pubkey);
|
||||
}
|
||||
|
||||
|
||||
void ECC_Start() {
|
||||
assert(secp256k1_context == NULL);
|
||||
assert(secp256k1_context_sign == NULL);
|
||||
|
||||
secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
assert(ctx != NULL);
|
||||
|
||||
{
|
||||
|
@ -209,12 +352,12 @@ void ECC_Start() {
|
|||
UnlockObject(seed);
|
||||
}
|
||||
|
||||
secp256k1_context = ctx;
|
||||
secp256k1_context_sign = ctx;
|
||||
}
|
||||
|
||||
void ECC_Stop() {
|
||||
secp256k1_context_t *ctx = secp256k1_context;
|
||||
secp256k1_context = NULL;
|
||||
secp256k1_context *ctx = secp256k1_context_sign;
|
||||
secp256k1_context_sign = NULL;
|
||||
|
||||
if (ctx) {
|
||||
secp256k1_context_destroy(ctx);
|
||||
|
|
12
src/key.h
12
src/key.h
|
@ -1,5 +1,6 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||
// Copyright (c) 2017 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
@ -17,17 +18,18 @@
|
|||
|
||||
/**
|
||||
* secp256k1:
|
||||
* const unsigned int PRIVATE_KEY_SIZE = 279;
|
||||
* const unsigned int PUBLIC_KEY_SIZE = 65;
|
||||
* const unsigned int SIGNATURE_SIZE = 72;
|
||||
*
|
||||
*/
|
||||
const unsigned int PRIVATE_KEY_SIZE = 279;
|
||||
const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214;
|
||||
/**
|
||||
* see www.keylength.com
|
||||
* script supports up to 75 for single byte push
|
||||
*/
|
||||
|
||||
/**
|
||||
* secure_allocator is defined in allocators.h
|
||||
* CPrivKey is a serialized private key, with all parameters included (279 bytes)
|
||||
* CPrivKey is a serialized private key, with all parameters included
|
||||
* (PRIVATE_KEY_SIZE bytes)
|
||||
*/
|
||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
|
||||
|
||||
|
|
41
src/main.cpp
41
src/main.cpp
|
@ -1058,6 +1058,17 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||
if (pfMissingInputs)
|
||||
*pfMissingInputs = false;
|
||||
|
||||
// Node operator can choose to reject tx by number of transparent inputs
|
||||
static_assert(std::numeric_limits<size_t>::max() >= std::numeric_limits<int64_t>::max(), "size_t too small");
|
||||
size_t limit = (size_t) GetArg("-mempooltxinputlimit", 0);
|
||||
if (limit > 0) {
|
||||
size_t n = tx.vin.size();
|
||||
if (n > limit) {
|
||||
LogPrint("mempool", "Dropping txid %s : too many transparent inputs %zu > limit %zu\n", tx.GetHash().ToString(), n, limit );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
if (!CheckTransaction(tx, state, verifier))
|
||||
return error("AcceptToMemoryPool: CheckTransaction failed");
|
||||
|
@ -1687,11 +1698,12 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
|
|||
|
||||
bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks)
|
||||
{
|
||||
if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs), consensusParams))
|
||||
return false;
|
||||
|
||||
if (!tx.IsCoinBase())
|
||||
{
|
||||
if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs), consensusParams)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pvChecks)
|
||||
pvChecks->reserve(tx.vin.size());
|
||||
|
||||
|
@ -2077,19 +2089,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
REJECT_INVALID, "bad-txns-BIP30");
|
||||
}
|
||||
|
||||
unsigned int flags = SCRIPT_VERIFY_P2SH;
|
||||
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
|
||||
|
||||
// Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks,
|
||||
// when 75% of the network has upgraded:
|
||||
if (block.nVersion >= 3) {
|
||||
flags |= SCRIPT_VERIFY_DERSIG;
|
||||
}
|
||||
|
||||
// Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4
|
||||
// blocks, when 75% of the network has upgraded:
|
||||
if (block.nVersion >= 4) {
|
||||
flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
|
||||
}
|
||||
// DERSIG (BIP66) is also always enforced, but does not have a flag.
|
||||
|
||||
CBlockUndo blockundo;
|
||||
|
||||
|
@ -3102,11 +3104,10 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
|
|||
}
|
||||
}
|
||||
|
||||
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
|
||||
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
|
||||
// Since MIN_BLOCK_VERSION = 4 all blocks with nHeight > 0 should satisfy this.
|
||||
// This rule is not applied to the genesis block, which didn't include the height
|
||||
// in the coinbase.
|
||||
// Enforce BIP 34 rule that the coinbase starts with serialized block height.
|
||||
// In Zcash this has been enforced since launch, except that the genesis
|
||||
// block didn't include the height in the coinbase (see Zcash protocol spec
|
||||
// section '6.8 Bitcoin Improvement Proposals').
|
||||
if (nHeight > 0)
|
||||
{
|
||||
CScript expect = CScript() << nHeight;
|
||||
|
|
|
@ -53,6 +53,12 @@ bool AtomicTimer::running()
|
|||
return threads > 0;
|
||||
}
|
||||
|
||||
uint64_t AtomicTimer::threadCount()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
return threads;
|
||||
}
|
||||
|
||||
double AtomicTimer::rate(const AtomicCounter& count)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
|
@ -199,15 +205,8 @@ int printMiningStatus(bool mining)
|
|||
int lines = 1;
|
||||
|
||||
if (mining) {
|
||||
int nThreads = GetArg("-genproclimit", 1);
|
||||
if (nThreads < 0) {
|
||||
// In regtest threads defaults to 1
|
||||
if (Params().DefaultMinerThreads())
|
||||
nThreads = Params().DefaultMinerThreads();
|
||||
else
|
||||
nThreads = boost::thread::hardware_concurrency();
|
||||
}
|
||||
if (miningTimer.running()) {
|
||||
auto nThreads = miningTimer.threadCount();
|
||||
if (nThreads > 0) {
|
||||
std::cout << strprintf(_("You are mining with the %s solver on %d threads."),
|
||||
GetArg("-equihashsolver", "default"), nThreads) << std::endl;
|
||||
} else {
|
||||
|
|
|
@ -49,6 +49,8 @@ public:
|
|||
|
||||
bool running();
|
||||
|
||||
uint64_t threadCount();
|
||||
|
||||
double rate(const AtomicCounter& count);
|
||||
};
|
||||
|
||||
|
|
|
@ -738,13 +738,8 @@ void GenerateBitcoins(bool fGenerate, int nThreads)
|
|||
{
|
||||
static boost::thread_group* minerThreads = NULL;
|
||||
|
||||
if (nThreads < 0) {
|
||||
// In regtest threads defaults to 1
|
||||
if (Params().DefaultMinerThreads())
|
||||
nThreads = Params().DefaultMinerThreads();
|
||||
else
|
||||
nThreads = boost::thread::hardware_concurrency();
|
||||
}
|
||||
if (nThreads < 0)
|
||||
nThreads = GetNumCores();
|
||||
|
||||
if (minerThreads != NULL)
|
||||
{
|
||||
|
|
122
src/pubkey.cpp
122
src/pubkey.cpp
|
@ -1,73 +1,101 @@
|
|||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||
// Copyright (c) 2017 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "pubkey.h"
|
||||
|
||||
#include "eccryptoverify.h"
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_recovery.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
/* Global secp256k1_context object used for verification. */
|
||||
secp256k1_context* secp256k1_context_verify = NULL;
|
||||
}
|
||||
|
||||
#include "ecwrapper.h"
|
||||
|
||||
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
CECKey key;
|
||||
if (!key.SetPubKey(begin(), size()))
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
|
||||
return false;
|
||||
if (!key.Verify(hash, vchSig))
|
||||
}
|
||||
if (vchSig.size() == 0) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
/* Zcash, unlike Bitcoin, has always enforced strict DER signatures. */
|
||||
if (!secp256k1_ecdsa_signature_parse_der(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {
|
||||
return false;
|
||||
}
|
||||
/* libsecp256k1's ECDSA verification requires lower-S signatures, which have
|
||||
* not historically been enforced in Bitcoin or Zcash, so normalize them first. */
|
||||
secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, &sig, &sig);
|
||||
return secp256k1_ecdsa_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey);
|
||||
}
|
||||
|
||||
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
|
||||
if (vchSig.size() != 65)
|
||||
if (vchSig.size() != COMPACT_SIGNATURE_SIZE)
|
||||
return false;
|
||||
int recid = (vchSig[0] - 27) & 3;
|
||||
bool fComp = ((vchSig[0] - 27) & 4) != 0;
|
||||
CECKey key;
|
||||
if (!key.Recover(hash, &vchSig[1], recid))
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_ecdsa_recoverable_signature sig;
|
||||
if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_verify, &sig, &vchSig[1], recid)) {
|
||||
return false;
|
||||
std::vector<unsigned char> pubkey;
|
||||
key.GetPubKey(pubkey, fComp);
|
||||
Set(pubkey.begin(), pubkey.end());
|
||||
}
|
||||
if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) {
|
||||
return false;
|
||||
}
|
||||
unsigned char pub[PUBLIC_KEY_SIZE];
|
||||
size_t publen = PUBLIC_KEY_SIZE;
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
|
||||
Set(pub, pub + publen);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPubKey::IsFullyValid() const {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
CECKey key;
|
||||
if (!key.SetPubKey(begin(), size()))
|
||||
return false;
|
||||
return true;
|
||||
secp256k1_pubkey pubkey;
|
||||
return secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size());
|
||||
}
|
||||
|
||||
bool CPubKey::Decompress() {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
CECKey key;
|
||||
if (!key.SetPubKey(begin(), size()))
|
||||
secp256k1_pubkey pubkey;
|
||||
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
|
||||
return false;
|
||||
std::vector<unsigned char> pubkey;
|
||||
key.GetPubKey(pubkey, false);
|
||||
Set(pubkey.begin(), pubkey.end());
|
||||
}
|
||||
unsigned char pub[PUBLIC_KEY_SIZE];
|
||||
size_t publen = PUBLIC_KEY_SIZE;
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
|
||||
Set(pub, pub + publen);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {
|
||||
assert(IsValid());
|
||||
assert((nChild >> 31) == 0);
|
||||
assert(begin() + 33 == end());
|
||||
assert(size() == COMPRESSED_PUBLIC_KEY_SIZE);
|
||||
unsigned char out[64];
|
||||
BIP32Hash(cc, nChild, *begin(), begin()+1, out);
|
||||
memcpy(ccChild.begin(), out+32, 32);
|
||||
CECKey key;
|
||||
bool ret = key.SetPubKey(begin(), size());
|
||||
ret &= key.TweakPublic(out);
|
||||
std::vector<unsigned char> pubkey;
|
||||
key.GetPubKey(pubkey, true);
|
||||
pubkeyChild.Set(pubkey.begin(), pubkey.end());
|
||||
return ret;
|
||||
secp256k1_pubkey pubkey;
|
||||
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
|
||||
return false;
|
||||
}
|
||||
if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) {
|
||||
return false;
|
||||
}
|
||||
unsigned char pub[COMPRESSED_PUBLIC_KEY_SIZE];
|
||||
size_t publen = COMPRESSED_PUBLIC_KEY_SIZE;
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED);
|
||||
pubkeyChild.Set(pub, pub + publen);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CExtPubKey::Encode(unsigned char code[74]) const {
|
||||
|
@ -76,8 +104,8 @@ void CExtPubKey::Encode(unsigned char code[74]) const {
|
|||
code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
|
||||
code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF;
|
||||
memcpy(code+9, chaincode.begin(), 32);
|
||||
assert(pubkey.size() == 33);
|
||||
memcpy(code+41, pubkey.begin(), 33);
|
||||
assert(pubkey.size() == COMPRESSED_PUBLIC_KEY_SIZE);
|
||||
memcpy(code+41, pubkey.begin(), COMPRESSED_PUBLIC_KEY_SIZE);
|
||||
}
|
||||
|
||||
void CExtPubKey::Decode(const unsigned char code[74]) {
|
||||
|
@ -95,3 +123,35 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const {
|
|||
out.nChild = nChild;
|
||||
return pubkey.Derive(out.pubkey, out.chaincode, nChild, chaincode);
|
||||
}
|
||||
|
||||
/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {
|
||||
secp256k1_ecdsa_signature sig;
|
||||
|
||||
/* Zcash, unlike Bitcoin, has always enforced strict DER signatures. */
|
||||
if (!secp256k1_ecdsa_signature_parse_der(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {
|
||||
return false;
|
||||
}
|
||||
return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, NULL, &sig));
|
||||
}
|
||||
|
||||
/* static */ int ECCVerifyHandle::refcount = 0;
|
||||
|
||||
ECCVerifyHandle::ECCVerifyHandle()
|
||||
{
|
||||
if (refcount == 0) {
|
||||
assert(secp256k1_context_verify == NULL);
|
||||
secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||
assert(secp256k1_context_verify != NULL);
|
||||
}
|
||||
refcount++;
|
||||
}
|
||||
|
||||
ECCVerifyHandle::~ECCVerifyHandle()
|
||||
{
|
||||
refcount--;
|
||||
if (refcount == 0) {
|
||||
assert(secp256k1_context_verify != NULL);
|
||||
secp256k1_context_destroy(secp256k1_context_verify);
|
||||
secp256k1_context_verify = NULL;
|
||||
}
|
||||
}
|
||||
|
|
40
src/pubkey.h
40
src/pubkey.h
|
@ -1,5 +1,6 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||
// Copyright (c) 2017 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
@ -15,10 +16,12 @@
|
|||
|
||||
/**
|
||||
* secp256k1:
|
||||
* const unsigned int PRIVATE_KEY_SIZE = 279;
|
||||
* const unsigned int PUBLIC_KEY_SIZE = 65;
|
||||
* const unsigned int SIGNATURE_SIZE = 72;
|
||||
*
|
||||
*/
|
||||
const unsigned int PUBLIC_KEY_SIZE = 65;
|
||||
const unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33;
|
||||
const unsigned int SIGNATURE_SIZE = 72;
|
||||
const unsigned int COMPACT_SIGNATURE_SIZE = 65;
|
||||
/**
|
||||
* see www.keylength.com
|
||||
* script supports up to 75 for single byte push
|
||||
*/
|
||||
|
@ -42,15 +45,18 @@ private:
|
|||
* Just store the serialized data.
|
||||
* Its length can very cheaply be computed from the first byte.
|
||||
*/
|
||||
unsigned char vch[65];
|
||||
unsigned char vch[PUBLIC_KEY_SIZE];
|
||||
static_assert(
|
||||
PUBLIC_KEY_SIZE >= COMPRESSED_PUBLIC_KEY_SIZE,
|
||||
"COMPRESSED_PUBLIC_KEY_SIZE is larger than PUBLIC_KEY_SIZE");
|
||||
|
||||
//! Compute the length of a pubkey with a given first byte.
|
||||
unsigned int static GetLen(unsigned char chHeader)
|
||||
{
|
||||
if (chHeader == 2 || chHeader == 3)
|
||||
return 33;
|
||||
return COMPRESSED_PUBLIC_KEY_SIZE;
|
||||
if (chHeader == 4 || chHeader == 6 || chHeader == 7)
|
||||
return 65;
|
||||
return PUBLIC_KEY_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -129,7 +135,7 @@ public:
|
|||
void Unserialize(Stream& s, int nType, int nVersion)
|
||||
{
|
||||
unsigned int len = ::ReadCompactSize(s);
|
||||
if (len <= 65) {
|
||||
if (len <= PUBLIC_KEY_SIZE) {
|
||||
s.read((char*)vch, len);
|
||||
} else {
|
||||
// invalid pubkey, skip available data
|
||||
|
@ -168,7 +174,7 @@ public:
|
|||
//! Check whether this is a compressed public key.
|
||||
bool IsCompressed() const
|
||||
{
|
||||
return size() == 33;
|
||||
return size() == COMPRESSED_PUBLIC_KEY_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -177,6 +183,11 @@ public:
|
|||
*/
|
||||
bool Verify(const uint256& hash, const std::vector<unsigned char>& vchSig) const;
|
||||
|
||||
/**
|
||||
* Check whether a signature is normalized (lower-S).
|
||||
*/
|
||||
static bool CheckLowS(const std::vector<unsigned char>& vchSig);
|
||||
|
||||
//! Recover a public key from a compact signature.
|
||||
bool RecoverCompact(const uint256& hash, const std::vector<unsigned char>& vchSig);
|
||||
|
||||
|
@ -205,4 +216,15 @@ struct CExtPubKey {
|
|||
bool Derive(CExtPubKey& out, unsigned int nChild) const;
|
||||
};
|
||||
|
||||
/** Users of this module must hold an ECCVerifyHandle. The constructor and
|
||||
* destructor of these are not allowed to run in parallel, though. */
|
||||
class ECCVerifyHandle
|
||||
{
|
||||
static int refcount;
|
||||
|
||||
public:
|
||||
ECCVerifyHandle();
|
||||
~ECCVerifyHandle();
|
||||
};
|
||||
|
||||
#endif // BITCOIN_PUBKEY_H
|
||||
|
|
|
@ -293,9 +293,7 @@ static const CRPCCommand vRPCCommands[] =
|
|||
{ "blockchain", "verifychain", &verifychain, true },
|
||||
|
||||
/* Mining */
|
||||
#ifdef ENABLE_WALLET
|
||||
{ "mining", "getblocktemplate", &getblocktemplate, true },
|
||||
#endif
|
||||
{ "mining", "getmininginfo", &getmininginfo, true },
|
||||
{ "mining", "getlocalsolps", &getlocalsolps, true },
|
||||
{ "mining", "getnetworksolps", &getnetworksolps, true },
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "crypto/ripemd160.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "eccryptoverify.h"
|
||||
#include "pubkey.h"
|
||||
#include "script/script.h"
|
||||
#include "uint256.h"
|
||||
|
@ -165,16 +164,14 @@ bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {
|
|||
if (!IsValidSignatureEncoding(vchSig)) {
|
||||
return set_error(serror, SCRIPT_ERR_SIG_DER);
|
||||
}
|
||||
unsigned int nLenR = vchSig[3];
|
||||
unsigned int nLenS = vchSig[5+nLenR];
|
||||
const unsigned char *S = &vchSig[6+nLenR];
|
||||
// https://bitcoin.stackexchange.com/a/12556:
|
||||
// Also note that inside transaction signatures, an extra hashtype byte
|
||||
// follows the actual signature data.
|
||||
std::vector<unsigned char> vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size() - 1);
|
||||
// If the S value is above the order of the curve divided by two, its
|
||||
// complement modulo the order could have been used instead, which is
|
||||
// one byte shorter when encoded correctly.
|
||||
if (!eccrypto::CheckSignatureElement(S, nLenS, true))
|
||||
return set_error(serror, SCRIPT_ERR_SIG_HIGH_S);
|
||||
|
||||
return true;
|
||||
return CPubKey::CheckLowS(vchSigCopy);
|
||||
}
|
||||
|
||||
bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
|
||||
|
@ -194,7 +191,7 @@ bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, Sc
|
|||
if (vchSig.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsValidSignatureEncoding(vchSig)) {
|
||||
if (!IsValidSignatureEncoding(vchSig)) {
|
||||
return set_error(serror, SCRIPT_ERR_SIG_DER);
|
||||
} else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) {
|
||||
// serror is set
|
||||
|
|
|
@ -45,7 +45,8 @@ enum
|
|||
SCRIPT_VERIFY_STRICTENC = (1U << 1),
|
||||
|
||||
// Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1)
|
||||
SCRIPT_VERIFY_DERSIG = (1U << 2),
|
||||
// In Zcash this is required, and validation of non-strict-DER signatures is not implemented.
|
||||
//SCRIPT_VERIFY_DERSIG = (1U << 2),
|
||||
|
||||
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
|
||||
// (softfork safe, BIP62 rule 5).
|
||||
|
|
|
@ -31,8 +31,7 @@ extern unsigned nMaxDatacarrierBytes;
|
|||
/**
|
||||
* Mandatory script verification flags that all new blocks must comply with for
|
||||
* them to be valid. (but old blocks may not comply with) Currently just P2SH,
|
||||
* but in the future other flags may be added, such as a soft-fork to enforce
|
||||
* strict DER encoding.
|
||||
* but in the future other flags may be added.
|
||||
*
|
||||
* Failing one of these tests may trigger a DoS ban - see CheckInputs() for
|
||||
* details.
|
||||
|
@ -45,7 +44,7 @@ static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
|
|||
* blocks and we must accept those blocks.
|
||||
*/
|
||||
static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
|
||||
SCRIPT_VERIFY_DERSIG |
|
||||
// SCRIPT_VERIFY_DERSIG is always enforced
|
||||
SCRIPT_VERIFY_STRICTENC |
|
||||
SCRIPT_VERIFY_MINIMALDATA |
|
||||
SCRIPT_VERIFY_NULLDUMMY |
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "zcashconsensus.h"
|
||||
|
||||
#include "primitives/transaction.h"
|
||||
#include "pubkey.h"
|
||||
#include "script/interpreter.h"
|
||||
#include "version.h"
|
||||
|
||||
|
@ -60,7 +61,13 @@ inline int set_error(zcashconsensus_error* ret, zcashconsensus_error serror)
|
|||
return 0;
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
struct ECCryptoClosure
|
||||
{
|
||||
ECCVerifyHandle handle;
|
||||
};
|
||||
|
||||
ECCryptoClosure instance_of_eccryptoclosure;
|
||||
}
|
||||
|
||||
int zcashconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
|
||||
const unsigned char *txTo , unsigned int txToLen,
|
||||
|
|
|
@ -46,7 +46,6 @@ enum
|
|||
{
|
||||
zcashconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0,
|
||||
zcashconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
|
||||
zcashconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance
|
||||
zcashconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65)
|
||||
};
|
||||
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
bench_inv
|
||||
bench_ecdh
|
||||
bench_sign
|
||||
bench_verify
|
||||
bench_schnorr_verify
|
||||
bench_recover
|
||||
bench_internal
|
||||
tests
|
||||
exhaustive_tests
|
||||
gen_context
|
||||
*.exe
|
||||
*.so
|
||||
*.a
|
||||
|
@ -22,16 +26,24 @@ config.status
|
|||
libtool
|
||||
.deps/
|
||||
.dirstamp
|
||||
build-aux/
|
||||
*.lo
|
||||
*.o
|
||||
*~
|
||||
src/libsecp256k1-config.h
|
||||
src/libsecp256k1-config.h.in
|
||||
m4/libtool.m4
|
||||
m4/ltoptions.m4
|
||||
m4/ltsugar.m4
|
||||
m4/ltversion.m4
|
||||
m4/lt~obsolete.m4
|
||||
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
|
||||
|
|
|
@ -6,22 +6,30 @@ addons:
|
|||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
cache:
|
||||
directories:
|
||||
- src/java/guava/
|
||||
env:
|
||||
global:
|
||||
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no ASM=no BUILD=check EXTRAFLAGS= HOST=
|
||||
- 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
|
||||
- SCALAR=32bit RECOVERY=yes
|
||||
- SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
|
||||
- SCALAR=64bit
|
||||
- FIELD=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
|
||||
- FIELD=32bit ENDOMORPHISM=yes
|
||||
- BIGNUM=no
|
||||
- BIGNUM=no ENDOMORPHISM=yes
|
||||
- BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes
|
||||
- BIGNUM=no STATICPRECOMPUTATION=no
|
||||
- BUILD=distcheck
|
||||
- EXTRAFLAGS=CFLAGS=-DDETERMINISTIC
|
||||
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
|
||||
- EXTRAFLAGS=CFLAGS=-O0
|
||||
- BUILD=check-java ECDH=yes EXPERIMENTAL=yes
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
|
@ -51,9 +59,11 @@ matrix:
|
|||
packages:
|
||||
- gcc-multilib
|
||||
- libgmp-dev:i386
|
||||
before_install: mkdir -p `dirname $GUAVA_JAR`
|
||||
install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi
|
||||
before_script: ./autogen.sh
|
||||
script:
|
||||
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
|
||||
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
|
||||
- ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
|
||||
- ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
|
||||
os: linux
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
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
|
||||
|
@ -19,6 +27,8 @@ 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
|
||||
|
@ -30,6 +40,7 @@ noinst_HEADERS += src/field_5x52_impl.h
|
|||
noinst_HEADERS += src/field_5x52_int128_impl.h
|
||||
noinst_HEADERS += src/field_5x52_asm_impl.h
|
||||
noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h
|
||||
noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h
|
||||
noinst_HEADERS += src/util.h
|
||||
noinst_HEADERS += src/testrand.h
|
||||
noinst_HEADERS += src/testrand_impl.h
|
||||
|
@ -38,40 +49,129 @@ 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
|
||||
|
||||
libsecp256k1_la_SOURCES = src/secp256k1.c
|
||||
libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include $(SECP_INCLUDES)
|
||||
libsecp256k1_la_LIBADD = $(SECP_LIBS)
|
||||
if USE_EXTERNAL_ASM
|
||||
if USE_ASM_ARM
|
||||
libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s
|
||||
endif
|
||||
endif
|
||||
|
||||
libsecp256k1_la_SOURCES = src/secp256k1.c
|
||||
libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
|
||||
libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB)
|
||||
|
||||
libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c
|
||||
libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES)
|
||||
|
||||
noinst_PROGRAMS =
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_verify bench_recover bench_sign bench_internal
|
||||
noinst_PROGRAMS += bench_verify bench_sign bench_internal
|
||||
bench_verify_SOURCES = src/bench_verify.c
|
||||
bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_verify_LDFLAGS = -static
|
||||
bench_recover_SOURCES = src/bench_recover.c
|
||||
bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_recover_LDFLAGS = -static
|
||||
bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
|
||||
bench_sign_SOURCES = src/bench_sign.c
|
||||
bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_sign_LDFLAGS = -static
|
||||
bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
|
||||
bench_internal_SOURCES = src/bench_internal.c
|
||||
bench_internal_LDADD = $(SECP_LIBS)
|
||||
bench_internal_LDFLAGS = -static
|
||||
bench_internal_CPPFLAGS = $(SECP_INCLUDES)
|
||||
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 = -DVERIFY $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
|
||||
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS)
|
||||
tests_LDFLAGS = -static -pthread
|
||||
TESTS = tests
|
||||
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
|
||||
|
||||
EXTRA_DIST = autogen.sh
|
||||
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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
libsecp256k1
|
||||
============
|
||||
|
||||
[![Build Status](https://travis-ci.org/bitcoin/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin/secp256k1)
|
||||
[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1)
|
||||
|
||||
Optimized C library for EC operations on curve secp256k1.
|
||||
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_JNI_INCLUDE_DIR
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# AX_JNI_INCLUDE_DIR finds include directories needed for compiling
|
||||
# programs using the JNI interface.
|
||||
#
|
||||
# JNI include directories are usually in the Java distribution. This is
|
||||
# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in
|
||||
# that order. When this macro completes, a list of directories is left in
|
||||
# the variable JNI_INCLUDE_DIRS.
|
||||
#
|
||||
# Example usage follows:
|
||||
#
|
||||
# AX_JNI_INCLUDE_DIR
|
||||
#
|
||||
# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
|
||||
# do
|
||||
# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR"
|
||||
# done
|
||||
#
|
||||
# If you want to force a specific compiler:
|
||||
#
|
||||
# - at the configure.in level, set JAVAC=yourcompiler before calling
|
||||
# AX_JNI_INCLUDE_DIR
|
||||
#
|
||||
# - at the configure level, setenv JAVAC
|
||||
#
|
||||
# Note: This macro can work with the autoconf M4 macros for Java programs.
|
||||
# This particular macro is not part of the original set of macros.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Don Anderson <dda@sleepycat.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 10
|
||||
|
||||
AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])
|
||||
AC_DEFUN([AX_JNI_INCLUDE_DIR],[
|
||||
|
||||
JNI_INCLUDE_DIRS=""
|
||||
|
||||
if test "x$JAVA_HOME" != x; then
|
||||
_JTOPDIR="$JAVA_HOME"
|
||||
else
|
||||
if test "x$JAVAC" = x; then
|
||||
JAVAC=javac
|
||||
fi
|
||||
AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no])
|
||||
if test "x$_ACJNI_JAVAC" = xno; then
|
||||
AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME])
|
||||
fi
|
||||
_ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC")
|
||||
_JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'`
|
||||
fi
|
||||
|
||||
case "$host_os" in
|
||||
darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
|
||||
_JINC="$_JTOPDIR/Headers";;
|
||||
*) _JINC="$_JTOPDIR/include";;
|
||||
esac
|
||||
_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])
|
||||
_AS_ECHO_LOG([_JINC=$_JINC])
|
||||
|
||||
# On Mac OS X 10.6.4, jni.h is a symlink:
|
||||
# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h
|
||||
# -> ../../CurrentJDK/Headers/jni.h.
|
||||
|
||||
AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path,
|
||||
[
|
||||
if test -f "$_JINC/jni.h"; then
|
||||
ac_cv_jni_header_path="$_JINC"
|
||||
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
|
||||
else
|
||||
_JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
|
||||
if test -f "$_JTOPDIR/include/jni.h"; then
|
||||
ac_cv_jni_header_path="$_JTOPDIR/include"
|
||||
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
|
||||
else
|
||||
ac_cv_jni_header_path=none
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
|
||||
# get the likely subdirectories for system specific java includes
|
||||
case "$host_os" in
|
||||
bsdi*) _JNI_INC_SUBDIRS="bsdos";;
|
||||
darwin*) _JNI_INC_SUBDIRS="darwin";;
|
||||
freebsd*) _JNI_INC_SUBDIRS="freebsd";;
|
||||
linux*) _JNI_INC_SUBDIRS="linux genunix";;
|
||||
osf*) _JNI_INC_SUBDIRS="alpha";;
|
||||
solaris*) _JNI_INC_SUBDIRS="solaris";;
|
||||
mingw*) _JNI_INC_SUBDIRS="win32";;
|
||||
cygwin*) _JNI_INC_SUBDIRS="win32";;
|
||||
*) _JNI_INC_SUBDIRS="genunix";;
|
||||
esac
|
||||
|
||||
if test "x$ac_cv_jni_header_path" != "xnone"; then
|
||||
# add any subdirectories that are present
|
||||
for JINCSUBDIR in $_JNI_INC_SUBDIRS
|
||||
do
|
||||
if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
|
||||
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
])
|
||||
|
||||
# _ACJNI_FOLLOW_SYMLINKS <path>
|
||||
# Follows symbolic links on <path>,
|
||||
# finally setting variable _ACJNI_FOLLOWED
|
||||
# ----------------------------------------
|
||||
AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[
|
||||
# find the include directory relative to the javac executable
|
||||
_cur="$1"
|
||||
while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do
|
||||
AC_MSG_CHECKING([symlink for $_cur])
|
||||
_slink=`ls -ld "$_cur" | sed 's/.* -> //'`
|
||||
case "$_slink" in
|
||||
/*) _cur="$_slink";;
|
||||
# 'X' avoids triggering unwanted echo options.
|
||||
*) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";;
|
||||
esac
|
||||
AC_MSG_RESULT([$_cur])
|
||||
done
|
||||
_ACJNI_FOLLOWED="$_cur"
|
||||
])# _ACJNI
|
|
@ -0,0 +1,125 @@
|
|||
# ===========================================================================
|
||||
# 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 <bonzini@gnu.org>
|
||||
#
|
||||
# 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
|
||||
])
|
|
@ -3,21 +3,20 @@ AC_DEFUN([SECP_INT128_CHECK],[
|
|||
has_int128=$ac_cv_type___int128
|
||||
])
|
||||
|
||||
dnl
|
||||
dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
|
||||
AC_DEFUN([SECP_64BIT_ASM_CHECK],[
|
||||
AC_MSG_CHECKING(for x86_64 assembly availability)
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <stdint.h>]],[[
|
||||
uint64_t a = 11, tmp;
|
||||
__asm__ __volatile__("movq $0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
|
||||
__asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
|
||||
]])],[has_64bit_asm=yes],[has_64bit_asm=no])
|
||||
AC_MSG_RESULT([$has_64bit_asm])
|
||||
])
|
||||
|
||||
dnl
|
||||
AC_DEFUN([SECP_OPENSSL_CHECK],[
|
||||
if test x"$use_pkgconfig" = x"yes"; then
|
||||
: #NOP
|
||||
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
|
||||
|
@ -27,11 +26,16 @@ if test x"$use_pkgconfig" = x"yes"; then
|
|||
LIBS="$TEMP_LIBS"
|
||||
fi
|
||||
])
|
||||
else
|
||||
AC_CHECK_HEADER(openssl/crypto.h,[AC_CHECK_LIB(crypto, main,[has_libcrypto=yes; CRYPTO_LIBS=-lcrypto; AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])]
|
||||
)])
|
||||
LIBS=
|
||||
fi
|
||||
if test x$has_libcrypto = 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([[
|
||||
|
@ -42,6 +46,10 @@ if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
|
|||
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
|
||||
|
|
|
@ -17,24 +17,19 @@ 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="-O3 -g"
|
||||
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
|
||||
|
||||
case $host in
|
||||
*mingw*)
|
||||
use_pkgconfig=no
|
||||
;;
|
||||
*)
|
||||
use_pkgconfig=yes
|
||||
;;
|
||||
esac
|
||||
AM_PROG_AS
|
||||
|
||||
case $host_os in
|
||||
*darwin*)
|
||||
|
@ -80,22 +75,70 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
|
|||
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=no])
|
||||
|
||||
AC_ARG_ENABLE(jni,
|
||||
AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),
|
||||
[use_jni=$enableval],
|
||||
[use_jni=auto])
|
||||
|
||||
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
|
||||
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
|
||||
|
||||
|
@ -105,8 +148,8 @@ AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],
|
|||
AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
|
||||
[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto])
|
||||
|
||||
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|no|auto]
|
||||
[Specify assembly optimizations to use. Default is auto])],[req_asm=$withval], [req_asm=auto])
|
||||
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto]
|
||||
[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto])
|
||||
|
||||
AC_CHECK_TYPES([__int128])
|
||||
|
||||
|
@ -116,6 +159,42 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
|
|||
[ 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
|
||||
|
@ -133,6 +212,8 @@ else
|
|||
AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
|
||||
fi
|
||||
;;
|
||||
arm)
|
||||
;;
|
||||
no)
|
||||
;;
|
||||
*)
|
||||
|
@ -225,10 +306,15 @@ else
|
|||
fi
|
||||
|
||||
# select assembly optimization
|
||||
use_external_asm=no
|
||||
|
||||
case $set_asm in
|
||||
x86_64)
|
||||
AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations])
|
||||
;;
|
||||
arm)
|
||||
use_external_asm=yes
|
||||
;;
|
||||
no)
|
||||
;;
|
||||
*)
|
||||
|
@ -283,16 +369,48 @@ esac
|
|||
if test x"$use_tests" = x"yes"; then
|
||||
SECP_OPENSSL_CHECK
|
||||
if test x"$has_openssl_ec" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
|
||||
SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
|
||||
SECP_TEST_LIBS="$CRYPTO_LIBS"
|
||||
if test x"$enable_openssl_tests" != x"no"; then
|
||||
AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
|
||||
SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
|
||||
SECP_TEST_LIBS="$CRYPTO_LIBS"
|
||||
|
||||
case $host in
|
||||
*mingw*)
|
||||
SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32"
|
||||
;;
|
||||
esac
|
||||
case $host in
|
||||
*mingw*)
|
||||
SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
else
|
||||
if test x"$enable_openssl_tests" = x"yes"; then
|
||||
AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available])
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if test x"$enable_openssl_tests" = x"yes"; then
|
||||
AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$use_jni" != x"no"; then
|
||||
AX_JNI_INCLUDE_DIR
|
||||
have_jni_dependencies=yes
|
||||
if test x"$enable_module_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
|
||||
|
||||
|
@ -305,22 +423,67 @@ 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
|
||||
|
||||
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([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([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"
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
/**********************************************************************
|
||||
* 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 <string.h>
|
||||
#include <secp256k1.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/**********************************************************************
|
||||
* 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 <secp256k1.h>
|
||||
|
||||
# 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
|
|
@ -0,0 +1,113 @@
|
|||
/**********************************************************************
|
||||
* 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 <string.h>
|
||||
#include <secp256k1.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/**********************************************************************
|
||||
* 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 <secp256k1.h>
|
||||
|
||||
# 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
|
|
@ -5,6 +5,93 @@
|
|||
extern "C" {
|
||||
# endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* 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_serialize_* 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) \
|
||||
|
@ -26,6 +113,20 @@ extern "C" {
|
|||
# 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. */
|
||||
|
@ -40,305 +141,471 @@ extern "C" {
|
|||
# define SECP256K1_ARG_NONNULL(_x)
|
||||
# endif
|
||||
|
||||
/** Opaque data structure that holds context information (precomputed tables etc.).
|
||||
* Only functions that take a pointer to a non-const context require exclusive
|
||||
* access to it. Multiple functions that take a pointer to a const context may
|
||||
* run simultaneously.
|
||||
*/
|
||||
typedef struct secp256k1_context_struct secp256k1_context_t;
|
||||
/** 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 (1 << 0)
|
||||
# define SECP256K1_CONTEXT_SIGN (1 << 1)
|
||||
#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)
|
||||
|
||||
/** 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_context_t* secp256k1_context_create(
|
||||
int flags
|
||||
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.
|
||||
* In: ctx: an existing context to copy
|
||||
* Args: ctx: an existing context to copy (cannot be NULL)
|
||||
*/
|
||||
secp256k1_context_t* secp256k1_context_clone(
|
||||
const secp256k1_context_t* ctx
|
||||
) SECP256K1_WARN_UNUSED_RESULT;
|
||||
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)
|
||||
*/
|
||||
void secp256k1_context_destroy(
|
||||
secp256k1_context_t* ctx
|
||||
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);
|
||||
|
||||
/** Verify an ECDSA signature.
|
||||
* Returns: 1: correct signature
|
||||
* 0: incorrect signature
|
||||
* -1: invalid public key
|
||||
* -2: invalid signature
|
||||
* In: ctx: a secp256k1 context object, initialized for verification.
|
||||
* msg32: the 32-byte message hash being verified (cannot be NULL)
|
||||
* sig: the signature being verified (cannot be NULL)
|
||||
* siglen: the length of the signature
|
||||
* pubkey: the public key to verify with (cannot be NULL)
|
||||
* pubkeylen: the length of pubkey
|
||||
/** 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_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
|
||||
const secp256k1_context_t* ctx,
|
||||
const unsigned char *msg32,
|
||||
const unsigned char *sig,
|
||||
int siglen,
|
||||
const unsigned char *pubkey,
|
||||
int pubkeylen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
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);
|
||||
|
||||
/** A pointer to a function to deterministically generate a nonce.
|
||||
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail.
|
||||
* 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)
|
||||
* 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.
|
||||
* data: Arbitrary data pointer that is passed through.
|
||||
* Out: nonce32: pointer to a 32-byte array to be filled by the function.
|
||||
* Except for test cases, this function should compute some cryptographic hash of
|
||||
* the message, the key and the attempt.
|
||||
/** 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.
|
||||
*/
|
||||
typedef int (*secp256k1_nonce_function_t)(
|
||||
unsigned char *nonce32,
|
||||
const unsigned char *msg32,
|
||||
const unsigned char *key32,
|
||||
unsigned int attempt,
|
||||
const void *data
|
||||
);
|
||||
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.
|
||||
*/
|
||||
extern const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979;
|
||||
SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
|
||||
|
||||
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
|
||||
extern const secp256k1_nonce_function_t secp256k1_nonce_function_default;
|
||||
|
||||
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, the private key was invalid, or there is not
|
||||
* enough space in the signature (as indicated by siglen).
|
||||
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
|
||||
* 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)
|
||||
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
|
||||
* In/Out: siglen: pointer to an int with the length of sig, which will be updated
|
||||
* to contain the actual signature length (<=72).
|
||||
*
|
||||
* The sig always has an s value in the lower half of the range (From 0x1
|
||||
* to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
|
||||
* inclusive), unlike many other implementations.
|
||||
* With ECDSA a third-party can can forge a second distinct signature
|
||||
* of the same message given a single initial signature without knowing
|
||||
* the key by setting s to its additive inverse mod-order, 'flipping' the
|
||||
* sign of the random point R which is not included in the signature.
|
||||
* Since the forgery is of the same message this 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 canonical 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. Adjusting it inside the signing
|
||||
* function avoids the need to re-serialize or have curve specific
|
||||
* constants outside of the library. By always using a canonical form
|
||||
* even in applications where it isn't needed it becomes possible to
|
||||
* impose a requirement later if a need is discovered.
|
||||
* 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.
|
||||
*/
|
||||
int secp256k1_ecdsa_sign(
|
||||
const secp256k1_context_t* ctx,
|
||||
const unsigned char *msg32,
|
||||
unsigned char *sig,
|
||||
int *siglen,
|
||||
const unsigned char *seckey,
|
||||
secp256k1_nonce_function_t noncefp,
|
||||
const void *ndata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Create a compact ECDSA signature (64 byte + recovery id).
|
||||
* Returns: 1: signature created
|
||||
* 0: the nonce generation function failed, or the secret key was invalid.
|
||||
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
|
||||
* msg32: the 32-byte message hash being signed (cannot be NULL)
|
||||
* 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)
|
||||
* Out: sig: pointer to a 64-byte array where the signature will be placed (cannot be NULL)
|
||||
* In case 0 is returned, the returned signature length will be zero.
|
||||
* recid: pointer to an int, which will be updated to contain the recovery id (can be NULL)
|
||||
*
|
||||
* The created signature is always in lower-S form. See
|
||||
* secp256k1_ecdsa_signature_normalize for more details.
|
||||
*/
|
||||
int secp256k1_ecdsa_sign_compact(
|
||||
const secp256k1_context_t* ctx,
|
||||
const unsigned char *msg32,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *seckey,
|
||||
secp256k1_nonce_function_t noncefp,
|
||||
const void *ndata,
|
||||
int *recid
|
||||
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);
|
||||
|
||||
/** Recover an ECDSA public key from a compact signature.
|
||||
* Returns: 1: public key successfully recovered (which guarantees a correct signature).
|
||||
* 0: otherwise.
|
||||
* In: ctx: pointer to a context object, initialized for verification (cannot be NULL)
|
||||
* msg32: the 32-byte message hash assumed to be signed (cannot be NULL)
|
||||
* sig64: signature as 64 byte array (cannot be NULL)
|
||||
* compressed: whether to recover a compressed or uncompressed pubkey
|
||||
* recid: the recovery id (0-3, as returned by ecdsa_sign_compact)
|
||||
* Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey (cannot be NULL)
|
||||
* pubkeylen: pointer to an int that will contain the pubkey length (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact(
|
||||
const secp256k1_context_t* ctx,
|
||||
const unsigned char *msg32,
|
||||
const unsigned char *sig64,
|
||||
unsigned char *pubkey,
|
||||
int *pubkeylen,
|
||||
int compressed,
|
||||
int recid
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Verify an ECDSA secret key.
|
||||
*
|
||||
* Returns: 1: secret key is valid
|
||||
* 0: secret key is invalid
|
||||
* In: ctx: pointer to a context object (cannot be NULL)
|
||||
* seckey: pointer to a 32-byte secret key (cannot be NULL)
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* In: seckey: pointer to a 32-byte secret key (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
|
||||
const secp256k1_context_t* ctx,
|
||||
const unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Just validate a public key.
|
||||
* Returns: 1: public key is valid
|
||||
* 0: public key is invalid
|
||||
* In: ctx: pointer to a context object (cannot be NULL)
|
||||
* pubkey: pointer to a 33-byte or 65-byte public key (cannot be NULL).
|
||||
* pubkeylen: length of pubkey
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_verify(
|
||||
const secp256k1_context_t* ctx,
|
||||
const unsigned char *pubkey,
|
||||
int pubkeylen
|
||||
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.
|
||||
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
|
||||
* compressed: whether the computed public key should be compressed
|
||||
* seckey: pointer to a 32-byte private key (cannot be NULL)
|
||||
* Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
|
||||
* area to store the public key (cannot be NULL)
|
||||
* pubkeylen: pointer to int that will be updated to contains the pubkey's
|
||||
* length (cannot be NULL)
|
||||
*
|
||||
* 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_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
|
||||
const secp256k1_context_t* ctx,
|
||||
unsigned char *pubkey,
|
||||
int *pubkeylen,
|
||||
const unsigned char *seckey,
|
||||
int compressed
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Decompress a public key.
|
||||
* In: ctx: pointer to a context object (cannot be NULL)
|
||||
* In/Out: pubkey: pointer to a 65-byte array to put the decompressed public key.
|
||||
* It must contain a 33-byte or 65-byte public key already (cannot be NULL)
|
||||
* pubkeylen: pointer to the size of the public key pointed to by pubkey (cannot be NULL)
|
||||
* It will be updated to reflect the new size.
|
||||
* Returns: 0: pubkey was invalid
|
||||
* 1: pubkey was valid, and was replaced with its decompressed version
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_decompress(
|
||||
const secp256k1_context_t* ctx,
|
||||
unsigned char *pubkey,
|
||||
int *pubkeylen
|
||||
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);
|
||||
|
||||
/** Export a private key in DER format.
|
||||
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
|
||||
/** 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_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export(
|
||||
const secp256k1_context_t* ctx,
|
||||
const unsigned char *seckey,
|
||||
unsigned char *privkey,
|
||||
int *privkeylen,
|
||||
int compressed
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
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);
|
||||
|
||||
/** Import a private key in DER format. */
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_import(
|
||||
const secp256k1_context_t* ctx,
|
||||
unsigned char *seckey,
|
||||
const unsigned char *privkey,
|
||||
int privkeylen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
/** 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. */
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
|
||||
const secp256k1_context_t* ctx,
|
||||
unsigned char *seckey,
|
||||
const unsigned char *tweak
|
||||
/** 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.
|
||||
* In: ctx: pointer to a context object, initialized for verification (cannot be NULL)
|
||||
* 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_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
|
||||
const secp256k1_context_t* ctx,
|
||||
unsigned char *pubkey,
|
||||
int pubkeylen,
|
||||
const unsigned char *tweak
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Tweak a private key by multiplying it with tweak. */
|
||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
|
||||
const secp256k1_context_t* ctx,
|
||||
unsigned char *seckey,
|
||||
const unsigned char *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 public key by multiplying it with tweak.
|
||||
* In: ctx: pointer to a context object, initialized for verification (cannot be NULL)
|
||||
/** 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_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
|
||||
const secp256k1_context_t* ctx,
|
||||
unsigned char *pubkey,
|
||||
int pubkeylen,
|
||||
const unsigned char *tweak
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
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);
|
||||
|
||||
/** Updates the context randomization.
|
||||
/** 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
|
||||
* In: ctx: pointer to a context object (cannot be NULL)
|
||||
* seed32: pointer to a 32-byte random seed (NULL resets to initial state)
|
||||
* 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_WARN_UNUSED_RESULT int secp256k1_context_randomize(
|
||||
secp256k1_context_t* ctx,
|
||||
const unsigned char *seed32
|
||||
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
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef _SECP256K1_ECDH_
|
||||
# define _SECP256K1_ECDH_
|
||||
|
||||
# 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
|
|
@ -0,0 +1,110 @@
|
|||
#ifndef _SECP256K1_RECOVERY_
|
||||
# define _SECP256K1_RECOVERY_
|
||||
|
||||
# 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
|
|
@ -5,7 +5,7 @@ includedir=@includedir@
|
|||
|
||||
Name: libsecp256k1
|
||||
Description: Optimized C library for EC operations on curve secp256k1
|
||||
URL: https://github.com/bitcoin/secp256k1
|
||||
URL: https://github.com/bitcoin-core/secp256k1
|
||||
Version: @PACKAGE_VERSION@
|
||||
Cflags: -I${includedir}
|
||||
Libs.private: @SECP_LIBS@
|
||||
|
|
|
@ -0,0 +1,322 @@
|
|||
# This code supports verifying group implementations which have branches
|
||||
# or conditional statements (like cmovs), by allowing each execution path
|
||||
# to independently set assumptions on input or intermediary variables.
|
||||
#
|
||||
# The general approach is:
|
||||
# * A constraint is a tuple of two sets of of symbolic expressions:
|
||||
# the first of which are required to evaluate to zero, the second of which
|
||||
# are required to evaluate to nonzero.
|
||||
# - A constraint is said to be conflicting if any of its nonzero expressions
|
||||
# is in the ideal with basis the zero expressions (in other words: when the
|
||||
# zero expressions imply that one of the nonzero expressions are zero).
|
||||
# * There is a list of laws that describe the intended behaviour, including
|
||||
# laws for addition and doubling. Each law is called with the symbolic point
|
||||
# coordinates as arguments, and returns:
|
||||
# - A constraint describing the assumptions under which it is applicable,
|
||||
# called "assumeLaw"
|
||||
# - A constraint describing the requirements of the law, called "require"
|
||||
# * Implementations are transliterated into functions that operate as well on
|
||||
# algebraic input points, and are called once per combination of branches
|
||||
# exectured. Each execution returns:
|
||||
# - A constraint describing the assumptions this implementation requires
|
||||
# (such as Z1=1), called "assumeFormula"
|
||||
# - A constraint describing the assumptions this specific branch requires,
|
||||
# but which is by construction guaranteed to cover the entire space by
|
||||
# merging the results from all branches, called "assumeBranch"
|
||||
# - The result of the computation
|
||||
# * All combinations of laws with implementation branches are tried, and:
|
||||
# - If the combination of assumeLaw, assumeFormula, and assumeBranch results
|
||||
# in a conflict, it means this law does not apply to this branch, and it is
|
||||
# skipped.
|
||||
# - For others, we try to prove the require constraints hold, assuming the
|
||||
# information in assumeLaw + assumeFormula + assumeBranch, and if this does
|
||||
# not succeed, we fail.
|
||||
# + To prove an expression is zero, we check whether it belongs to the
|
||||
# ideal with the assumed zero expressions as basis. This test is exact.
|
||||
# + To prove an expression is nonzero, we check whether each of its
|
||||
# factors is contained in the set of nonzero assumptions' factors.
|
||||
# This test is not exact, so various combinations of original and
|
||||
# reduced expressions' factors are tried.
|
||||
# - If we succeed, we print out the assumptions from assumeFormula that
|
||||
# weren't implied by assumeLaw already. Those from assumeBranch are skipped,
|
||||
# as we assume that all constraints in it are complementary with each other.
|
||||
#
|
||||
# Based on the sage verification scripts used in the Explicit-Formulas Database
|
||||
# by Tanja Lange and others, see http://hyperelliptic.org/EFD
|
||||
|
||||
class fastfrac:
|
||||
"""Fractions over rings."""
|
||||
|
||||
def __init__(self,R,top,bot=1):
|
||||
"""Construct a fractional, given a ring, a numerator, and denominator."""
|
||||
self.R = R
|
||||
if parent(top) == ZZ or parent(top) == R:
|
||||
self.top = R(top)
|
||||
self.bot = R(bot)
|
||||
elif top.__class__ == fastfrac:
|
||||
self.top = top.top
|
||||
self.bot = top.bot * bot
|
||||
else:
|
||||
self.top = R(numerator(top))
|
||||
self.bot = R(denominator(top)) * bot
|
||||
|
||||
def iszero(self,I):
|
||||
"""Return whether this fraction is zero given an ideal."""
|
||||
return self.top in I and self.bot not in I
|
||||
|
||||
def reduce(self,assumeZero):
|
||||
zero = self.R.ideal(map(numerator, assumeZero))
|
||||
return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot))
|
||||
|
||||
def __add__(self,other):
|
||||
"""Add two fractions."""
|
||||
if parent(other) == ZZ:
|
||||
return fastfrac(self.R,self.top + self.bot * other,self.bot)
|
||||
if other.__class__ == fastfrac:
|
||||
return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot)
|
||||
return NotImplemented
|
||||
|
||||
def __sub__(self,other):
|
||||
"""Subtract two fractions."""
|
||||
if parent(other) == ZZ:
|
||||
return fastfrac(self.R,self.top - self.bot * other,self.bot)
|
||||
if other.__class__ == fastfrac:
|
||||
return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot)
|
||||
return NotImplemented
|
||||
|
||||
def __neg__(self):
|
||||
"""Return the negation of a fraction."""
|
||||
return fastfrac(self.R,-self.top,self.bot)
|
||||
|
||||
def __mul__(self,other):
|
||||
"""Multiply two fractions."""
|
||||
if parent(other) == ZZ:
|
||||
return fastfrac(self.R,self.top * other,self.bot)
|
||||
if other.__class__ == fastfrac:
|
||||
return fastfrac(self.R,self.top * other.top,self.bot * other.bot)
|
||||
return NotImplemented
|
||||
|
||||
def __rmul__(self,other):
|
||||
"""Multiply something else with a fraction."""
|
||||
return self.__mul__(other)
|
||||
|
||||
def __div__(self,other):
|
||||
"""Divide two fractions."""
|
||||
if parent(other) == ZZ:
|
||||
return fastfrac(self.R,self.top,self.bot * other)
|
||||
if other.__class__ == fastfrac:
|
||||
return fastfrac(self.R,self.top * other.bot,self.bot * other.top)
|
||||
return NotImplemented
|
||||
|
||||
def __pow__(self,other):
|
||||
"""Compute a power of a fraction."""
|
||||
if parent(other) == ZZ:
|
||||
if other < 0:
|
||||
# Negative powers require flipping top and bottom
|
||||
return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other))
|
||||
else:
|
||||
return fastfrac(self.R,self.top ^ other,self.bot ^ other)
|
||||
return NotImplemented
|
||||
|
||||
def __str__(self):
|
||||
return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))"
|
||||
def __repr__(self):
|
||||
return "%s" % self
|
||||
|
||||
def numerator(self):
|
||||
return self.top
|
||||
|
||||
class constraints:
|
||||
"""A set of constraints, consisting of zero and nonzero expressions.
|
||||
|
||||
Constraints can either be used to express knowledge or a requirement.
|
||||
|
||||
Both the fields zero and nonzero are maps from expressions to description
|
||||
strings. The expressions that are the keys in zero are required to be zero,
|
||||
and the expressions that are the keys in nonzero are required to be nonzero.
|
||||
|
||||
Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in
|
||||
nonzero could be multiplied into a single key. This is often much less
|
||||
efficient to work with though, so we keep them separate inside the
|
||||
constraints. This allows higher-level code to do fast checks on the individual
|
||||
nonzero elements, or combine them if needed for stronger checks.
|
||||
|
||||
We can't multiply the different zero elements, as it would suffice for one of
|
||||
the factors to be zero, instead of all of them. Instead, the zero elements are
|
||||
typically combined into an ideal first.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
if 'zero' in kwargs:
|
||||
self.zero = dict(kwargs['zero'])
|
||||
else:
|
||||
self.zero = dict()
|
||||
if 'nonzero' in kwargs:
|
||||
self.nonzero = dict(kwargs['nonzero'])
|
||||
else:
|
||||
self.nonzero = dict()
|
||||
|
||||
def negate(self):
|
||||
return constraints(zero=self.nonzero, nonzero=self.zero)
|
||||
|
||||
def __add__(self, other):
|
||||
zero = self.zero.copy()
|
||||
zero.update(other.zero)
|
||||
nonzero = self.nonzero.copy()
|
||||
nonzero.update(other.nonzero)
|
||||
return constraints(zero=zero, nonzero=nonzero)
|
||||
|
||||
def __str__(self):
|
||||
return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero)
|
||||
|
||||
def __repr__(self):
|
||||
return "%s" % self
|
||||
|
||||
|
||||
def conflicts(R, con):
|
||||
"""Check whether any of the passed non-zero assumptions is implied by the zero assumptions"""
|
||||
zero = R.ideal(map(numerator, con.zero))
|
||||
if 1 in zero:
|
||||
return True
|
||||
# First a cheap check whether any of the individual nonzero terms conflict on
|
||||
# their own.
|
||||
for nonzero in con.nonzero:
|
||||
if nonzero.iszero(zero):
|
||||
return True
|
||||
# It can be the case that entries in the nonzero set do not individually
|
||||
# conflict with the zero set, but their combination does. For example, knowing
|
||||
# that either x or y is zero is equivalent to having x*y in the zero set.
|
||||
# Having x or y individually in the nonzero set is not a conflict, but both
|
||||
# simultaneously is, so that is the right thing to check for.
|
||||
if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def get_nonzero_set(R, assume):
|
||||
"""Calculate a simple set of nonzero expressions"""
|
||||
zero = R.ideal(map(numerator, assume.zero))
|
||||
nonzero = set()
|
||||
for nz in map(numerator, assume.nonzero):
|
||||
for (f,n) in nz.factor():
|
||||
nonzero.add(f)
|
||||
rnz = zero.reduce(nz)
|
||||
for (f,n) in rnz.factor():
|
||||
nonzero.add(f)
|
||||
return nonzero
|
||||
|
||||
|
||||
def prove_nonzero(R, exprs, assume):
|
||||
"""Check whether an expression is provably nonzero, given assumptions"""
|
||||
zero = R.ideal(map(numerator, assume.zero))
|
||||
nonzero = get_nonzero_set(R, assume)
|
||||
expl = set()
|
||||
ok = True
|
||||
for expr in exprs:
|
||||
if numerator(expr) in zero:
|
||||
return (False, [exprs[expr]])
|
||||
allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1)
|
||||
for (f, n) in allexprs.factor():
|
||||
if f not in nonzero:
|
||||
ok = False
|
||||
if ok:
|
||||
return (True, None)
|
||||
ok = True
|
||||
for (f, n) in zero.reduce(numerator(allexprs)).factor():
|
||||
if f not in nonzero:
|
||||
ok = False
|
||||
if ok:
|
||||
return (True, None)
|
||||
ok = True
|
||||
for expr in exprs:
|
||||
for (f,n) in numerator(expr).factor():
|
||||
if f not in nonzero:
|
||||
ok = False
|
||||
if ok:
|
||||
return (True, None)
|
||||
ok = True
|
||||
for expr in exprs:
|
||||
for (f,n) in zero.reduce(numerator(expr)).factor():
|
||||
if f not in nonzero:
|
||||
expl.add(exprs[expr])
|
||||
if expl:
|
||||
return (False, list(expl))
|
||||
else:
|
||||
return (True, None)
|
||||
|
||||
|
||||
def prove_zero(R, exprs, assume):
|
||||
"""Check whether all of the passed expressions are provably zero, given assumptions"""
|
||||
r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume)
|
||||
if not r:
|
||||
return (False, map(lambda x: "Possibly zero denominator: %s" % x, e))
|
||||
zero = R.ideal(map(numerator, assume.zero))
|
||||
nonzero = prod(x for x in assume.nonzero)
|
||||
expl = []
|
||||
for expr in exprs:
|
||||
if not expr.iszero(zero):
|
||||
expl.append(exprs[expr])
|
||||
if not expl:
|
||||
return (True, None)
|
||||
return (False, expl)
|
||||
|
||||
|
||||
def describe_extra(R, assume, assumeExtra):
|
||||
"""Describe what assumptions are added, given existing assumptions"""
|
||||
zerox = assume.zero.copy()
|
||||
zerox.update(assumeExtra.zero)
|
||||
zero = R.ideal(map(numerator, assume.zero))
|
||||
zeroextra = R.ideal(map(numerator, zerox))
|
||||
nonzero = get_nonzero_set(R, assume)
|
||||
ret = set()
|
||||
# Iterate over the extra zero expressions
|
||||
for base in assumeExtra.zero:
|
||||
if base not in zero:
|
||||
add = []
|
||||
for (f, n) in numerator(base).factor():
|
||||
if f not in nonzero:
|
||||
add += ["%s" % f]
|
||||
if add:
|
||||
ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base])
|
||||
# Iterate over the extra nonzero expressions
|
||||
for nz in assumeExtra.nonzero:
|
||||
nzr = zeroextra.reduce(numerator(nz))
|
||||
if nzr not in zeroextra:
|
||||
for (f,n) in nzr.factor():
|
||||
if zeroextra.reduce(f) not in nonzero:
|
||||
ret.add("%s != 0" % zeroextra.reduce(f))
|
||||
return ", ".join(x for x in ret)
|
||||
|
||||
|
||||
def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require):
|
||||
"""Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions"""
|
||||
assume = assumeLaw + assumeAssert + assumeBranch
|
||||
|
||||
if conflicts(R, assume):
|
||||
# This formula does not apply
|
||||
return None
|
||||
|
||||
describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert)
|
||||
|
||||
ok, msg = prove_zero(R, require.zero, assume)
|
||||
if not ok:
|
||||
return "FAIL, %s fails (assuming %s)" % (str(msg), describe)
|
||||
|
||||
res, expl = prove_nonzero(R, require.nonzero, assume)
|
||||
if not res:
|
||||
return "FAIL, %s fails (assuming %s)" % (str(expl), describe)
|
||||
|
||||
if describe != "":
|
||||
return "OK (assuming %s)" % describe
|
||||
else:
|
||||
return "OK"
|
||||
|
||||
|
||||
def concrete_verify(c):
|
||||
for k in c.zero:
|
||||
if k != 0:
|
||||
return (False, c.zero[k])
|
||||
for k in c.nonzero:
|
||||
if k == 0:
|
||||
return (False, c.nonzero[k])
|
||||
return (True, None)
|
|
@ -0,0 +1,306 @@
|
|||
# Test libsecp256k1' group operation implementations using prover.sage
|
||||
|
||||
import sys
|
||||
|
||||
load("group_prover.sage")
|
||||
load("weierstrass_prover.sage")
|
||||
|
||||
def formula_secp256k1_gej_double_var(a):
|
||||
"""libsecp256k1's secp256k1_gej_double_var, used by various addition functions"""
|
||||
rz = a.Z * a.Y
|
||||
rz = rz * 2
|
||||
t1 = a.X^2
|
||||
t1 = t1 * 3
|
||||
t2 = t1^2
|
||||
t3 = a.Y^2
|
||||
t3 = t3 * 2
|
||||
t4 = t3^2
|
||||
t4 = t4 * 2
|
||||
t3 = t3 * a.X
|
||||
rx = t3
|
||||
rx = rx * 4
|
||||
rx = -rx
|
||||
rx = rx + t2
|
||||
t2 = -t2
|
||||
t3 = t3 * 6
|
||||
t3 = t3 + t2
|
||||
ry = t1 * t3
|
||||
t2 = -t4
|
||||
ry = ry + t2
|
||||
return jacobianpoint(rx, ry, rz)
|
||||
|
||||
def formula_secp256k1_gej_add_var(branch, a, b):
|
||||
"""libsecp256k1's secp256k1_gej_add_var"""
|
||||
if branch == 0:
|
||||
return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b)
|
||||
if branch == 1:
|
||||
return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a)
|
||||
z22 = b.Z^2
|
||||
z12 = a.Z^2
|
||||
u1 = a.X * z22
|
||||
u2 = b.X * z12
|
||||
s1 = a.Y * z22
|
||||
s1 = s1 * b.Z
|
||||
s2 = b.Y * z12
|
||||
s2 = s2 * a.Z
|
||||
h = -u1
|
||||
h = h + u2
|
||||
i = -s1
|
||||
i = i + s2
|
||||
if branch == 2:
|
||||
r = formula_secp256k1_gej_double_var(a)
|
||||
return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r)
|
||||
if branch == 3:
|
||||
return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity())
|
||||
i2 = i^2
|
||||
h2 = h^2
|
||||
h3 = h2 * h
|
||||
h = h * b.Z
|
||||
rz = a.Z * h
|
||||
t = u1 * h2
|
||||
rx = t
|
||||
rx = rx * 2
|
||||
rx = rx + h3
|
||||
rx = -rx
|
||||
rx = rx + i2
|
||||
ry = -rx
|
||||
ry = ry + t
|
||||
ry = ry * i
|
||||
h3 = h3 * s1
|
||||
h3 = -h3
|
||||
ry = ry + h3
|
||||
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
|
||||
|
||||
def formula_secp256k1_gej_add_ge_var(branch, a, b):
|
||||
"""libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1"""
|
||||
if branch == 0:
|
||||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b)
|
||||
if branch == 1:
|
||||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a)
|
||||
z12 = a.Z^2
|
||||
u1 = a.X
|
||||
u2 = b.X * z12
|
||||
s1 = a.Y
|
||||
s2 = b.Y * z12
|
||||
s2 = s2 * a.Z
|
||||
h = -u1
|
||||
h = h + u2
|
||||
i = -s1
|
||||
i = i + s2
|
||||
if (branch == 2):
|
||||
r = formula_secp256k1_gej_double_var(a)
|
||||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r)
|
||||
if (branch == 3):
|
||||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity())
|
||||
i2 = i^2
|
||||
h2 = h^2
|
||||
h3 = h * h2
|
||||
rz = a.Z * h
|
||||
t = u1 * h2
|
||||
rx = t
|
||||
rx = rx * 2
|
||||
rx = rx + h3
|
||||
rx = -rx
|
||||
rx = rx + i2
|
||||
ry = -rx
|
||||
ry = ry + t
|
||||
ry = ry * i
|
||||
h3 = h3 * s1
|
||||
h3 = -h3
|
||||
ry = ry + h3
|
||||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
|
||||
|
||||
def formula_secp256k1_gej_add_zinv_var(branch, a, b):
|
||||
"""libsecp256k1's secp256k1_gej_add_zinv_var"""
|
||||
bzinv = b.Z^(-1)
|
||||
if branch == 0:
|
||||
return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a)
|
||||
if branch == 1:
|
||||
bzinv2 = bzinv^2
|
||||
bzinv3 = bzinv2 * bzinv
|
||||
rx = b.X * bzinv2
|
||||
ry = b.Y * bzinv3
|
||||
rz = 1
|
||||
return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz))
|
||||
azz = a.Z * bzinv
|
||||
z12 = azz^2
|
||||
u1 = a.X
|
||||
u2 = b.X * z12
|
||||
s1 = a.Y
|
||||
s2 = b.Y * z12
|
||||
s2 = s2 * azz
|
||||
h = -u1
|
||||
h = h + u2
|
||||
i = -s1
|
||||
i = i + s2
|
||||
if branch == 2:
|
||||
r = formula_secp256k1_gej_double_var(a)
|
||||
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r)
|
||||
if branch == 3:
|
||||
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity())
|
||||
i2 = i^2
|
||||
h2 = h^2
|
||||
h3 = h * h2
|
||||
rz = a.Z
|
||||
rz = rz * h
|
||||
t = u1 * h2
|
||||
rx = t
|
||||
rx = rx * 2
|
||||
rx = rx + h3
|
||||
rx = -rx
|
||||
rx = rx + i2
|
||||
ry = -rx
|
||||
ry = ry + t
|
||||
ry = ry * i
|
||||
h3 = h3 * s1
|
||||
h3 = -h3
|
||||
ry = ry + h3
|
||||
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
|
||||
|
||||
def formula_secp256k1_gej_add_ge(branch, a, b):
|
||||
"""libsecp256k1's secp256k1_gej_add_ge"""
|
||||
zeroes = {}
|
||||
nonzeroes = {}
|
||||
a_infinity = False
|
||||
if (branch & 4) != 0:
|
||||
nonzeroes.update({a.Infinity : 'a_infinite'})
|
||||
a_infinity = True
|
||||
else:
|
||||
zeroes.update({a.Infinity : 'a_finite'})
|
||||
zz = a.Z^2
|
||||
u1 = a.X
|
||||
u2 = b.X * zz
|
||||
s1 = a.Y
|
||||
s2 = b.Y * zz
|
||||
s2 = s2 * a.Z
|
||||
t = u1
|
||||
t = t + u2
|
||||
m = s1
|
||||
m = m + s2
|
||||
rr = t^2
|
||||
m_alt = -u2
|
||||
tt = u1 * m_alt
|
||||
rr = rr + tt
|
||||
degenerate = (branch & 3) == 3
|
||||
if (branch & 1) != 0:
|
||||
zeroes.update({m : 'm_zero'})
|
||||
else:
|
||||
nonzeroes.update({m : 'm_nonzero'})
|
||||
if (branch & 2) != 0:
|
||||
zeroes.update({rr : 'rr_zero'})
|
||||
else:
|
||||
nonzeroes.update({rr : 'rr_nonzero'})
|
||||
rr_alt = s1
|
||||
rr_alt = rr_alt * 2
|
||||
m_alt = m_alt + u1
|
||||
if not degenerate:
|
||||
rr_alt = rr
|
||||
m_alt = m
|
||||
n = m_alt^2
|
||||
q = n * t
|
||||
n = n^2
|
||||
if degenerate:
|
||||
n = m
|
||||
t = rr_alt^2
|
||||
rz = a.Z * m_alt
|
||||
infinity = False
|
||||
if (branch & 8) != 0:
|
||||
if not a_infinity:
|
||||
infinity = True
|
||||
zeroes.update({rz : 'r.z=0'})
|
||||
else:
|
||||
nonzeroes.update({rz : 'r.z!=0'})
|
||||
rz = rz * 2
|
||||
q = -q
|
||||
t = t + q
|
||||
rx = t
|
||||
t = t * 2
|
||||
t = t + q
|
||||
t = t * rr_alt
|
||||
t = t + n
|
||||
ry = -t
|
||||
rx = rx * 4
|
||||
ry = ry * 4
|
||||
if a_infinity:
|
||||
rx = b.X
|
||||
ry = b.Y
|
||||
rz = 1
|
||||
if infinity:
|
||||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity())
|
||||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz))
|
||||
|
||||
def formula_secp256k1_gej_add_ge_old(branch, a, b):
|
||||
"""libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx"""
|
||||
a_infinity = (branch & 1) != 0
|
||||
zero = {}
|
||||
nonzero = {}
|
||||
if a_infinity:
|
||||
nonzero.update({a.Infinity : 'a_infinite'})
|
||||
else:
|
||||
zero.update({a.Infinity : 'a_finite'})
|
||||
zz = a.Z^2
|
||||
u1 = a.X
|
||||
u2 = b.X * zz
|
||||
s1 = a.Y
|
||||
s2 = b.Y * zz
|
||||
s2 = s2 * a.Z
|
||||
z = a.Z
|
||||
t = u1
|
||||
t = t + u2
|
||||
m = s1
|
||||
m = m + s2
|
||||
n = m^2
|
||||
q = n * t
|
||||
n = n^2
|
||||
rr = t^2
|
||||
t = u1 * u2
|
||||
t = -t
|
||||
rr = rr + t
|
||||
t = rr^2
|
||||
rz = m * z
|
||||
infinity = False
|
||||
if (branch & 2) != 0:
|
||||
if not a_infinity:
|
||||
infinity = True
|
||||
else:
|
||||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity())
|
||||
zero.update({rz : 'r.z=0'})
|
||||
else:
|
||||
nonzero.update({rz : 'r.z!=0'})
|
||||
rz = rz * (0 if a_infinity else 2)
|
||||
rx = t
|
||||
q = -q
|
||||
rx = rx + q
|
||||
q = q * 3
|
||||
t = t * 2
|
||||
t = t + q
|
||||
t = t * rr
|
||||
t = t + n
|
||||
ry = -t
|
||||
rx = rx * (0 if a_infinity else 4)
|
||||
ry = ry * (0 if a_infinity else 4)
|
||||
t = b.X
|
||||
t = t * (1 if a_infinity else 0)
|
||||
rx = rx + t
|
||||
t = b.Y
|
||||
t = t * (1 if a_infinity else 0)
|
||||
ry = ry + t
|
||||
t = (1 if a_infinity else 0)
|
||||
rz = rz + t
|
||||
if infinity:
|
||||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity())
|
||||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz))
|
||||
|
||||
if __name__ == "__main__":
|
||||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
|
||||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
|
||||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
|
||||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge)
|
||||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old)
|
||||
|
||||
if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive":
|
||||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
|
||||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
|
||||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
|
||||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)
|
||||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)
|
|
@ -0,0 +1,264 @@
|
|||
# Prover implementation for Weierstrass curves of the form
|
||||
# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws
|
||||
# operating on affine and Jacobian coordinates, including the point at infinity
|
||||
# represented by a 4th variable in coordinates.
|
||||
|
||||
load("group_prover.sage")
|
||||
|
||||
|
||||
class affinepoint:
|
||||
def __init__(self, x, y, infinity=0):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.infinity = infinity
|
||||
def __str__(self):
|
||||
return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity)
|
||||
|
||||
|
||||
class jacobianpoint:
|
||||
def __init__(self, x, y, z, infinity=0):
|
||||
self.X = x
|
||||
self.Y = y
|
||||
self.Z = z
|
||||
self.Infinity = infinity
|
||||
def __str__(self):
|
||||
return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity)
|
||||
|
||||
|
||||
def point_at_infinity():
|
||||
return jacobianpoint(1, 1, 1, 1)
|
||||
|
||||
|
||||
def negate(p):
|
||||
if p.__class__ == affinepoint:
|
||||
return affinepoint(p.x, -p.y)
|
||||
if p.__class__ == jacobianpoint:
|
||||
return jacobianpoint(p.X, -p.Y, p.Z)
|
||||
assert(False)
|
||||
|
||||
|
||||
def on_weierstrass_curve(A, B, p):
|
||||
"""Return a set of zero-expressions for an affine point to be on the curve"""
|
||||
return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'})
|
||||
|
||||
|
||||
def tangential_to_weierstrass_curve(A, B, p12, p3):
|
||||
"""Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)"""
|
||||
return constraints(zero={
|
||||
(p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve'
|
||||
})
|
||||
|
||||
|
||||
def colinear(p1, p2, p3):
|
||||
"""Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear"""
|
||||
return constraints(zero={
|
||||
(p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1',
|
||||
(p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2',
|
||||
(p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3'
|
||||
})
|
||||
|
||||
|
||||
def good_affine_point(p):
|
||||
return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'})
|
||||
|
||||
|
||||
def good_jacobian_point(p):
|
||||
return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'})
|
||||
|
||||
|
||||
def good_point(p):
|
||||
return constraints(nonzero={p.Z^6 : 'nonzero_X'})
|
||||
|
||||
|
||||
def finite(p, *affine_fns):
|
||||
con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'})
|
||||
if p.Z != 0:
|
||||
return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con)
|
||||
else:
|
||||
return con
|
||||
|
||||
def infinite(p):
|
||||
return constraints(nonzero={p.Infinity : 'infinite_point'})
|
||||
|
||||
|
||||
def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC):
|
||||
"""Check whether the passed set of coordinates is a valid Jacobian add, given assumptions"""
|
||||
assumeLaw = (good_affine_point(pa) +
|
||||
good_affine_point(pb) +
|
||||
good_jacobian_point(pA) +
|
||||
good_jacobian_point(pB) +
|
||||
on_weierstrass_curve(A, B, pa) +
|
||||
on_weierstrass_curve(A, B, pb) +
|
||||
finite(pA) +
|
||||
finite(pB) +
|
||||
constraints(nonzero={pa.x - pb.x : 'different_x'}))
|
||||
require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +
|
||||
colinear(pa, pb, negate(pc))))
|
||||
return (assumeLaw, require)
|
||||
|
||||
|
||||
def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC):
|
||||
"""Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions"""
|
||||
assumeLaw = (good_affine_point(pa) +
|
||||
good_affine_point(pb) +
|
||||
good_jacobian_point(pA) +
|
||||
good_jacobian_point(pB) +
|
||||
on_weierstrass_curve(A, B, pa) +
|
||||
on_weierstrass_curve(A, B, pb) +
|
||||
finite(pA) +
|
||||
finite(pB) +
|
||||
constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'}))
|
||||
require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +
|
||||
tangential_to_weierstrass_curve(A, B, pa, negate(pc))))
|
||||
return (assumeLaw, require)
|
||||
|
||||
|
||||
def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC):
|
||||
assumeLaw = (good_affine_point(pa) +
|
||||
good_affine_point(pb) +
|
||||
good_jacobian_point(pA) +
|
||||
good_jacobian_point(pB) +
|
||||
on_weierstrass_curve(A, B, pa) +
|
||||
on_weierstrass_curve(A, B, pb) +
|
||||
finite(pA) +
|
||||
finite(pB) +
|
||||
constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'}))
|
||||
require = infinite(pC)
|
||||
return (assumeLaw, require)
|
||||
|
||||
|
||||
def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC):
|
||||
assumeLaw = (good_affine_point(pa) +
|
||||
good_affine_point(pb) +
|
||||
good_jacobian_point(pA) +
|
||||
good_jacobian_point(pB) +
|
||||
on_weierstrass_curve(A, B, pb) +
|
||||
infinite(pA) +
|
||||
finite(pB))
|
||||
require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'}))
|
||||
return (assumeLaw, require)
|
||||
|
||||
|
||||
def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC):
|
||||
assumeLaw = (good_affine_point(pa) +
|
||||
good_affine_point(pb) +
|
||||
good_jacobian_point(pA) +
|
||||
good_jacobian_point(pB) +
|
||||
on_weierstrass_curve(A, B, pa) +
|
||||
infinite(pB) +
|
||||
finite(pA))
|
||||
require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'}))
|
||||
return (assumeLaw, require)
|
||||
|
||||
|
||||
def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC):
|
||||
assumeLaw = (good_affine_point(pa) +
|
||||
good_affine_point(pb) +
|
||||
good_jacobian_point(pA) +
|
||||
good_jacobian_point(pB) +
|
||||
infinite(pA) +
|
||||
infinite(pB))
|
||||
require = infinite(pC)
|
||||
return (assumeLaw, require)
|
||||
|
||||
|
||||
laws_jacobian_weierstrass = {
|
||||
'add': law_jacobian_weierstrass_add,
|
||||
'double': law_jacobian_weierstrass_double,
|
||||
'add_opposite': law_jacobian_weierstrass_add_opposites,
|
||||
'add_infinite_a': law_jacobian_weierstrass_add_infinite_a,
|
||||
'add_infinite_b': law_jacobian_weierstrass_add_infinite_b,
|
||||
'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab
|
||||
}
|
||||
|
||||
|
||||
def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
|
||||
"""Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field"""
|
||||
F = Integers(p)
|
||||
print "Formula %s on Z%i:" % (name, p)
|
||||
points = []
|
||||
for x in xrange(0, p):
|
||||
for y in xrange(0, p):
|
||||
point = affinepoint(F(x), F(y))
|
||||
r, e = concrete_verify(on_weierstrass_curve(A, B, point))
|
||||
if r:
|
||||
points.append(point)
|
||||
|
||||
for za in xrange(1, p):
|
||||
for zb in xrange(1, p):
|
||||
for pa in points:
|
||||
for pb in points:
|
||||
for ia in xrange(2):
|
||||
for ib in xrange(2):
|
||||
pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia)
|
||||
pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib)
|
||||
for branch in xrange(0, branches):
|
||||
assumeAssert, assumeBranch, pC = formula(branch, pA, pB)
|
||||
pC.X = F(pC.X)
|
||||
pC.Y = F(pC.Y)
|
||||
pC.Z = F(pC.Z)
|
||||
pC.Infinity = F(pC.Infinity)
|
||||
r, e = concrete_verify(assumeAssert + assumeBranch)
|
||||
if r:
|
||||
match = False
|
||||
for key in laws_jacobian_weierstrass:
|
||||
assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC)
|
||||
r, e = concrete_verify(assumeLaw)
|
||||
if r:
|
||||
if match:
|
||||
print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity)
|
||||
else:
|
||||
match = True
|
||||
r, e = concrete_verify(require)
|
||||
if not r:
|
||||
print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e)
|
||||
print
|
||||
|
||||
|
||||
def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC):
|
||||
assumeLaw, require = f(A, B, pa, pb, pA, pB, pC)
|
||||
return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require)
|
||||
|
||||
def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
|
||||
"""Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically"""
|
||||
R.<ax,bx,ay,by,Az,Bz,Ai,Bi> = PolynomialRing(QQ,8,order='invlex')
|
||||
lift = lambda x: fastfrac(R,x)
|
||||
ax = lift(ax)
|
||||
ay = lift(ay)
|
||||
Az = lift(Az)
|
||||
bx = lift(bx)
|
||||
by = lift(by)
|
||||
Bz = lift(Bz)
|
||||
Ai = lift(Ai)
|
||||
Bi = lift(Bi)
|
||||
|
||||
pa = affinepoint(ax, ay, Ai)
|
||||
pb = affinepoint(bx, by, Bi)
|
||||
pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai)
|
||||
pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi)
|
||||
|
||||
res = {}
|
||||
|
||||
for key in laws_jacobian_weierstrass:
|
||||
res[key] = []
|
||||
|
||||
print ("Formula " + name + ":")
|
||||
count = 0
|
||||
for branch in xrange(branches):
|
||||
assumeFormula, assumeBranch, pC = formula(branch, pA, pB)
|
||||
pC.X = lift(pC.X)
|
||||
pC.Y = lift(pC.Y)
|
||||
pC.Z = lift(pC.Z)
|
||||
pC.Infinity = lift(pC.Infinity)
|
||||
|
||||
for key in laws_jacobian_weierstrass:
|
||||
res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch))
|
||||
|
||||
for key in res:
|
||||
print " %s:" % key
|
||||
val = res[key]
|
||||
for x in val:
|
||||
if x[0] is not None:
|
||||
print " branch %i: %s" % (x[1], x[0])
|
||||
|
||||
print
|
|
@ -0,0 +1,919 @@
|
|||
@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm:
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2014 Wladimir J. van der Laan *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
/*
|
||||
ARM implementation of field_10x26 inner loops.
|
||||
|
||||
Note:
|
||||
|
||||
- To avoid unnecessary loads and make use of available registers, two
|
||||
'passes' have every time been interleaved, with the odd passes accumulating c' and d'
|
||||
which will be added to c and d respectively in the the even passes
|
||||
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
.arch armv7-a
|
||||
@ eabi attributes - see readelf -A
|
||||
.eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes
|
||||
.eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no
|
||||
.eabi_attribute 10, 0 @ Tag_FP_arch = none
|
||||
.eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte
|
||||
.eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP
|
||||
.eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed
|
||||
.eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6
|
||||
.text
|
||||
|
||||
@ Field constants
|
||||
.set field_R0, 0x3d10
|
||||
.set field_R1, 0x400
|
||||
.set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff
|
||||
|
||||
.align 2
|
||||
.global secp256k1_fe_mul_inner
|
||||
.type secp256k1_fe_mul_inner, %function
|
||||
@ Arguments:
|
||||
@ r0 r Restrict: can overlap with a, not with b
|
||||
@ r1 a
|
||||
@ r2 b
|
||||
@ Stack (total 4+10*4 = 44)
|
||||
@ sp + #0 saved 'r' pointer
|
||||
@ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9
|
||||
secp256k1_fe_mul_inner:
|
||||
stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14}
|
||||
sub sp, sp, #48 @ frame=44 + alignment
|
||||
str r0, [sp, #0] @ save result address, we need it only at the end
|
||||
|
||||
/******************************************
|
||||
* Main computation code.
|
||||
******************************************
|
||||
|
||||
Allocation:
|
||||
r0,r14,r7,r8 scratch
|
||||
r1 a (pointer)
|
||||
r2 b (pointer)
|
||||
r3:r4 c
|
||||
r5:r6 d
|
||||
r11:r12 c'
|
||||
r9:r10 d'
|
||||
|
||||
Note: do not write to r[] here, it may overlap with a[]
|
||||
*/
|
||||
|
||||
/* A - interleaved with B */
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
ldr r8, [r2, #9*4] @ b[9]
|
||||
ldr r0, [r1, #1*4] @ a[1]
|
||||
umull r5, r6, r7, r8 @ d = a[0] * b[9]
|
||||
ldr r14, [r2, #8*4] @ b[8]
|
||||
umull r9, r10, r0, r8 @ d' = a[1] * b[9]
|
||||
ldr r7, [r1, #2*4] @ a[2]
|
||||
umlal r5, r6, r0, r14 @ d += a[1] * b[8]
|
||||
ldr r8, [r2, #7*4] @ b[7]
|
||||
umlal r9, r10, r7, r14 @ d' += a[2] * b[8]
|
||||
ldr r0, [r1, #3*4] @ a[3]
|
||||
umlal r5, r6, r7, r8 @ d += a[2] * b[7]
|
||||
ldr r14, [r2, #6*4] @ b[6]
|
||||
umlal r9, r10, r0, r8 @ d' += a[3] * b[7]
|
||||
ldr r7, [r1, #4*4] @ a[4]
|
||||
umlal r5, r6, r0, r14 @ d += a[3] * b[6]
|
||||
ldr r8, [r2, #5*4] @ b[5]
|
||||
umlal r9, r10, r7, r14 @ d' += a[4] * b[6]
|
||||
ldr r0, [r1, #5*4] @ a[5]
|
||||
umlal r5, r6, r7, r8 @ d += a[4] * b[5]
|
||||
ldr r14, [r2, #4*4] @ b[4]
|
||||
umlal r9, r10, r0, r8 @ d' += a[5] * b[5]
|
||||
ldr r7, [r1, #6*4] @ a[6]
|
||||
umlal r5, r6, r0, r14 @ d += a[5] * b[4]
|
||||
ldr r8, [r2, #3*4] @ b[3]
|
||||
umlal r9, r10, r7, r14 @ d' += a[6] * b[4]
|
||||
ldr r0, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r7, r8 @ d += a[6] * b[3]
|
||||
ldr r14, [r2, #2*4] @ b[2]
|
||||
umlal r9, r10, r0, r8 @ d' += a[7] * b[3]
|
||||
ldr r7, [r1, #8*4] @ a[8]
|
||||
umlal r5, r6, r0, r14 @ d += a[7] * b[2]
|
||||
ldr r8, [r2, #1*4] @ b[1]
|
||||
umlal r9, r10, r7, r14 @ d' += a[8] * b[2]
|
||||
ldr r0, [r1, #9*4] @ a[9]
|
||||
umlal r5, r6, r7, r8 @ d += a[8] * b[1]
|
||||
ldr r14, [r2, #0*4] @ b[0]
|
||||
umlal r9, r10, r0, r8 @ d' += a[9] * b[1]
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
umlal r5, r6, r0, r14 @ d += a[9] * b[0]
|
||||
@ r7,r14 used in B
|
||||
|
||||
bic r0, r5, field_not_M @ t9 = d & M
|
||||
str r0, [sp, #4 + 4*9]
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
|
||||
/* B */
|
||||
umull r3, r4, r7, r14 @ c = a[0] * b[0]
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u0 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u0 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t0 = c & M
|
||||
str r14, [sp, #4 + 0*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u0 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* C - interleaved with D */
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
ldr r8, [r2, #2*4] @ b[2]
|
||||
ldr r14, [r2, #1*4] @ b[1]
|
||||
umull r11, r12, r7, r8 @ c' = a[0] * b[2]
|
||||
ldr r0, [r1, #1*4] @ a[1]
|
||||
umlal r3, r4, r7, r14 @ c += a[0] * b[1]
|
||||
ldr r8, [r2, #0*4] @ b[0]
|
||||
umlal r11, r12, r0, r14 @ c' += a[1] * b[1]
|
||||
ldr r7, [r1, #2*4] @ a[2]
|
||||
umlal r3, r4, r0, r8 @ c += a[1] * b[0]
|
||||
ldr r14, [r2, #9*4] @ b[9]
|
||||
umlal r11, r12, r7, r8 @ c' += a[2] * b[0]
|
||||
ldr r0, [r1, #3*4] @ a[3]
|
||||
umlal r5, r6, r7, r14 @ d += a[2] * b[9]
|
||||
ldr r8, [r2, #8*4] @ b[8]
|
||||
umull r9, r10, r0, r14 @ d' = a[3] * b[9]
|
||||
ldr r7, [r1, #4*4] @ a[4]
|
||||
umlal r5, r6, r0, r8 @ d += a[3] * b[8]
|
||||
ldr r14, [r2, #7*4] @ b[7]
|
||||
umlal r9, r10, r7, r8 @ d' += a[4] * b[8]
|
||||
ldr r0, [r1, #5*4] @ a[5]
|
||||
umlal r5, r6, r7, r14 @ d += a[4] * b[7]
|
||||
ldr r8, [r2, #6*4] @ b[6]
|
||||
umlal r9, r10, r0, r14 @ d' += a[5] * b[7]
|
||||
ldr r7, [r1, #6*4] @ a[6]
|
||||
umlal r5, r6, r0, r8 @ d += a[5] * b[6]
|
||||
ldr r14, [r2, #5*4] @ b[5]
|
||||
umlal r9, r10, r7, r8 @ d' += a[6] * b[6]
|
||||
ldr r0, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r7, r14 @ d += a[6] * b[5]
|
||||
ldr r8, [r2, #4*4] @ b[4]
|
||||
umlal r9, r10, r0, r14 @ d' += a[7] * b[5]
|
||||
ldr r7, [r1, #8*4] @ a[8]
|
||||
umlal r5, r6, r0, r8 @ d += a[7] * b[4]
|
||||
ldr r14, [r2, #3*4] @ b[3]
|
||||
umlal r9, r10, r7, r8 @ d' += a[8] * b[4]
|
||||
ldr r0, [r1, #9*4] @ a[9]
|
||||
umlal r5, r6, r7, r14 @ d += a[8] * b[3]
|
||||
ldr r8, [r2, #2*4] @ b[2]
|
||||
umlal r9, r10, r0, r14 @ d' += a[9] * b[3]
|
||||
umlal r5, r6, r0, r8 @ d += a[9] * b[2]
|
||||
|
||||
bic r0, r5, field_not_M @ u1 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u1 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t1 = c & M
|
||||
str r14, [sp, #4 + 1*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u1 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* D */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u2 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u2 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t2 = c & M
|
||||
str r14, [sp, #4 + 2*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u2 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* E - interleaved with F */
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
ldr r8, [r2, #4*4] @ b[4]
|
||||
umull r11, r12, r7, r8 @ c' = a[0] * b[4]
|
||||
ldr r8, [r2, #3*4] @ b[3]
|
||||
umlal r3, r4, r7, r8 @ c += a[0] * b[3]
|
||||
ldr r7, [r1, #1*4] @ a[1]
|
||||
umlal r11, r12, r7, r8 @ c' += a[1] * b[3]
|
||||
ldr r8, [r2, #2*4] @ b[2]
|
||||
umlal r3, r4, r7, r8 @ c += a[1] * b[2]
|
||||
ldr r7, [r1, #2*4] @ a[2]
|
||||
umlal r11, r12, r7, r8 @ c' += a[2] * b[2]
|
||||
ldr r8, [r2, #1*4] @ b[1]
|
||||
umlal r3, r4, r7, r8 @ c += a[2] * b[1]
|
||||
ldr r7, [r1, #3*4] @ a[3]
|
||||
umlal r11, r12, r7, r8 @ c' += a[3] * b[1]
|
||||
ldr r8, [r2, #0*4] @ b[0]
|
||||
umlal r3, r4, r7, r8 @ c += a[3] * b[0]
|
||||
ldr r7, [r1, #4*4] @ a[4]
|
||||
umlal r11, r12, r7, r8 @ c' += a[4] * b[0]
|
||||
ldr r8, [r2, #9*4] @ b[9]
|
||||
umlal r5, r6, r7, r8 @ d += a[4] * b[9]
|
||||
ldr r7, [r1, #5*4] @ a[5]
|
||||
umull r9, r10, r7, r8 @ d' = a[5] * b[9]
|
||||
ldr r8, [r2, #8*4] @ b[8]
|
||||
umlal r5, r6, r7, r8 @ d += a[5] * b[8]
|
||||
ldr r7, [r1, #6*4] @ a[6]
|
||||
umlal r9, r10, r7, r8 @ d' += a[6] * b[8]
|
||||
ldr r8, [r2, #7*4] @ b[7]
|
||||
umlal r5, r6, r7, r8 @ d += a[6] * b[7]
|
||||
ldr r7, [r1, #7*4] @ a[7]
|
||||
umlal r9, r10, r7, r8 @ d' += a[7] * b[7]
|
||||
ldr r8, [r2, #6*4] @ b[6]
|
||||
umlal r5, r6, r7, r8 @ d += a[7] * b[6]
|
||||
ldr r7, [r1, #8*4] @ a[8]
|
||||
umlal r9, r10, r7, r8 @ d' += a[8] * b[6]
|
||||
ldr r8, [r2, #5*4] @ b[5]
|
||||
umlal r5, r6, r7, r8 @ d += a[8] * b[5]
|
||||
ldr r7, [r1, #9*4] @ a[9]
|
||||
umlal r9, r10, r7, r8 @ d' += a[9] * b[5]
|
||||
ldr r8, [r2, #4*4] @ b[4]
|
||||
umlal r5, r6, r7, r8 @ d += a[9] * b[4]
|
||||
|
||||
bic r0, r5, field_not_M @ u3 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u3 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t3 = c & M
|
||||
str r14, [sp, #4 + 3*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u3 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* F */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u4 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u4 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t4 = c & M
|
||||
str r14, [sp, #4 + 4*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u4 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* G - interleaved with H */
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
ldr r8, [r2, #6*4] @ b[6]
|
||||
ldr r14, [r2, #5*4] @ b[5]
|
||||
umull r11, r12, r7, r8 @ c' = a[0] * b[6]
|
||||
ldr r0, [r1, #1*4] @ a[1]
|
||||
umlal r3, r4, r7, r14 @ c += a[0] * b[5]
|
||||
ldr r8, [r2, #4*4] @ b[4]
|
||||
umlal r11, r12, r0, r14 @ c' += a[1] * b[5]
|
||||
ldr r7, [r1, #2*4] @ a[2]
|
||||
umlal r3, r4, r0, r8 @ c += a[1] * b[4]
|
||||
ldr r14, [r2, #3*4] @ b[3]
|
||||
umlal r11, r12, r7, r8 @ c' += a[2] * b[4]
|
||||
ldr r0, [r1, #3*4] @ a[3]
|
||||
umlal r3, r4, r7, r14 @ c += a[2] * b[3]
|
||||
ldr r8, [r2, #2*4] @ b[2]
|
||||
umlal r11, r12, r0, r14 @ c' += a[3] * b[3]
|
||||
ldr r7, [r1, #4*4] @ a[4]
|
||||
umlal r3, r4, r0, r8 @ c += a[3] * b[2]
|
||||
ldr r14, [r2, #1*4] @ b[1]
|
||||
umlal r11, r12, r7, r8 @ c' += a[4] * b[2]
|
||||
ldr r0, [r1, #5*4] @ a[5]
|
||||
umlal r3, r4, r7, r14 @ c += a[4] * b[1]
|
||||
ldr r8, [r2, #0*4] @ b[0]
|
||||
umlal r11, r12, r0, r14 @ c' += a[5] * b[1]
|
||||
ldr r7, [r1, #6*4] @ a[6]
|
||||
umlal r3, r4, r0, r8 @ c += a[5] * b[0]
|
||||
ldr r14, [r2, #9*4] @ b[9]
|
||||
umlal r11, r12, r7, r8 @ c' += a[6] * b[0]
|
||||
ldr r0, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r7, r14 @ d += a[6] * b[9]
|
||||
ldr r8, [r2, #8*4] @ b[8]
|
||||
umull r9, r10, r0, r14 @ d' = a[7] * b[9]
|
||||
ldr r7, [r1, #8*4] @ a[8]
|
||||
umlal r5, r6, r0, r8 @ d += a[7] * b[8]
|
||||
ldr r14, [r2, #7*4] @ b[7]
|
||||
umlal r9, r10, r7, r8 @ d' += a[8] * b[8]
|
||||
ldr r0, [r1, #9*4] @ a[9]
|
||||
umlal r5, r6, r7, r14 @ d += a[8] * b[7]
|
||||
ldr r8, [r2, #6*4] @ b[6]
|
||||
umlal r9, r10, r0, r14 @ d' += a[9] * b[7]
|
||||
umlal r5, r6, r0, r8 @ d += a[9] * b[6]
|
||||
|
||||
bic r0, r5, field_not_M @ u5 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u5 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t5 = c & M
|
||||
str r14, [sp, #4 + 5*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u5 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* H */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u6 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u6 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t6 = c & M
|
||||
str r14, [sp, #4 + 6*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u6 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* I - interleaved with J */
|
||||
ldr r8, [r2, #8*4] @ b[8]
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
ldr r14, [r2, #7*4] @ b[7]
|
||||
umull r11, r12, r7, r8 @ c' = a[0] * b[8]
|
||||
ldr r0, [r1, #1*4] @ a[1]
|
||||
umlal r3, r4, r7, r14 @ c += a[0] * b[7]
|
||||
ldr r8, [r2, #6*4] @ b[6]
|
||||
umlal r11, r12, r0, r14 @ c' += a[1] * b[7]
|
||||
ldr r7, [r1, #2*4] @ a[2]
|
||||
umlal r3, r4, r0, r8 @ c += a[1] * b[6]
|
||||
ldr r14, [r2, #5*4] @ b[5]
|
||||
umlal r11, r12, r7, r8 @ c' += a[2] * b[6]
|
||||
ldr r0, [r1, #3*4] @ a[3]
|
||||
umlal r3, r4, r7, r14 @ c += a[2] * b[5]
|
||||
ldr r8, [r2, #4*4] @ b[4]
|
||||
umlal r11, r12, r0, r14 @ c' += a[3] * b[5]
|
||||
ldr r7, [r1, #4*4] @ a[4]
|
||||
umlal r3, r4, r0, r8 @ c += a[3] * b[4]
|
||||
ldr r14, [r2, #3*4] @ b[3]
|
||||
umlal r11, r12, r7, r8 @ c' += a[4] * b[4]
|
||||
ldr r0, [r1, #5*4] @ a[5]
|
||||
umlal r3, r4, r7, r14 @ c += a[4] * b[3]
|
||||
ldr r8, [r2, #2*4] @ b[2]
|
||||
umlal r11, r12, r0, r14 @ c' += a[5] * b[3]
|
||||
ldr r7, [r1, #6*4] @ a[6]
|
||||
umlal r3, r4, r0, r8 @ c += a[5] * b[2]
|
||||
ldr r14, [r2, #1*4] @ b[1]
|
||||
umlal r11, r12, r7, r8 @ c' += a[6] * b[2]
|
||||
ldr r0, [r1, #7*4] @ a[7]
|
||||
umlal r3, r4, r7, r14 @ c += a[6] * b[1]
|
||||
ldr r8, [r2, #0*4] @ b[0]
|
||||
umlal r11, r12, r0, r14 @ c' += a[7] * b[1]
|
||||
ldr r7, [r1, #8*4] @ a[8]
|
||||
umlal r3, r4, r0, r8 @ c += a[7] * b[0]
|
||||
ldr r14, [r2, #9*4] @ b[9]
|
||||
umlal r11, r12, r7, r8 @ c' += a[8] * b[0]
|
||||
ldr r0, [r1, #9*4] @ a[9]
|
||||
umlal r5, r6, r7, r14 @ d += a[8] * b[9]
|
||||
ldr r8, [r2, #8*4] @ b[8]
|
||||
umull r9, r10, r0, r14 @ d' = a[9] * b[9]
|
||||
umlal r5, r6, r0, r8 @ d += a[9] * b[8]
|
||||
|
||||
bic r0, r5, field_not_M @ u7 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u7 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t7 = c & M
|
||||
str r14, [sp, #4 + 7*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u7 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* J */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u8 = d & M
|
||||
str r0, [sp, #4 + 8*4]
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u8 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/******************************************
|
||||
* compute and write back result
|
||||
******************************************
|
||||
Allocation:
|
||||
r0 r
|
||||
r3:r4 c
|
||||
r5:r6 d
|
||||
r7 t0
|
||||
r8 t1
|
||||
r9 t2
|
||||
r11 u8
|
||||
r12 t9
|
||||
r1,r2,r10,r14 scratch
|
||||
|
||||
Note: do not read from a[] after here, it may overlap with r[]
|
||||
*/
|
||||
ldr r0, [sp, #0]
|
||||
add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9
|
||||
ldmia r1, {r2,r7,r8,r9,r10,r11,r12}
|
||||
add r1, r0, #3*4
|
||||
stmia r1, {r2,r7,r8,r9,r10}
|
||||
|
||||
bic r2, r3, field_not_M @ r[8] = c & M
|
||||
str r2, [r0, #8*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u8 * R1
|
||||
umlal r3, r4, r11, r14
|
||||
movw r14, field_R0 @ c += d * R0
|
||||
umlal r3, r4, r5, r14
|
||||
adds r3, r3, r12 @ c += t9
|
||||
adc r4, r4, #0
|
||||
|
||||
add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2
|
||||
ldmia r1, {r7,r8,r9}
|
||||
|
||||
ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4)
|
||||
str r2, [r0, #9*4]
|
||||
mov r3, r3, lsr #22 @ c >>= 22
|
||||
orr r3, r3, r4, asl #10
|
||||
mov r4, r4, lsr #22
|
||||
movw r14, field_R1 << 4 @ c += d * (R1 << 4)
|
||||
umlal r3, r4, r5, r14
|
||||
|
||||
movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add)
|
||||
umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4)
|
||||
adds r5, r5, r7 @ d.lo += t0
|
||||
mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4)
|
||||
adc r6, r6, 0 @ d.hi += carry
|
||||
|
||||
bic r2, r5, field_not_M @ r[0] = d & M
|
||||
str r2, [r0, #0*4]
|
||||
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
|
||||
movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add)
|
||||
umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4)
|
||||
adds r5, r5, r8 @ d.lo += t1
|
||||
adc r6, r6, #0 @ d.hi += carry
|
||||
adds r5, r5, r1 @ d.lo += tmp.lo
|
||||
mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4)
|
||||
adc r6, r6, r2 @ d.hi += carry + tmp.hi
|
||||
|
||||
bic r2, r5, field_not_M @ r[1] = d & M
|
||||
str r2, [r0, #1*4]
|
||||
mov r5, r5, lsr #26 @ d >>= 26 (ignore hi)
|
||||
orr r5, r5, r6, asl #6
|
||||
|
||||
add r5, r5, r9 @ d += t2
|
||||
str r5, [r0, #2*4] @ r[2] = d
|
||||
|
||||
add sp, sp, #48
|
||||
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
|
||||
.size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner
|
||||
|
||||
.align 2
|
||||
.global secp256k1_fe_sqr_inner
|
||||
.type secp256k1_fe_sqr_inner, %function
|
||||
@ Arguments:
|
||||
@ r0 r Can overlap with a
|
||||
@ r1 a
|
||||
@ Stack (total 4+10*4 = 44)
|
||||
@ sp + #0 saved 'r' pointer
|
||||
@ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9
|
||||
secp256k1_fe_sqr_inner:
|
||||
stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14}
|
||||
sub sp, sp, #48 @ frame=44 + alignment
|
||||
str r0, [sp, #0] @ save result address, we need it only at the end
|
||||
/******************************************
|
||||
* Main computation code.
|
||||
******************************************
|
||||
|
||||
Allocation:
|
||||
r0,r14,r2,r7,r8 scratch
|
||||
r1 a (pointer)
|
||||
r3:r4 c
|
||||
r5:r6 d
|
||||
r11:r12 c'
|
||||
r9:r10 d'
|
||||
|
||||
Note: do not write to r[] here, it may overlap with a[]
|
||||
*/
|
||||
/* A interleaved with B */
|
||||
ldr r0, [r1, #1*4] @ a[1]*2
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
mov r0, r0, asl #1
|
||||
ldr r14, [r1, #9*4] @ a[9]
|
||||
umull r3, r4, r7, r7 @ c = a[0] * a[0]
|
||||
ldr r8, [r1, #8*4] @ a[8]
|
||||
mov r7, r7, asl #1
|
||||
umull r5, r6, r7, r14 @ d = a[0]*2 * a[9]
|
||||
ldr r7, [r1, #2*4] @ a[2]*2
|
||||
umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9]
|
||||
ldr r14, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8]
|
||||
mov r7, r7, asl #1
|
||||
ldr r0, [r1, #3*4] @ a[3]*2
|
||||
umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8]
|
||||
ldr r8, [r1, #6*4] @ a[6]
|
||||
umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7]
|
||||
mov r0, r0, asl #1
|
||||
ldr r7, [r1, #4*4] @ a[4]*2
|
||||
umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7]
|
||||
ldr r14, [r1, #5*4] @ a[5]
|
||||
mov r7, r7, asl #1
|
||||
umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6]
|
||||
umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6]
|
||||
umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5]
|
||||
umlal r9, r10, r14, r14 @ d' += a[5] * a[5]
|
||||
|
||||
bic r0, r5, field_not_M @ t9 = d & M
|
||||
str r0, [sp, #4 + 9*4]
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
|
||||
/* B */
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u0 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u0 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t0 = c & M
|
||||
str r14, [sp, #4 + 0*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u0 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* C interleaved with D */
|
||||
ldr r0, [r1, #0*4] @ a[0]*2
|
||||
ldr r14, [r1, #1*4] @ a[1]
|
||||
mov r0, r0, asl #1
|
||||
ldr r8, [r1, #2*4] @ a[2]
|
||||
umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1]
|
||||
mov r7, r8, asl #1 @ a[2]*2
|
||||
umull r11, r12, r14, r14 @ c' = a[1] * a[1]
|
||||
ldr r14, [r1, #9*4] @ a[9]
|
||||
umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2]
|
||||
ldr r0, [r1, #3*4] @ a[3]*2
|
||||
ldr r8, [r1, #8*4] @ a[8]
|
||||
umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9]
|
||||
mov r0, r0, asl #1
|
||||
ldr r7, [r1, #4*4] @ a[4]*2
|
||||
umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9]
|
||||
ldr r14, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8]
|
||||
mov r7, r7, asl #1
|
||||
ldr r0, [r1, #5*4] @ a[5]*2
|
||||
umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8]
|
||||
ldr r8, [r1, #6*4] @ a[6]
|
||||
mov r0, r0, asl #1
|
||||
umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7]
|
||||
umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7]
|
||||
umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6]
|
||||
umlal r9, r10, r8, r8 @ d' += a[6] * a[6]
|
||||
|
||||
bic r0, r5, field_not_M @ u1 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u1 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t1 = c & M
|
||||
str r14, [sp, #4 + 1*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u1 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* D */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u2 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u2 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t2 = c & M
|
||||
str r14, [sp, #4 + 2*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u2 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* E interleaved with F */
|
||||
ldr r7, [r1, #0*4] @ a[0]*2
|
||||
ldr r0, [r1, #1*4] @ a[1]*2
|
||||
ldr r14, [r1, #2*4] @ a[2]
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #3*4] @ a[3]
|
||||
ldr r2, [r1, #4*4]
|
||||
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3]
|
||||
mov r0, r0, asl #1
|
||||
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4]
|
||||
mov r2, r2, asl #1 @ a[4]*2
|
||||
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3]
|
||||
ldr r8, [r1, #9*4] @ a[9]
|
||||
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2]
|
||||
ldr r0, [r1, #5*4] @ a[5]*2
|
||||
umlal r11, r12, r14, r14 @ c' += a[2] * a[2]
|
||||
ldr r14, [r1, #8*4] @ a[8]
|
||||
mov r0, r0, asl #1
|
||||
umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9]
|
||||
ldr r7, [r1, #6*4] @ a[6]*2
|
||||
umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9]
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8]
|
||||
umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8]
|
||||
umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7]
|
||||
umlal r9, r10, r8, r8 @ d' += a[7] * a[7]
|
||||
|
||||
bic r0, r5, field_not_M @ u3 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u3 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t3 = c & M
|
||||
str r14, [sp, #4 + 3*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u3 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* F */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u4 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u4 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t4 = c & M
|
||||
str r14, [sp, #4 + 4*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u4 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* G interleaved with H */
|
||||
ldr r7, [r1, #0*4] @ a[0]*2
|
||||
ldr r0, [r1, #1*4] @ a[1]*2
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #5*4] @ a[5]
|
||||
ldr r2, [r1, #6*4] @ a[6]
|
||||
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5]
|
||||
ldr r14, [r1, #4*4] @ a[4]
|
||||
mov r0, r0, asl #1
|
||||
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6]
|
||||
ldr r7, [r1, #2*4] @ a[2]*2
|
||||
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5]
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #3*4] @ a[3]
|
||||
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4]
|
||||
mov r0, r2, asl #1 @ a[6]*2
|
||||
umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4]
|
||||
ldr r14, [r1, #9*4] @ a[9]
|
||||
umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3]
|
||||
ldr r7, [r1, #7*4] @ a[7]*2
|
||||
umlal r11, r12, r8, r8 @ c' += a[3] * a[3]
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #8*4] @ a[8]
|
||||
umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9]
|
||||
umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9]
|
||||
umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8]
|
||||
umlal r9, r10, r8, r8 @ d' += a[8] * a[8]
|
||||
|
||||
bic r0, r5, field_not_M @ u5 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u5 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t5 = c & M
|
||||
str r14, [sp, #4 + 5*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u5 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* H */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u6 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u6 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t6 = c & M
|
||||
str r14, [sp, #4 + 6*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u6 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* I interleaved with J */
|
||||
ldr r7, [r1, #0*4] @ a[0]*2
|
||||
ldr r0, [r1, #1*4] @ a[1]*2
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #7*4] @ a[7]
|
||||
ldr r2, [r1, #8*4] @ a[8]
|
||||
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7]
|
||||
ldr r14, [r1, #6*4] @ a[6]
|
||||
mov r0, r0, asl #1
|
||||
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8]
|
||||
ldr r7, [r1, #2*4] @ a[2]*2
|
||||
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7]
|
||||
ldr r8, [r1, #5*4] @ a[5]
|
||||
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6]
|
||||
ldr r0, [r1, #3*4] @ a[3]*2
|
||||
mov r7, r7, asl #1
|
||||
umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6]
|
||||
ldr r14, [r1, #4*4] @ a[4]
|
||||
mov r0, r0, asl #1
|
||||
umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5]
|
||||
mov r2, r2, asl #1 @ a[8]*2
|
||||
umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5]
|
||||
umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4]
|
||||
umlal r11, r12, r14, r14 @ c' += a[4] * a[4]
|
||||
ldr r8, [r1, #9*4] @ a[9]
|
||||
umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9]
|
||||
@ r8 will be used in J
|
||||
|
||||
bic r0, r5, field_not_M @ u7 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u7 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t7 = c & M
|
||||
str r14, [sp, #4 + 7*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u7 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* J */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
umlal r5, r6, r8, r8 @ d += a[9] * a[9]
|
||||
|
||||
bic r0, r5, field_not_M @ u8 = d & M
|
||||
str r0, [sp, #4 + 8*4]
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u8 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/******************************************
|
||||
* compute and write back result
|
||||
******************************************
|
||||
Allocation:
|
||||
r0 r
|
||||
r3:r4 c
|
||||
r5:r6 d
|
||||
r7 t0
|
||||
r8 t1
|
||||
r9 t2
|
||||
r11 u8
|
||||
r12 t9
|
||||
r1,r2,r10,r14 scratch
|
||||
|
||||
Note: do not read from a[] after here, it may overlap with r[]
|
||||
*/
|
||||
ldr r0, [sp, #0]
|
||||
add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9
|
||||
ldmia r1, {r2,r7,r8,r9,r10,r11,r12}
|
||||
add r1, r0, #3*4
|
||||
stmia r1, {r2,r7,r8,r9,r10}
|
||||
|
||||
bic r2, r3, field_not_M @ r[8] = c & M
|
||||
str r2, [r0, #8*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u8 * R1
|
||||
umlal r3, r4, r11, r14
|
||||
movw r14, field_R0 @ c += d * R0
|
||||
umlal r3, r4, r5, r14
|
||||
adds r3, r3, r12 @ c += t9
|
||||
adc r4, r4, #0
|
||||
|
||||
add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2
|
||||
ldmia r1, {r7,r8,r9}
|
||||
|
||||
ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4)
|
||||
str r2, [r0, #9*4]
|
||||
mov r3, r3, lsr #22 @ c >>= 22
|
||||
orr r3, r3, r4, asl #10
|
||||
mov r4, r4, lsr #22
|
||||
movw r14, field_R1 << 4 @ c += d * (R1 << 4)
|
||||
umlal r3, r4, r5, r14
|
||||
|
||||
movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add)
|
||||
umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4)
|
||||
adds r5, r5, r7 @ d.lo += t0
|
||||
mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4)
|
||||
adc r6, r6, 0 @ d.hi += carry
|
||||
|
||||
bic r2, r5, field_not_M @ r[0] = d & M
|
||||
str r2, [r0, #0*4]
|
||||
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
|
||||
movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add)
|
||||
umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4)
|
||||
adds r5, r5, r8 @ d.lo += t1
|
||||
adc r6, r6, #0 @ d.hi += carry
|
||||
adds r5, r5, r1 @ d.lo += tmp.lo
|
||||
mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4)
|
||||
adc r6, r6, r2 @ d.hi += carry + tmp.hi
|
||||
|
||||
bic r2, r5, field_not_M @ r[1] = d & M
|
||||
str r2, [r0, #1*4]
|
||||
mov r5, r5, lsr #26 @ d >>= 26 (ignore hi)
|
||||
orr r5, r5, r6, asl #6
|
||||
|
||||
add r5, r5, r9 @ d += t2
|
||||
str r5, [r0, #2*4] @ r[2] = d
|
||||
|
||||
add sp, sp, #48
|
||||
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
|
||||
.size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/**********************************************************************
|
||||
* 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_
|
||||
#define _SECP256K1_BASIC_CONFIG_
|
||||
|
||||
#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_
|
|
@ -20,8 +20,10 @@ static double gettimedouble(void) {
|
|||
void print_number(double x) {
|
||||
double y = x;
|
||||
int c = 0;
|
||||
if (y < 0.0) y = -y;
|
||||
while (y < 100.0) {
|
||||
if (y < 0.0) {
|
||||
y = -y;
|
||||
}
|
||||
while (y > 0 && y < 100.0) {
|
||||
y *= 10.0;
|
||||
c++;
|
||||
}
|
||||
|
@ -35,13 +37,21 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v
|
|||
double max = 0.0;
|
||||
for (i = 0; i < count; i++) {
|
||||
double begin, total;
|
||||
if (setup) setup(data);
|
||||
if (setup != NULL) {
|
||||
setup(data);
|
||||
}
|
||||
begin = gettimedouble();
|
||||
benchmark(data);
|
||||
total = gettimedouble() - begin;
|
||||
if (teardown) teardown(data);
|
||||
if (total < min) min = total;
|
||||
if (total > max) max = total;
|
||||
if (teardown != NULL) {
|
||||
teardown(data);
|
||||
}
|
||||
if (total < min) {
|
||||
min = total;
|
||||
}
|
||||
if (total > max) {
|
||||
max = total;
|
||||
}
|
||||
sum += total;
|
||||
}
|
||||
printf("%s: min ", name);
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/**********************************************************************
|
||||
* 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 <string.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -13,15 +13,17 @@
|
|||
#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_t scalar_x, scalar_y;
|
||||
secp256k1_fe_t fe_x, fe_y;
|
||||
secp256k1_ge_t ge_x, ge_y;
|
||||
secp256k1_gej_t gej_x, gej_y;
|
||||
unsigned char data[32];
|
||||
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;
|
||||
|
||||
|
@ -51,6 +53,7 @@ void bench_setup(void* arg) {
|
|||
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) {
|
||||
|
@ -95,8 +98,8 @@ void bench_scalar_split(void* arg) {
|
|||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_scalar_t l, r;
|
||||
secp256k1_scalar_split_lambda_var(&l, &r, &data->scalar_x);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -178,12 +181,12 @@ void bench_field_inverse_var(void* arg) {
|
|||
}
|
||||
}
|
||||
|
||||
void bench_field_sqrt_var(void* arg) {
|
||||
void bench_field_sqrt(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_fe_sqrt_var(&data->fe_x, &data->fe_x);
|
||||
secp256k1_fe_sqrt(&data->fe_x, &data->fe_x);
|
||||
secp256k1_fe_add(&data->fe_x, &data->fe_y);
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +196,7 @@ void bench_group_double_var(void* arg) {
|
|||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
|
||||
for (i = 0; i < 200000; i++) {
|
||||
secp256k1_gej_double_var(&data->gej_x, &data->gej_x);
|
||||
secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,7 +205,7 @@ void bench_group_add_var(void* arg) {
|
|||
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);
|
||||
secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,7 +223,16 @@ void bench_group_add_affine_var(void* arg) {
|
|||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,7 +241,17 @@ void bench_ecmult_wnaf(void* arg) {
|
|||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_ecmult_wnaf(data->wnaf, &data->scalar_x, WINDOW_A);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -265,11 +287,42 @@ void bench_rfc6979_hmac_sha256(void* arg) {
|
|||
secp256k1_rfc6979_hmac_sha256_t rng;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 32, data->data, 32, NULL, 0);
|
||||
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;
|
||||
|
@ -278,7 +331,9 @@ int have_flag(int argc, char** argv, char *flag) {
|
|||
return 1;
|
||||
}
|
||||
while (argv != NULL && argv != argm) {
|
||||
if (strcmp(*argv, flag) == 0) return 1;
|
||||
if (strcmp(*argv, flag) == 0) {
|
||||
return 1;
|
||||
}
|
||||
argv++;
|
||||
}
|
||||
return 0;
|
||||
|
@ -302,17 +357,26 @@ int main(int argc, char **argv) {
|
|||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt_var", bench_field_sqrt_var, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000);
|
||||
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000);
|
||||
|
||||
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2014 Pieter Wuille *
|
||||
* 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_t *ctx;
|
||||
secp256k1_context *ctx;
|
||||
unsigned char msg[32];
|
||||
unsigned char sig[64];
|
||||
} bench_recover_t;
|
||||
|
@ -17,16 +18,20 @@ typedef struct {
|
|||
void bench_recover(void* arg) {
|
||||
int i;
|
||||
bench_recover_t *data = (bench_recover_t*)arg;
|
||||
unsigned char pubkey[33];
|
||||
secp256k1_pubkey pubkey;
|
||||
unsigned char pubkeyc[33];
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
int j;
|
||||
int pubkeylen = 33;
|
||||
CHECK(secp256k1_ecdsa_recover_compact(data->ctx, data->msg, data->sig, pubkey, &pubkeylen, 1, i % 2));
|
||||
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] = pubkey[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */
|
||||
data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,8 +40,12 @@ 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;
|
||||
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) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "bench.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context_t* ctx;
|
||||
secp256k1_context* ctx;
|
||||
unsigned char msg[32];
|
||||
unsigned char key[32];
|
||||
} bench_sign_t;
|
||||
|
@ -18,22 +18,28 @@ 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;
|
||||
for (i = 0; i < 32; i++) {
|
||||
data->msg[i] = i + 1;
|
||||
}
|
||||
for (i = 0; i < 32; i++) {
|
||||
data->key[i] = i + 65;
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_sign(void* arg) {
|
||||
int i;
|
||||
bench_sign_t *data = (bench_sign_t*)arg;
|
||||
|
||||
unsigned char sig[64];
|
||||
unsigned char sig[74];
|
||||
for (i = 0; i < 20000; i++) {
|
||||
size_t siglen = 74;
|
||||
int j;
|
||||
int recid = 0;
|
||||
CHECK(secp256k1_ecdsa_sign_compact(data->ctx, data->msg, sig, data->key, NULL, NULL, &recid));
|
||||
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]; /* Move former R to message. */
|
||||
data->key[j] = sig[j + 32]; /* Move former S to key. */
|
||||
data->msg[j] = sig[j];
|
||||
data->key[j] = sig[j + 32];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,14 +11,23 @@
|
|||
#include "util.h"
|
||||
#include "bench.h"
|
||||
|
||||
#ifdef ENABLE_OPENSSL_TESTS
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context_t *ctx;
|
||||
secp256k1_context *ctx;
|
||||
unsigned char msg[32];
|
||||
unsigned char key[32];
|
||||
unsigned char sig[72];
|
||||
int siglen;
|
||||
size_t siglen;
|
||||
unsigned char pubkey[33];
|
||||
int pubkeylen;
|
||||
size_t pubkeylen;
|
||||
#ifdef ENABLE_OPENSSL_TESTS
|
||||
EC_GROUP* ec_group;
|
||||
#endif
|
||||
} benchmark_verify_t;
|
||||
|
||||
static void benchmark_verify(void* arg) {
|
||||
|
@ -26,30 +35,77 @@ static void benchmark_verify(void* arg) {
|
|||
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_ecdsa_verify(data->ctx, data->msg, data->sig, data->siglen, data->pubkey, data->pubkeylen) == (i == 0));
|
||||
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;
|
||||
for (i = 0; i < 32; i++) {
|
||||
data.msg[i] = 1 + i;
|
||||
}
|
||||
for (i = 0; i < 32; i++) {
|
||||
data.key[i] = 33 + i;
|
||||
}
|
||||
data.siglen = 72;
|
||||
secp256k1_ecdsa_sign(data.ctx, data.msg, data.sig, &data.siglen, data.key, NULL, NULL);
|
||||
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_create(data.ctx, data.pubkey, &data.pubkeylen, data.key, 1));
|
||||
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;
|
||||
|
|
|
@ -7,18 +7,15 @@
|
|||
#ifndef _SECP256K1_ECDSA_
|
||||
#define _SECP256K1_ECDSA_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
#include "ecmult.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_scalar_t r, s;
|
||||
} secp256k1_ecdsa_sig_t;
|
||||
|
||||
static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size);
|
||||
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a);
|
||||
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message);
|
||||
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid);
|
||||
static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid);
|
||||
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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* 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.*
|
||||
**********************************************************************/
|
||||
|
@ -28,7 +28,7 @@
|
|||
* sage: '%x' % (EllipticCurve ([F (a), F (b)]).order())
|
||||
* 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141'
|
||||
*/
|
||||
static const secp256k1_fe_t secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST(
|
||||
static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST(
|
||||
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL,
|
||||
0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL
|
||||
);
|
||||
|
@ -42,82 +42,150 @@ static const secp256k1_fe_t secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CON
|
|||
* sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order())
|
||||
* '14551231950b75fc4402da1722fc9baee'
|
||||
*/
|
||||
static const secp256k1_fe_t secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST(
|
||||
static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST(
|
||||
0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL
|
||||
);
|
||||
|
||||
static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) {
|
||||
unsigned char ra[32] = {0}, sa[32] = {0};
|
||||
const unsigned char *rp;
|
||||
const unsigned char *sp;
|
||||
int lenr;
|
||||
int lens;
|
||||
int overflow;
|
||||
if (sig[0] != 0x30) {
|
||||
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) {
|
||||
if ((ret >> ((sizeof(size_t) - 1) * 8)) != 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;
|
||||
}
|
||||
lenr = sig[3];
|
||||
if (5+lenr >= size) {
|
||||
(*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;
|
||||
}
|
||||
lens = sig[lenr+5];
|
||||
if (sig[1] != lenr+lens+4) {
|
||||
if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) {
|
||||
/* Excessive 0x00 padding. */
|
||||
return 0;
|
||||
}
|
||||
if (lenr+lens+6 > size) {
|
||||
if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) {
|
||||
/* Excessive 0xFF padding. */
|
||||
return 0;
|
||||
}
|
||||
if (sig[2] != 0x02) {
|
||||
return 0;
|
||||
if ((**sig & 0x80) == 0x80) {
|
||||
/* Negative. */
|
||||
overflow = 1;
|
||||
}
|
||||
if (lenr == 0) {
|
||||
return 0;
|
||||
while (rlen > 0 && **sig == 0) {
|
||||
/* Skip leading zero bytes */
|
||||
rlen--;
|
||||
(*sig)++;
|
||||
}
|
||||
if (sig[lenr+4] != 0x02) {
|
||||
return 0;
|
||||
if (rlen > 32) {
|
||||
overflow = 1;
|
||||
}
|
||||
if (lens == 0) {
|
||||
return 0;
|
||||
if (!overflow) {
|
||||
memcpy(ra + 32 - rlen, *sig, rlen);
|
||||
secp256k1_scalar_set_b32(r, ra, &overflow);
|
||||
}
|
||||
sp = sig + 6 + lenr;
|
||||
while (lens > 0 && sp[0] == 0) {
|
||||
lens--;
|
||||
sp++;
|
||||
}
|
||||
if (lens > 32) {
|
||||
return 0;
|
||||
}
|
||||
rp = sig + 4;
|
||||
while (lenr > 0 && rp[0] == 0) {
|
||||
lenr--;
|
||||
rp++;
|
||||
}
|
||||
if (lenr > 32) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(ra + 32 - lenr, rp, lenr);
|
||||
memcpy(sa + 32 - lens, sp, lens);
|
||||
overflow = 0;
|
||||
secp256k1_scalar_set_b32(&r->r, ra, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&r->s, sa, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
secp256k1_scalar_set_int(r, 0);
|
||||
}
|
||||
(*sig) += rlen;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) {
|
||||
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;
|
||||
int lenR = 33, lenS = 33;
|
||||
secp256k1_scalar_get_b32(&r[1], &a->r);
|
||||
secp256k1_scalar_get_b32(&s[1], &a->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;
|
||||
|
@ -132,26 +200,41 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) {
|
||||
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_t sn, u1, u2;
|
||||
secp256k1_fe_t xr;
|
||||
secp256k1_gej_t pubkeyj;
|
||||
secp256k1_gej_t pr;
|
||||
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(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) {
|
||||
if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_scalar_inverse_var(&sn, &sig->s);
|
||||
secp256k1_scalar_inverse_var(&sn, sigs);
|
||||
secp256k1_scalar_mul(&u1, &sn, message);
|
||||
secp256k1_scalar_mul(&u2, &sn, &sig->r);
|
||||
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;
|
||||
}
|
||||
secp256k1_scalar_get_b32(c, &sig->r);
|
||||
|
||||
#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)
|
||||
|
@ -171,11 +254,11 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, con
|
|||
* secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test.
|
||||
*/
|
||||
if (secp256k1_gej_eq_x_var(&xr, &pr)) {
|
||||
/* xr.x == xr * xr.z^2 mod p, so the signature is valid. */
|
||||
/* 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 + p >= n, so we can skip testing the second case. */
|
||||
/* xr + n >= p, so we can skip testing the second case. */
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe);
|
||||
|
@ -184,46 +267,14 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, con
|
|||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) {
|
||||
unsigned char brx[32];
|
||||
secp256k1_fe_t fx;
|
||||
secp256k1_ge_t x;
|
||||
secp256k1_gej_t xj;
|
||||
secp256k1_scalar_t rn, u1, u2;
|
||||
secp256k1_gej_t qj;
|
||||
|
||||
if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_scalar_get_b32(brx, &sig->r);
|
||||
VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */
|
||||
if (recid & 2) {
|
||||
if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe);
|
||||
}
|
||||
if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&xj, &x);
|
||||
secp256k1_scalar_inverse_var(&rn, &sig->r);
|
||||
secp256k1_scalar_mul(&u1, &rn, message);
|
||||
secp256k1_scalar_negate(&u1, &u1);
|
||||
secp256k1_scalar_mul(&u2, &rn, &sig->s);
|
||||
secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1);
|
||||
secp256k1_ge_set_gej_var(pubkey, &qj);
|
||||
return !secp256k1_gej_is_infinity(&qj);
|
||||
}
|
||||
|
||||
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) {
|
||||
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_t rp;
|
||||
secp256k1_ge_t r;
|
||||
secp256k1_scalar_t n;
|
||||
secp256k1_gej rp;
|
||||
secp256k1_ge r;
|
||||
secp256k1_scalar n;
|
||||
int overflow = 0;
|
||||
|
||||
secp256k1_ecmult_gen(ctx, &rp, nonce);
|
||||
|
@ -231,28 +282,29 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, s
|
|||
secp256k1_fe_normalize(&r.x);
|
||||
secp256k1_fe_normalize(&r.y);
|
||||
secp256k1_fe_get_b32(b, &r.x);
|
||||
secp256k1_scalar_set_b32(&sig->r, b, &overflow);
|
||||
if (secp256k1_scalar_is_zero(&sig->r)) {
|
||||
/* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. */
|
||||
secp256k1_gej_clear(&rp);
|
||||
secp256k1_ge_clear(&r);
|
||||
return 0;
|
||||
}
|
||||
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, &sig->r, seckey);
|
||||
secp256k1_scalar_mul(&n, sigr, seckey);
|
||||
secp256k1_scalar_add(&n, &n, message);
|
||||
secp256k1_scalar_inverse(&sig->s, nonce);
|
||||
secp256k1_scalar_mul(&sig->s, &sig->s, &n);
|
||||
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(&sig->s)) {
|
||||
if (secp256k1_scalar_is_zero(sigs)) {
|
||||
return 0;
|
||||
}
|
||||
if (secp256k1_scalar_is_high(&sig->s)) {
|
||||
secp256k1_scalar_negate(&sig->s, &sig->s);
|
||||
if (secp256k1_scalar_is_high(sigs)) {
|
||||
secp256k1_scalar_negate(sigs, sigs);
|
||||
if (recid) {
|
||||
*recid ^= 1;
|
||||
}
|
||||
|
|
|
@ -7,20 +7,19 @@
|
|||
#ifndef _SECP256K1_ECKEY_
|
||||
#define _SECP256K1_ECKEY_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
#include "ecmult.h"
|
||||
#include "ecmult_gen.h"
|
||||
|
||||
static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size);
|
||||
static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed);
|
||||
static int secp256k1_eckey_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_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen);
|
||||
static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed);
|
||||
|
||||
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak);
|
||||
static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak);
|
||||
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak);
|
||||
static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak);
|
||||
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
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
#include "group.h"
|
||||
#include "ecmult_gen.h"
|
||||
|
||||
static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size) {
|
||||
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
|
||||
if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
|
||||
secp256k1_fe_t x;
|
||||
secp256k1_fe x;
|
||||
return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03);
|
||||
} else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
|
||||
secp256k1_fe_t x, y;
|
||||
secp256k1_fe x, y;
|
||||
if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned cha
|
|||
}
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed) {
|
||||
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;
|
||||
}
|
||||
|
@ -51,110 +51,7 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen) {
|
||||
unsigned char c[32] = {0};
|
||||
const unsigned char *end = privkey + privkeylen;
|
||||
int lenb = 0;
|
||||
int len = 0;
|
||||
int overflow = 0;
|
||||
/* 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(c + 32 - privkey[1], privkey + 2, privkey[1]);
|
||||
secp256k1_scalar_set_b32(key, c, &overflow);
|
||||
memset(c, 0, 32);
|
||||
return !overflow;
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed) {
|
||||
secp256k1_gej_t rp;
|
||||
secp256k1_ge_t r;
|
||||
int pubkeylen = 0;
|
||||
secp256k1_ecmult_gen(ctx, &rp, key);
|
||||
secp256k1_ge_set_gej(&r, &rp);
|
||||
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);
|
||||
secp256k1_scalar_get_b32(ptr, key); ptr += 32;
|
||||
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
|
||||
if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 1)) {
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
secp256k1_scalar_get_b32(ptr, key); ptr += 32;
|
||||
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
|
||||
if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 0)) {
|
||||
return 0;
|
||||
}
|
||||
ptr += pubkeylen;
|
||||
*privkeylen = ptr - privkey;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) {
|
||||
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;
|
||||
|
@ -162,9 +59,9 @@ static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) {
|
||||
secp256k1_gej_t pt;
|
||||
secp256k1_scalar_t one;
|
||||
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);
|
||||
|
@ -176,7 +73,7 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ct
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) {
|
||||
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
|
||||
if (secp256k1_scalar_is_zero(tweak)) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -185,9 +82,9 @@ static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) {
|
||||
secp256k1_scalar_t zero;
|
||||
secp256k1_gej_t pt;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -12,20 +12,20 @@
|
|||
|
||||
typedef struct {
|
||||
/* For accelerating the computation of a*P + b*G: */
|
||||
secp256k1_ge_storage_t (*pre_g)[]; /* odd multiples of the generator */
|
||||
secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
secp256k1_ge_storage_t (*pre_g_128)[]; /* odd multiples of 2^128*generator */
|
||||
secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */
|
||||
#endif
|
||||
} secp256k1_ecmult_context_t;
|
||||
} secp256k1_ecmult_context;
|
||||
|
||||
static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx);
|
||||
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx);
|
||||
static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst,
|
||||
const secp256k1_ecmult_context_t *src);
|
||||
static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx);
|
||||
static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx);
|
||||
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_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng);
|
||||
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
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/**********************************************************************
|
||||
* 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_
|
||||
#define _SECP256K1_ECMULT_CONST_
|
||||
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,239 @@
|
|||
/**********************************************************************
|
||||
* 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_
|
||||
#define _SECP256K1_ECMULT_CONST_IMPL_
|
||||
|
||||
#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..return_val)
|
||||
* with 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 returned; this is always (WNAF_BITS + w - 1) / w
|
||||
*
|
||||
* 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
|
|
@ -23,21 +23,21 @@ typedef struct {
|
|||
* None of the resulting prec group elements have a known scalar, and neither do any of
|
||||
* the intermediate sums while computing a*G.
|
||||
*/
|
||||
secp256k1_ge_storage_t (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */
|
||||
secp256k1_scalar_t blind;
|
||||
secp256k1_gej_t initial;
|
||||
} secp256k1_ecmult_gen_context_t;
|
||||
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_t* ctx);
|
||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t* ctx);
|
||||
static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst,
|
||||
const secp256k1_ecmult_gen_context_t* src);
|
||||
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t* ctx);
|
||||
static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx);
|
||||
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_t* ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *a);
|
||||
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_t *ctx, const unsigned char *seed32);
|
||||
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,22 +11,26 @@
|
|||
#include "group.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "hash_impl.h"
|
||||
|
||||
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t *ctx) {
|
||||
#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_t *ctx) {
|
||||
secp256k1_ge_t prec[1024];
|
||||
secp256k1_gej_t gj;
|
||||
secp256k1_gej_t nums_gej;
|
||||
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;
|
||||
}
|
||||
|
||||
ctx->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*ctx->prec));
|
||||
#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);
|
||||
|
@ -34,77 +38,93 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *c
|
|||
/* Construct a group element with no known corresponding scalar (nothing up my sleeve). */
|
||||
{
|
||||
static const unsigned char nums_b32[33] = "The scalar for this x is unknown";
|
||||
secp256k1_fe_t nums_x;
|
||||
secp256k1_ge_t nums_ge;
|
||||
VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32));
|
||||
VERIFY_CHECK(secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0));
|
||||
secp256k1_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);
|
||||
secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL);
|
||||
}
|
||||
|
||||
/* compute prec. */
|
||||
{
|
||||
secp256k1_gej_t precj[1024]; /* Jacobian versions of prec. */
|
||||
secp256k1_gej_t gbase;
|
||||
secp256k1_gej_t numsbase;
|
||||
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);
|
||||
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);
|
||||
secp256k1_gej_double_var(&gbase, &gbase, NULL);
|
||||
}
|
||||
/* Multiply numbase by 2. */
|
||||
secp256k1_gej_double_var(&numsbase, &numsbase);
|
||||
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);
|
||||
secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);
|
||||
}
|
||||
}
|
||||
secp256k1_ge_set_all_gej_var(1024, prec, precj);
|
||||
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_t* ctx) {
|
||||
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_t *dst,
|
||||
const secp256k1_ecmult_gen_context_t *src) {
|
||||
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 {
|
||||
dst->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*dst->prec));
|
||||
#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_t *ctx) {
|
||||
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_t *ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *gn) {
|
||||
secp256k1_ge_t add;
|
||||
secp256k1_ge_storage_t adds;
|
||||
secp256k1_scalar_t gnb;
|
||||
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));
|
||||
|
@ -136,14 +156,15 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t *ctx, secp
|
|||
}
|
||||
|
||||
/* Setup blinding values for secp256k1_ecmult_gen. */
|
||||
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32) {
|
||||
secp256k1_scalar_t b;
|
||||
secp256k1_gej_t gb;
|
||||
secp256k1_fe_t s;
|
||||
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;
|
||||
if (!seed32) {
|
||||
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);
|
||||
|
@ -155,13 +176,18 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons
|
|||
* 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.
|
||||
*/
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed32 ? seed32 : nonce32, 32, nonce32, 32, NULL, 0);
|
||||
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);
|
||||
} 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);
|
||||
|
@ -170,7 +196,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons
|
|||
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);
|
||||
} 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);
|
||||
|
|
|
@ -7,13 +7,29 @@
|
|||
#ifndef _SECP256K1_ECMULT_IMPL_H_
|
||||
#define _SECP256K1_ECMULT_IMPL_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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
|
||||
|
@ -23,63 +39,109 @@
|
|||
/** One table for window size 16: 1.375 MiB. */
|
||||
#define WINDOW_G 16
|
||||
#endif
|
||||
|
||||
/** Fill a table 'pre' with precomputed odd multiples of a. W determines the size of the table.
|
||||
* pre will contains the values [1*a,3*a,5*a,...,(2^(w-1)-1)*a], so it needs place for
|
||||
* 2^(w-2) entries.
|
||||
*
|
||||
* There are two versions of this function:
|
||||
* - secp256k1_ecmult_precomp_wnaf_gej, which operates on group elements in jacobian notation,
|
||||
* fast to precompute, but slower to use in later additions.
|
||||
* - secp256k1_ecmult_precomp_wnaf_ge, which operates on group elements in affine notations,
|
||||
* (much) slower to precompute, but a bit faster to use in later additions.
|
||||
* To compute a*P + b*G, we use the jacobian version for P, and the affine version for G, as
|
||||
* G is constant, so it only needs to be done once in advance.
|
||||
*/
|
||||
static void secp256k1_ecmult_table_precomp_gej_var(secp256k1_gej_t *pre, const secp256k1_gej_t *a, int w) {
|
||||
secp256k1_gej_t d;
|
||||
int i;
|
||||
pre[0] = *a;
|
||||
secp256k1_gej_double_var(&d, &pre[0]);
|
||||
for (i = 1; i < (1 << (w-2)); i++) {
|
||||
secp256k1_gej_add_var(&pre[i], &d, &pre[i-1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult_table_precomp_ge_storage_var(secp256k1_ge_storage_t *pre, const secp256k1_gej_t *a, int w) {
|
||||
secp256k1_gej_t d;
|
||||
int i;
|
||||
const int table_size = 1 << (w-2);
|
||||
secp256k1_gej_t *prej = (secp256k1_gej_t *)checked_malloc(sizeof(secp256k1_gej_t) * table_size);
|
||||
secp256k1_ge_t *prea = (secp256k1_ge_t *)checked_malloc(sizeof(secp256k1_ge_t) * table_size);
|
||||
prej[0] = *a;
|
||||
secp256k1_gej_double_var(&d, a);
|
||||
for (i = 1; i < table_size; i++) {
|
||||
secp256k1_gej_add_var(&prej[i], &d, &prej[i-1]);
|
||||
}
|
||||
secp256k1_ge_set_all_gej_var(table_size, prea, prej);
|
||||
for (i = 0; i < table_size; i++) {
|
||||
secp256k1_ge_to_storage(&pre[i], &prea[i]);
|
||||
}
|
||||
free(prej);
|
||||
free(prea);
|
||||
}
|
||||
#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_GEJ(r,pre,n,w) do { \
|
||||
#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_gej_neg((r), &(pre)[(-(n)-1)/2]); \
|
||||
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)); \
|
||||
|
@ -92,15 +154,15 @@ static void secp256k1_ecmult_table_precomp_ge_storage_var(secp256k1_ge_storage_t
|
|||
} \
|
||||
} while(0)
|
||||
|
||||
static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx) {
|
||||
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_t *ctx) {
|
||||
secp256k1_gej_t gj;
|
||||
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) {
|
||||
secp256k1_gej gj;
|
||||
|
||||
if (ctx->pre_g != NULL) {
|
||||
return;
|
||||
|
@ -109,35 +171,35 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) {
|
|||
/* get the generator */
|
||||
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
|
||||
|
||||
ctx->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_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_table_precomp_ge_storage_var(*ctx->pre_g, &gj, WINDOW_G);
|
||||
secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb);
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
{
|
||||
secp256k1_gej_t g_128j;
|
||||
secp256k1_gej g_128j;
|
||||
int i;
|
||||
|
||||
ctx->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G));
|
||||
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);
|
||||
secp256k1_gej_double_var(&g_128j, &g_128j, NULL);
|
||||
}
|
||||
secp256k1_ecmult_table_precomp_ge_storage_var(*ctx->pre_g_128, &g_128j, WINDOW_G);
|
||||
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_t *dst,
|
||||
const secp256k1_ecmult_context_t *src) {
|
||||
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_t (*)[])checked_malloc(size);
|
||||
dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size);
|
||||
memcpy(dst->pre_g, src->pre_g, size);
|
||||
}
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
|
@ -145,17 +207,17 @@ static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst,
|
|||
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_t (*)[])checked_malloc(size);
|
||||
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_t *ctx) {
|
||||
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_t *ctx) {
|
||||
static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) {
|
||||
free(ctx->pre_g);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
free(ctx->pre_g_128);
|
||||
|
@ -168,54 +230,68 @@ static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx) {
|
|||
* - 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.
|
||||
* than the number of bits in the (absolute value) of the input.
|
||||
*/
|
||||
static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w) {
|
||||
secp256k1_scalar_t s = *a;
|
||||
int set_bits = 0;
|
||||
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 < 256) {
|
||||
while (bit < len) {
|
||||
int now;
|
||||
int word;
|
||||
if (secp256k1_scalar_get_bits(&s, bit, 1) == 0) {
|
||||
if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) {
|
||||
bit++;
|
||||
continue;
|
||||
}
|
||||
while (set_bits < bit) {
|
||||
wnaf[set_bits++] = 0;
|
||||
}
|
||||
|
||||
now = w;
|
||||
if (bit + now > 256) {
|
||||
now = 256 - bit;
|
||||
}
|
||||
word = secp256k1_scalar_get_bits_var(&s, bit, now);
|
||||
if (word & (1 << (w-1))) {
|
||||
secp256k1_scalar_add_bit(&s, bit + w);
|
||||
wnaf[set_bits++] = sign * (word - (1 << w));
|
||||
} else {
|
||||
wnaf[set_bits++] = sign * word;
|
||||
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;
|
||||
}
|
||||
return set_bits;
|
||||
#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_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng) {
|
||||
secp256k1_gej_t tmpj;
|
||||
secp256k1_gej_t pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
secp256k1_ge_t tmpa;
|
||||
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_gej_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
secp256k1_scalar_t na_1, na_lam;
|
||||
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
secp256k1_scalar na_1, na_lam;
|
||||
/* Splitted G factors. */
|
||||
secp256k1_scalar_t ng_1, ng_128;
|
||||
secp256k1_scalar ng_1, ng_128;
|
||||
int wnaf_na_1[130];
|
||||
int wnaf_na_lam[130];
|
||||
int bits_na_1;
|
||||
|
@ -227,7 +303,7 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge
|
|||
#else
|
||||
int wnaf_na[256];
|
||||
int bits_na;
|
||||
int wnaf_ng[257];
|
||||
int wnaf_ng[256];
|
||||
int bits_ng;
|
||||
#endif
|
||||
int i;
|
||||
|
@ -235,11 +311,11 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge
|
|||
|
||||
#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_var(&na_1, &na_lam, na);
|
||||
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, &na_1, WINDOW_A);
|
||||
bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A);
|
||||
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;
|
||||
|
@ -248,24 +324,33 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge
|
|||
}
|
||||
#else
|
||||
/* build wnaf representation for na. */
|
||||
bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A);
|
||||
bits_na = secp256k1_ecmult_wnaf(wnaf_na, 256, na, WINDOW_A);
|
||||
bits = bits_na;
|
||||
#endif
|
||||
|
||||
/* calculate odd multiples of a */
|
||||
secp256k1_ecmult_table_precomp_gej_var(pre_a, a, WINDOW_A);
|
||||
/* 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_gej_mul_lambda(&pre_a_lam[i], &pre_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, &ng_1, WINDOW_G);
|
||||
bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G);
|
||||
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;
|
||||
}
|
||||
|
@ -273,7 +358,7 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge
|
|||
bits = bits_ng_128;
|
||||
}
|
||||
#else
|
||||
bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G);
|
||||
bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G);
|
||||
if (bits_ng > bits) {
|
||||
bits = bits_ng;
|
||||
}
|
||||
|
@ -281,37 +366,41 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge
|
|||
|
||||
secp256k1_gej_set_infinity(r);
|
||||
|
||||
for (i = bits-1; i >= 0; i--) {
|
||||
for (i = bits - 1; i >= 0; i--) {
|
||||
int n;
|
||||
secp256k1_gej_double_var(r, r);
|
||||
secp256k1_gej_double_var(r, r, NULL);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
if (i < bits_na_1 && (n = wnaf_na_1[i])) {
|
||||
ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A);
|
||||
secp256k1_gej_add_var(r, r, &tmpj);
|
||||
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_GEJ(&tmpj, pre_a_lam, n, WINDOW_A);
|
||||
secp256k1_gej_add_var(r, r, &tmpj);
|
||||
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_ge_var(r, r, &tmpa);
|
||||
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_ge_var(r, r, &tmpa);
|
||||
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
|
||||
}
|
||||
#else
|
||||
if (i < bits_na && (n = wnaf_na[i])) {
|
||||
ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A);
|
||||
secp256k1_gej_add_var(r, r, &tmpj);
|
||||
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_ge_var(r, r, &tmpa);
|
||||
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!r->infinity) {
|
||||
secp256k1_fe_mul(&r->z, &r->z, &Z);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
/** Field element module.
|
||||
*
|
||||
* Field elements can be represented in several ways, but code accessing
|
||||
* it (and implementations) need to take certain properaties into account:
|
||||
* 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
|
||||
|
@ -30,90 +30,103 @@
|
|||
#error "Please select field implementation"
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
|
||||
/** Normalize a field element. */
|
||||
static void secp256k1_fe_normalize(secp256k1_fe_t *r);
|
||||
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_t *r);
|
||||
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_t *r);
|
||||
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_t *r);
|
||||
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_t *r);
|
||||
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_t *r, int a);
|
||||
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_t *a);
|
||||
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_t *a);
|
||||
static int secp256k1_fe_is_odd(const secp256k1_fe *a);
|
||||
|
||||
/** Compare two field elements. Requires magnitude-1 inputs. */
|
||||
static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b);
|
||||
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_t *a, const secp256k1_fe_t *b);
|
||||
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 succesful, the resulting field element is normalized. */
|
||||
static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a);
|
||||
/** 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_t *a);
|
||||
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_t *r, const secp256k1_fe_t *a, int m);
|
||||
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_t *r, int a);
|
||||
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_t *r, const secp256k1_fe_t *a);
|
||||
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_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b);
|
||||
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_t *r, const secp256k1_fe_t *a);
|
||||
static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
|
||||
/** Sets a field element to be the (modular) square root (if any exist) of another. Requires the
|
||||
* input's magnitude to be at most 8. The output magnitude is 1 (but not guaranteed to be
|
||||
* normalized). Return value indicates whether a square root was found. */
|
||||
static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a);
|
||||
/** 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_t *r, const secp256k1_fe_t *a);
|
||||
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_t *r, const secp256k1_fe_t *a);
|
||||
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(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a);
|
||||
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_t *r, const secp256k1_fe_t*);
|
||||
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_t *r, const secp256k1_fe_storage_t*);
|
||||
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_t *r, const secp256k1_fe_storage_t *a, int flag);
|
||||
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_t *r, const secp256k1_fe_t *a, int flag);
|
||||
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,20 +16,20 @@ typedef struct {
|
|||
int magnitude;
|
||||
int normalized;
|
||||
#endif
|
||||
} secp256k1_fe_t;
|
||||
} 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, \
|
||||
((d0) >> 26) | ((d1) & 0xFFFFFUL) << 6, \
|
||||
((d1) >> 20) | ((d2) & 0x3FFFUL) << 12, \
|
||||
((d2) >> 14) | ((d3) & 0xFFUL) << 18, \
|
||||
((d3) >> 8) | ((d4) & 0x3) << 24, \
|
||||
((d4) >> 2) & 0x3FFFFFFUL, \
|
||||
((d4) >> 28) | ((d5) & 0x3FFFFFUL) << 4, \
|
||||
((d5) >> 22) | ((d6) & 0xFFFF) << 10, \
|
||||
((d6) >> 16) | ((d7) & 0x3FF) << 16, \
|
||||
((d7) >> 10) \
|
||||
(((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
|
||||
|
@ -40,8 +40,8 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
uint32_t n[8];
|
||||
} secp256k1_fe_storage_t;
|
||||
} 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
|
||||
|
|
|
@ -7,14 +7,12 @@
|
|||
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
#define _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "util.h"
|
||||
#include "num.h"
|
||||
#include "field.h"
|
||||
|
||||
#ifdef VERIFY
|
||||
static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
|
||||
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);
|
||||
|
@ -40,13 +38,9 @@ static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
|
|||
}
|
||||
VERIFY_CHECK(r == 1);
|
||||
}
|
||||
#else
|
||||
static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
|
||||
(void)a;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void secp256k1_fe_normalize(secp256k1_fe_t *r) {
|
||||
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];
|
||||
|
||||
|
@ -101,7 +95,7 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) {
|
||||
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];
|
||||
|
||||
|
@ -132,7 +126,7 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) {
|
||||
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];
|
||||
|
||||
|
@ -188,7 +182,7 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) {
|
||||
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];
|
||||
|
||||
|
@ -217,7 +211,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) {
|
|||
return (z0 == 0) | (z1 == 0x3FFFFFFUL);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
|
||||
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;
|
||||
|
@ -252,7 +246,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
|
|||
t9 &= 0x03FFFFFUL;
|
||||
t1 += (x << 6);
|
||||
|
||||
t1 += (t0 >> 26); t0 = z0;
|
||||
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;
|
||||
|
@ -269,7 +263,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
|
|||
return (z0 == 0) | (z1 == 0x3FFFFFFUL);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
|
||||
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
|
||||
|
@ -279,7 +273,7 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
|
|||
#endif
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
|
||||
const uint32_t *t = a->n;
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
@ -288,7 +282,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
|
|||
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_t *a) {
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->normalized);
|
||||
secp256k1_fe_verify(a);
|
||||
|
@ -296,7 +290,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
|
|||
return a->n[0] & 1;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) {
|
||||
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
|
||||
int i;
|
||||
#ifdef VERIFY
|
||||
a->magnitude = 0;
|
||||
|
@ -307,7 +301,7 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) {
|
|||
}
|
||||
}
|
||||
|
||||
static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
|
||||
static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
int i;
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
@ -326,18 +320,18 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
|
||||
int i;
|
||||
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
|
||||
r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
|
||||
for (i=0; i<32; i++) {
|
||||
int j;
|
||||
for (j=0; j<4; j++) {
|
||||
int limb = (8*i+2*j)/26;
|
||||
int shift = (8*i+2*j)%26;
|
||||
r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -350,25 +344,46 @@ static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
|
|||
}
|
||||
|
||||
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
|
||||
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
|
||||
int i;
|
||||
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->normalized);
|
||||
secp256k1_fe_verify(a);
|
||||
#endif
|
||||
for (i=0; i<32; i++) {
|
||||
int j;
|
||||
int c = 0;
|
||||
for (j=0; j<4; j++) {
|
||||
int limb = (8*i+2*j)/26;
|
||||
int shift = (8*i+2*j)%26;
|
||||
c |= ((a->n[limb] >> shift) & 0x3) << (2 * j);
|
||||
}
|
||||
r[31-i] = c;
|
||||
}
|
||||
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_t *r, const secp256k1_fe_t *a, int m) {
|
||||
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);
|
||||
|
@ -390,7 +405,7 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp25
|
|||
#endif
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
|
||||
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;
|
||||
|
@ -408,7 +423,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
|
|||
#endif
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
#ifdef VERIFY
|
||||
secp256k1_fe_verify(a);
|
||||
#endif
|
||||
|
@ -429,6 +444,14 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(USE_EXTERNAL_ASM)
|
||||
|
||||
/* External assembler implementation */
|
||||
void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b);
|
||||
void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a);
|
||||
|
||||
#else
|
||||
|
||||
#ifdef VERIFY
|
||||
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
|
||||
#else
|
||||
|
@ -1037,9 +1060,9 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
|
|||
VERIFY_BITS(r[2], 27);
|
||||
/* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) {
|
||||
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);
|
||||
|
@ -1055,7 +1078,7 @@ static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const s
|
|||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->magnitude <= 8);
|
||||
secp256k1_fe_verify(a);
|
||||
|
@ -1068,7 +1091,7 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) {
|
||||
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;
|
||||
|
@ -1083,12 +1106,14 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k
|
|||
r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1);
|
||||
r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1);
|
||||
#ifdef VERIFY
|
||||
r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1);
|
||||
r->normalized = (r->normalized & mask0) | (a->normalized & mask1);
|
||||
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_t *r, const secp256k1_fe_storage_t *a, int flag) {
|
||||
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;
|
||||
|
@ -1102,7 +1127,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r
|
|||
r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) {
|
||||
static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->normalized);
|
||||
#endif
|
||||
|
@ -1116,7 +1141,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_f
|
|||
r->n[7] = a->n[8] >> 16 | a->n[9] << 10;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) {
|
||||
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);
|
||||
|
|
|
@ -16,15 +16,15 @@ typedef struct {
|
|||
int magnitude;
|
||||
int normalized;
|
||||
#endif
|
||||
} secp256k1_fe_t;
|
||||
} 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, \
|
||||
((d1) >> 20) | ((uint64_t)(d2)) << 12 | ((uint64_t)(d3) & 0xFFUL) << 44, \
|
||||
((d3) >> 8) | ((uint64_t)(d4) & 0xFFFFFFFUL) << 24, \
|
||||
((d4) >> 28) | ((uint64_t)(d5)) << 4 | ((uint64_t)(d6) & 0xFFFFUL) << 36, \
|
||||
((d6) >> 16) | ((uint64_t)(d7)) << 16 \
|
||||
(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
|
||||
|
@ -35,13 +35,13 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
uint64_t n[4];
|
||||
} secp256k1_fe_storage_t;
|
||||
} 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 \
|
||||
(d0) | (((uint64_t)(d1)) << 32), \
|
||||
(d2) | (((uint64_t)(d3)) << 32), \
|
||||
(d4) | (((uint64_t)(d5)) << 32), \
|
||||
(d6) | (((uint64_t)(d7)) << 32) \
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "libsecp256k1-config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include "util.h"
|
||||
#include "num.h"
|
||||
#include "field.h"
|
||||
|
@ -31,7 +30,7 @@
|
|||
*/
|
||||
|
||||
#ifdef VERIFY
|
||||
static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
|
||||
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. */
|
||||
|
@ -50,13 +49,9 @@ static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
|
|||
}
|
||||
VERIFY_CHECK(r == 1);
|
||||
}
|
||||
#else
|
||||
static void secp256k1_fe_verify(const secp256k1_fe_t *a) {
|
||||
(void)a;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void secp256k1_fe_normalize(secp256k1_fe_t *r) {
|
||||
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 */
|
||||
|
@ -99,7 +94,7 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) {
|
||||
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 */
|
||||
|
@ -123,7 +118,7 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) {
|
||||
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 */
|
||||
|
@ -167,7 +162,7 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) {
|
||||
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 */
|
||||
|
@ -190,7 +185,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) {
|
|||
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
|
||||
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;
|
||||
|
@ -219,7 +214,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
|
|||
|
||||
t4 &= 0x0FFFFFFFFFFFFULL;
|
||||
|
||||
t1 += (t0 >> 52); t0 = z0;
|
||||
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;
|
||||
|
@ -231,7 +226,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) {
|
|||
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
|
||||
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
|
||||
|
@ -241,7 +236,7 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) {
|
|||
#endif
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
|
||||
const uint64_t *t = a->n;
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
@ -250,7 +245,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) {
|
|||
return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->normalized);
|
||||
secp256k1_fe_verify(a);
|
||||
|
@ -258,7 +253,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) {
|
|||
return a->n[0] & 1;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) {
|
||||
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
|
||||
int i;
|
||||
#ifdef VERIFY
|
||||
a->magnitude = 0;
|
||||
|
@ -269,7 +264,7 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) {
|
|||
}
|
||||
}
|
||||
|
||||
static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
|
||||
static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
int i;
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
@ -288,17 +283,41 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
|
||||
int i;
|
||||
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
|
||||
for (i=0; i<32; i++) {
|
||||
int j;
|
||||
for (j=0; j<2; j++) {
|
||||
int limb = (8*i+4*j)/52;
|
||||
int shift = (8*i+4*j)%52;
|
||||
r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -311,25 +330,46 @@ static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) {
|
|||
}
|
||||
|
||||
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
|
||||
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) {
|
||||
int i;
|
||||
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->normalized);
|
||||
secp256k1_fe_verify(a);
|
||||
#endif
|
||||
for (i=0; i<32; i++) {
|
||||
int j;
|
||||
int c = 0;
|
||||
for (j=0; j<2; j++) {
|
||||
int limb = (8*i+4*j)/52;
|
||||
int shift = (8*i+4*j)%52;
|
||||
c |= ((a->n[limb] >> shift) & 0xF) << (4 * j);
|
||||
}
|
||||
r[31-i] = c;
|
||||
}
|
||||
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_t *r, const secp256k1_fe_t *a, int m) {
|
||||
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);
|
||||
|
@ -346,7 +386,7 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp25
|
|||
#endif
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
|
||||
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;
|
||||
|
@ -359,7 +399,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) {
|
|||
#endif
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
#ifdef VERIFY
|
||||
secp256k1_fe_verify(a);
|
||||
#endif
|
||||
|
@ -375,7 +415,7 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1
|
|||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) {
|
||||
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);
|
||||
|
@ -391,7 +431,7 @@ static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const s
|
|||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->magnitude <= 8);
|
||||
secp256k1_fe_verify(a);
|
||||
|
@ -404,7 +444,7 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) {
|
||||
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;
|
||||
|
@ -414,12 +454,14 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k
|
|||
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
|
||||
r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
|
||||
#ifdef VERIFY
|
||||
r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1);
|
||||
r->normalized = (r->normalized & mask0) | (a->normalized & mask1);
|
||||
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_t *r, const secp256k1_fe_storage_t *a, int flag) {
|
||||
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;
|
||||
|
@ -429,7 +471,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r
|
|||
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) {
|
||||
static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->normalized);
|
||||
#endif
|
||||
|
@ -439,7 +481,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_f
|
|||
r->n[3] = a->n[3] >> 36 | a->n[4] << 16;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) {
|
||||
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);
|
||||
|
|
|
@ -137,7 +137,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
|
|||
VERIFY_BITS(r[2], 52);
|
||||
VERIFY_BITS(c, 63);
|
||||
/* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
c += d * R + t3;;
|
||||
c += d * R + t3;
|
||||
VERIFY_BITS(c, 100);
|
||||
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
r[3] = c & M; c >>= 52;
|
||||
|
@ -259,7 +259,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
|
|||
VERIFY_BITS(c, 63);
|
||||
/* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
|
||||
c += d * R + t3;;
|
||||
c += d * R + t3;
|
||||
VERIFY_BITS(c, 100);
|
||||
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
r[3] = c & M; c >>= 52;
|
||||
|
|
|
@ -21,15 +21,31 @@
|
|||
#error "Please select field implementation"
|
||||
#endif
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
|
||||
secp256k1_fe_t na;
|
||||
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_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
secp256k1_fe_t x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
|
||||
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
|
||||
|
@ -114,11 +130,11 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
|||
/* Check that a square root was actually calculated */
|
||||
|
||||
secp256k1_fe_sqr(&t1, r);
|
||||
return secp256k1_fe_equal_var(&t1, a);
|
||||
return secp256k1_fe_equal(&t1, a);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
secp256k1_fe_t x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
|
||||
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
|
||||
|
@ -207,11 +223,15 @@ static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
|||
secp256k1_fe_mul(r, a, &t1);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
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_t n, m;
|
||||
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,
|
||||
|
@ -220,21 +240,28 @@ static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
|||
0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
|
||||
};
|
||||
unsigned char b[32];
|
||||
secp256k1_fe_t c = *a;
|
||||
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);
|
||||
VERIFY_CHECK(secp256k1_fe_set_b32(r, b));
|
||||
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(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a) {
|
||||
secp256k1_fe_t u;
|
||||
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;
|
||||
|
@ -252,7 +279,7 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp25
|
|||
secp256k1_fe_inv_var(&u, &r[--i]);
|
||||
|
||||
while (i > 0) {
|
||||
int j = i--;
|
||||
size_t j = i--;
|
||||
secp256k1_fe_mul(&r[j], &r[i], &u);
|
||||
secp256k1_fe_mul(&u, &u, &a[j]);
|
||||
}
|
||||
|
@ -260,4 +287,29 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp25
|
|||
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
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/**********************************************************************
|
||||
* 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;
|
||||
}
|
|
@ -12,110 +12,133 @@
|
|||
|
||||
/** A group element of the secp256k1 curve, in affine coordinates. */
|
||||
typedef struct {
|
||||
secp256k1_fe_t x;
|
||||
secp256k1_fe_t y;
|
||||
secp256k1_fe x;
|
||||
secp256k1_fe y;
|
||||
int infinity; /* whether this represents the point at infinity */
|
||||
} secp256k1_ge_t;
|
||||
} 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_t x; /* actual X: x/z^2 */
|
||||
secp256k1_fe_t y; /* actual Y: y/z^3 */
|
||||
secp256k1_fe_t z;
|
||||
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_t;
|
||||
} 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_t x;
|
||||
secp256k1_fe_storage_t y;
|
||||
} secp256k1_ge_storage_t;
|
||||
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))}
|
||||
|
||||
/** Set a group element equal to the point at infinity */
|
||||
static void secp256k1_ge_set_infinity(secp256k1_ge_t *r);
|
||||
#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_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y);
|
||||
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_t *r, const secp256k1_fe_t *x, int odd);
|
||||
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_t *a);
|
||||
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_t *a);
|
||||
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a);
|
||||
|
||||
static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *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_t *r, secp256k1_gej_t *a);
|
||||
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(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a);
|
||||
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_t *r);
|
||||
|
||||
/** Set a group element (jacobian) equal to the point with given X and Y coordinates. */
|
||||
static void secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y);
|
||||
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_t *r, const secp256k1_ge_t *a);
|
||||
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_t *x, const secp256k1_gej_t *a);
|
||||
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_t *r, const secp256k1_gej_t *a);
|
||||
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_t *a);
|
||||
static int secp256k1_gej_is_infinity(const secp256k1_gej *a);
|
||||
|
||||
/** Set r equal to the double of a. */
|
||||
static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *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 sum of a and b. */
|
||||
static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b);
|
||||
/** 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_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b);
|
||||
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. */
|
||||
static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b);
|
||||
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_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a);
|
||||
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a);
|
||||
#endif
|
||||
|
||||
/** Clear a secp256k1_gej_t to prevent leaking sensitive information. */
|
||||
static void secp256k1_gej_clear(secp256k1_gej_t *r);
|
||||
/** Clear a secp256k1_gej to prevent leaking sensitive information. */
|
||||
static void secp256k1_gej_clear(secp256k1_gej *r);
|
||||
|
||||
/** Clear a secp256k1_ge_t to prevent leaking sensitive information. */
|
||||
static void secp256k1_ge_clear(secp256k1_ge_t *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_t *r, const secp256k1_ge_t*);
|
||||
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_t *r, const secp256k1_ge_storage_t*);
|
||||
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_t *r, const secp256k1_ge_storage_t *a, int flag);
|
||||
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_t *r, const secp256k1_fe_t *b);
|
||||
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,44 +7,98 @@
|
|||
#ifndef _SECP256K1_GROUP_IMPL_H_
|
||||
#define _SECP256K1_GROUP_IMPL_H_
|
||||
|
||||
#include <string.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_t secp256k1_ge_const_g = SECP256K1_GE_CONST(
|
||||
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
|
||||
);
|
||||
|
||||
static void secp256k1_ge_set_infinity(secp256k1_ge_t *r) {
|
||||
r->infinity = 1;
|
||||
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_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) {
|
||||
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_t *a) {
|
||||
static int secp256k1_ge_is_infinity(const secp256k1_ge *a) {
|
||||
return a->infinity;
|
||||
}
|
||||
|
||||
static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a) {
|
||||
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_t *r, secp256k1_gej_t *a) {
|
||||
secp256k1_fe_t z2, z3;
|
||||
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);
|
||||
|
@ -56,8 +110,8 @@ static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) {
|
|||
r->y = a->y;
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) {
|
||||
secp256k1_fe_t z2, z3;
|
||||
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;
|
||||
|
@ -72,73 +126,106 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) {
|
|||
r->y = a->y;
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a) {
|
||||
secp256k1_fe_t *az;
|
||||
secp256k1_fe_t *azi;
|
||||
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_t *)checked_malloc(sizeof(secp256k1_fe_t) * len);
|
||||
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_t *)checked_malloc(sizeof(secp256k1_fe_t) * count);
|
||||
secp256k1_fe_inv_all_var(count, azi, az);
|
||||
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_fe_t zi2, zi3;
|
||||
secp256k1_fe_t *zi = &azi[count++];
|
||||
secp256k1_fe_sqr(&zi2, zi);
|
||||
secp256k1_fe_mul(&zi3, &zi2, zi);
|
||||
secp256k1_fe_mul(&r[i].x, &a[i].x, &zi2);
|
||||
secp256k1_fe_mul(&r[i].y, &a[i].y, &zi3);
|
||||
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]);
|
||||
}
|
||||
}
|
||||
free(azi);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_set_infinity(secp256k1_gej_t *r) {
|
||||
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_set_int(&r->x, 0);
|
||||
secp256k1_fe_set_int(&r->y, 0);
|
||||
secp256k1_fe_set_int(&r->z, 0);
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
secp256k1_fe_clear(&r->z);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) {
|
||||
r->infinity = 0;
|
||||
r->x = *x;
|
||||
r->y = *y;
|
||||
secp256k1_fe_set_int(&r->z, 1);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_clear(secp256k1_gej_t *r) {
|
||||
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_t *r) {
|
||||
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_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd) {
|
||||
secp256k1_fe_t x2, x3, c;
|
||||
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, 7);
|
||||
secp256k1_fe_set_int(&c, CURVE_B);
|
||||
secp256k1_fe_add(&c, &x3);
|
||||
if (!secp256k1_fe_sqrt_var(&r->y, &c)) {
|
||||
return secp256k1_fe_sqrt(&r->y, &c);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
|
||||
if (!secp256k1_ge_set_xquad(r, x)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_normalize_var(&r->y);
|
||||
|
@ -146,24 +233,25 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, i
|
|||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a) {
|
||||
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_t *x, const secp256k1_gej_t *a) {
|
||||
secp256k1_fe_t r, r2;
|
||||
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_t *r, const secp256k1_gej_t *a) {
|
||||
static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) {
|
||||
r->infinity = a->infinity;
|
||||
r->x = a->x;
|
||||
r->y = a->y;
|
||||
|
@ -172,12 +260,12 @@ static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
|
|||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
}
|
||||
|
||||
static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a) {
|
||||
static int secp256k1_gej_is_infinity(const secp256k1_gej *a) {
|
||||
return a->infinity;
|
||||
}
|
||||
|
||||
static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) {
|
||||
secp256k1_fe_t y2, x3, z2, z6;
|
||||
static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) {
|
||||
secp256k1_fe y2, x3, z2, z6;
|
||||
if (a->infinity) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -190,38 +278,59 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) {
|
|||
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, 7);
|
||||
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_t *a) {
|
||||
secp256k1_fe_t y2, x3, c;
|
||||
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, 7);
|
||||
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_t *r, const secp256k1_gej_t *a) {
|
||||
/* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate */
|
||||
secp256k1_fe_t t1,t2,t3,t4;
|
||||
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);
|
||||
|
@ -244,17 +353,29 @@ static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *
|
|||
secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */
|
||||
}
|
||||
|
||||
static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
|
||||
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_t z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
|
||||
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);
|
||||
|
@ -266,8 +387,11 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a,
|
|||
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);
|
||||
secp256k1_gej_double_var(r, a, rzr);
|
||||
} else {
|
||||
if (rzr != NULL) {
|
||||
secp256k1_fe_set_int(rzr, 0);
|
||||
}
|
||||
r->infinity = 1;
|
||||
}
|
||||
return;
|
||||
|
@ -275,7 +399,11 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a,
|
|||
secp256k1_fe_sqr(&i2, &i);
|
||||
secp256k1_fe_sqr(&h2, &h);
|
||||
secp256k1_fe_mul(&h3, &h, &h2);
|
||||
secp256k1_fe_mul(&r->z, &a->z, &b->z); secp256k1_fe_mul(&r->z, &r->z, &h);
|
||||
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);
|
||||
|
@ -283,21 +411,23 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a,
|
|||
secp256k1_fe_add(&r->y, &h3);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) {
|
||||
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_t z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
|
||||
secp256k1_fe z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
|
||||
if (a->infinity) {
|
||||
r->infinity = b->infinity;
|
||||
r->x = b->x;
|
||||
r->y = b->y;
|
||||
secp256k1_fe_set_int(&r->z, 1);
|
||||
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);
|
||||
|
@ -307,7 +437,69 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *
|
|||
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);
|
||||
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;
|
||||
}
|
||||
|
@ -324,11 +516,13 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *
|
|||
secp256k1_fe_add(&r->y, &h3);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) {
|
||||
/* Operations: 7 mul, 5 sqr, 5 normalize, 17 mul_int/add/negate/cmov */
|
||||
static const secp256k1_fe_t fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
|
||||
secp256k1_fe_t zz, u1, u2, s1, s2, z, t, m, n, q, rr;
|
||||
int infinity;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -352,53 +546,102 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c
|
|||
* 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*Z2^2 (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) */
|
||||
z = a->z; /* z = Z = Z1*Z2 (8) */
|
||||
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(&n, &m); /* n = M^2 (1) */
|
||||
secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*M^2 (1) */
|
||||
secp256k1_fe_sqr(&n, &n); /* n = M^4 (1) */
|
||||
secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */
|
||||
secp256k1_fe_mul(&t, &u1, &u2); secp256k1_fe_negate(&t, &t, 1); /* t = -U1*U2 (2) */
|
||||
secp256k1_fe_add(&rr, &t); /* rr = R = T^2-U1*U2 (3) */
|
||||
secp256k1_fe_sqr(&t, &rr); /* t = R^2 (1) */
|
||||
secp256k1_fe_mul(&r->z, &m, &z); /* r->z = M*Z (1) */
|
||||
infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity);
|
||||
secp256k1_fe_mul_int(&r->z, 2 * (1 - a->infinity)); /* r->z = Z3 = 2*M*Z (2) */
|
||||
r->x = t; /* r->x = R^2 (1) */
|
||||
secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */
|
||||
secp256k1_fe_add(&r->x, &q); /* r->x = R^2-Q (3) */
|
||||
secp256k1_fe_normalize(&r->x);
|
||||
secp256k1_fe_mul_int(&q, 3); /* q = -3*Q (6) */
|
||||
secp256k1_fe_mul_int(&t, 2); /* t = 2*R^2 (2) */
|
||||
secp256k1_fe_add(&t, &q); /* t = 2*R^2-3*Q (8) */
|
||||
secp256k1_fe_mul(&t, &t, &rr); /* t = R*(2*R^2-3*Q) (1) */
|
||||
secp256k1_fe_add(&t, &n); /* t = R*(2*R^2-3*Q)+M^4 (2) */
|
||||
secp256k1_fe_negate(&r->y, &t, 2); /* r->y = R*(3*Q-2*R^2)-M^4 (3) */
|
||||
secp256k1_fe_normalize_weak(&r->y);
|
||||
secp256k1_fe_mul_int(&r->x, 4 * (1 - a->infinity)); /* r->x = X3 = 4*(R^2-Q) */
|
||||
secp256k1_fe_mul_int(&r->y, 4 * (1 - a->infinity)); /* r->y = Y3 = 4*R*(3*Q-2*R^2)-4*M^4 (4) */
|
||||
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 */
|
||||
|
||||
/** In case a->infinity == 1, the above code results in r->x, r->y, and r->z all equal to 0.
|
||||
* Replace r with b->x, b->y, 1 in that case.
|
||||
*/
|
||||
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_t *r, const secp256k1_fe_t *s) {
|
||||
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {
|
||||
/* Operations: 4 mul, 1 sqr */
|
||||
secp256k1_fe_t zz;
|
||||
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 */
|
||||
|
@ -407,8 +650,8 @@ static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *s) {
|
|||
secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */
|
||||
}
|
||||
|
||||
static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t *a) {
|
||||
secp256k1_fe_t x, y;
|
||||
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);
|
||||
|
@ -418,20 +661,20 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_g
|
|||
secp256k1_fe_to_storage(&r->y, &y);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_storage_t *a) {
|
||||
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_t *r, const secp256k1_ge_storage_t *a, int flag) {
|
||||
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_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a) {
|
||||
static const secp256k1_fe_t beta = SECP256K1_FE_CONST(
|
||||
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
|
||||
);
|
||||
|
@ -440,4 +683,18 @@ static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *
|
|||
}
|
||||
#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
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue