Browse Source
7a49cac Merge #410: Add string.h include to ecmult_impl 0bbd5d4 Add string.h include to ecmult_impl c5b32e1 Merge #405: Make secp256k1_fe_sqrt constant time 926836a Make secp256k1_fe_sqrt constant time e2a8e92 Merge #404: Replace 3M + 4S doubling formula with 2M + 5S one 8ec49d8 Add note about 2M + 5S doubling formula 5a91bd7 Merge #400: A couple minor cleanups ac01378 build: add -DSECP256K1_BUILD to benchmark_internal build flags a6c6f99 Remove a bunch of unused stdlib #includes 65285a6 Merge #403: configure: add flag to disable OpenSSL tests a9b2a5d configure: add flag to disable OpenSSL tests b340123 Merge #402: Add support for testing quadratic residues e6e9805 Add function for testing quadratic residue field/group elements. efd953a Add Jacobi symbol test via GMP fa36a0d Merge #401: ecmult_const: unify endomorphism and non-endomorphism skew cases c6191fd ecmult_const: unify endomorphism and non-endomorphism skew cases 0b3e618 Merge #378: .gitignore build-aux cleanup 6042217 Merge #384: JNI: align shared files copyright/comments to bitcoinj's 24ad20f Merge #399: build: verify that the native compiler works for static precomp b3be852 Merge #398: Test whether ECDH and Schnorr are enabled for JNI aa0b1fd build: verify that the native compiler works for static precomp eee808d Test whether ECDH and Schnorr are enabled for JNI 7b0fb18 Merge #366: ARM assembly implementation of field_10x26 inner (rebase of #173) 001f176 ARM assembly implementation of field_10x26 inner 0172be9 Merge #397: Small fixes for sha256 3f8b78e Fix undefs in hash_impl.h 2ab4695 Fix state size in sha256 struct 6875b01 Merge #386: Add some missing `VERIFY_CHECK(ctx != NULL)` 2c52b5d Merge #389: Cast pointers through uintptr_t under JNI 43097a4 Merge #390: Update bitcoin-core GitHub links 31c9c12 Merge #391: JNI: Only call ecdsa_verify if its inputs parsed correctly 1cb2302 Merge #392: Add testcase which hits additional branch in secp256k1_scalar_sqr d2ee340 Merge #388: bench_ecdh: fix call to secp256k1_context_create 093a497 Add testcase which hits additional branch in secp256k1_scalar_sqr a40c701 JNI: Only call ecdsa_verify if its inputs parsed correctly faa2a11 Update bitcoin-core GitHub links 47b9e78 Cast pointers through uintptr_t under JNI f36f9c6 bench_ecdh: fix call to secp256k1_context_create bcc4881 Add some missing `VERIFY_CHECK(ctx != NULL)` for functions that use `ARG_CHECK` 6ceea2c align shared files copyright/comments to bitcoinj's 70141a8 Update .gitignore 7b549b1 Merge #373: build: fix x86_64 asm detection for some compilers bc7c93c Merge #374: Add note about y=0 being possible on one of the sextic twists e457018 Merge #364: JNI rebased 86e2d07 JNI library: cleanup, removed unimplemented code 3093576a JNI library bd2895f Merge pull request #371 e72e93a Add note about y=0 being possible on one of the sextic twists 3f8fdfb build: fix x86_64 asm detection for some compilers e5a9047 [Trivial] Remove double semicolons c18b869 Merge pull request #360 3026daa Merge pull request #302 03d4611 Add sage verification script for the group laws a965937 Merge pull request #361 83221ec Add experimental features to configure 5d4c5a3 Prevent damage_array in the signature test from going out of bounds. 419bf7f Merge pull request #356 03d84a4 Benchmark against OpenSSL verification git-subtree-dir: src/secp256k1 git-subtree-split: 7a49cacd3937311fcb1cb36b6ba3336fca8119910.14
Wladimir J. van der Laan
8 years ago
42 changed files with 3905 additions and 195 deletions
@ -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,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,247 @@ |
|||||||
|
package org.bitcoin; |
||||||
|
|
||||||
|
import com.google.common.io.BaseEncoding; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.math.BigInteger; |
||||||
|
import javax.xml.bind.DatatypeConverter; |
||||||
|
import static org.bitcoin.NativeSecp256k1Util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class holds test cases defined for testing this library. |
||||||
|
*/ |
||||||
|
public class NativeSecp256k1Test { |
||||||
|
|
||||||
|
//TODO improve comments/add more tests
|
||||||
|
/** |
||||||
|
* This tests verify() for a valid signature |
||||||
|
*/ |
||||||
|
public static void testVerifyPos() throws AssertFailException{ |
||||||
|
boolean result = false; |
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); |
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); |
||||||
|
|
||||||
|
result = NativeSecp256k1.verify( data, sig, pub); |
||||||
|
assertEquals( result, true , "testVerifyPos"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests verify() for a non-valid signature |
||||||
|
*/ |
||||||
|
public static void testVerifyNeg() throws AssertFailException{ |
||||||
|
boolean result = false; |
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); |
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); |
||||||
|
|
||||||
|
result = NativeSecp256k1.verify( data, sig, pub); |
||||||
|
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||||
|
assertEquals( result, false , "testVerifyNeg"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests secret key verify() for a valid secretkey |
||||||
|
*/ |
||||||
|
public static void testSecKeyVerifyPos() throws AssertFailException{ |
||||||
|
boolean result = false; |
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
||||||
|
|
||||||
|
result = NativeSecp256k1.secKeyVerify( sec ); |
||||||
|
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||||
|
assertEquals( result, true , "testSecKeyVerifyPos"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests secret key verify() for a invalid secretkey |
||||||
|
*/ |
||||||
|
public static void testSecKeyVerifyNeg() throws AssertFailException{ |
||||||
|
boolean result = false; |
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); |
||||||
|
|
||||||
|
result = NativeSecp256k1.secKeyVerify( sec ); |
||||||
|
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||||
|
assertEquals( result, false , "testSecKeyVerifyNeg"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests public key create() for a valid secretkey |
||||||
|
*/ |
||||||
|
public static void testPubKeyCreatePos() throws AssertFailException{ |
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.computePubkey( sec); |
||||||
|
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
||||||
|
assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests public key create() for a invalid secretkey |
||||||
|
*/ |
||||||
|
public static void testPubKeyCreateNeg() throws AssertFailException{ |
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); |
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.computePubkey( sec); |
||||||
|
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
||||||
|
assertEquals( pubkeyString, "" , "testPubKeyCreateNeg"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests sign() for a valid secretkey |
||||||
|
*/ |
||||||
|
public static void testSignPos() throws AssertFailException{ |
||||||
|
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.sign(data, sec); |
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
||||||
|
assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests sign() for a invalid secretkey |
||||||
|
*/ |
||||||
|
public static void testSignNeg() throws AssertFailException{ |
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); |
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.sign(data, sec); |
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
||||||
|
assertEquals( sigString, "" , "testSignNeg"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests private key tweak-add |
||||||
|
*/ |
||||||
|
public static void testPrivKeyTweakAdd_1() throws AssertFailException { |
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data ); |
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
||||||
|
assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests private key tweak-mul |
||||||
|
*/ |
||||||
|
public static void testPrivKeyTweakMul_1() throws AssertFailException { |
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data ); |
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
||||||
|
assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests private key tweak-add uncompressed |
||||||
|
*/ |
||||||
|
public static void testPrivKeyTweakAdd_2() throws AssertFailException { |
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); |
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data ); |
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
||||||
|
assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests private key tweak-mul uncompressed |
||||||
|
*/ |
||||||
|
public static void testPrivKeyTweakMul_2() throws AssertFailException { |
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); |
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data ); |
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
||||||
|
assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests seed randomization |
||||||
|
*/ |
||||||
|
public static void testRandomize() throws AssertFailException { |
||||||
|
byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random"
|
||||||
|
boolean result = NativeSecp256k1.randomize(seed); |
||||||
|
assertEquals( result, true, "testRandomize"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests signSchnorr() for a valid secretkey |
||||||
|
*/ |
||||||
|
public static void testSchnorrSign() throws AssertFailException{ |
||||||
|
|
||||||
|
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.schnorrSign(data, sec); |
||||||
|
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
||||||
|
assertEquals( sigString, "C5E929AA058B982048760422D3B563749B7D0E50C5EBD8CD2FFC23214BD6A2F1B072C13880997EBA847CF20F2F90FCE07C1CA33A890A4127095A351127F8D95F" , "testSchnorrSign"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This tests signSchnorr() for a valid secretkey |
||||||
|
*/ |
||||||
|
public static void testCreateECDHSecret() throws AssertFailException{ |
||||||
|
|
||||||
|
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
||||||
|
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); |
||||||
|
|
||||||
|
byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub); |
||||||
|
String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
||||||
|
assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret"); |
||||||
|
} |
||||||
|
|
||||||
|
public static void main(String[] args) throws AssertFailException{ |
||||||
|
|
||||||
|
|
||||||
|
System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n"); |
||||||
|
|
||||||
|
assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" ); |
||||||
|
|
||||||
|
//Test verify() success/fail
|
||||||
|
testVerifyPos(); |
||||||
|
testVerifyNeg(); |
||||||
|
|
||||||
|
//Test secKeyVerify() success/fail
|
||||||
|
testSecKeyVerifyPos(); |
||||||
|
testSecKeyVerifyNeg(); |
||||||
|
|
||||||
|
//Test computePubkey() success/fail
|
||||||
|
testPubKeyCreatePos(); |
||||||
|
testPubKeyCreateNeg(); |
||||||
|
|
||||||
|
//Test sign() success/fail
|
||||||
|
testSignPos(); |
||||||
|
testSignNeg(); |
||||||
|
|
||||||
|
//Test Schnorr (partial support) //TODO
|
||||||
|
testSchnorrSign(); |
||||||
|
//testSchnorrVerify
|
||||||
|
//testSchnorrRecovery
|
||||||
|
|
||||||
|
//Test privKeyTweakAdd() 1
|
||||||
|
testPrivKeyTweakAdd_1(); |
||||||
|
|
||||||
|
//Test privKeyTweakMul() 2
|
||||||
|
testPrivKeyTweakMul_1(); |
||||||
|
|
||||||
|
//Test privKeyTweakAdd() 3
|
||||||
|
testPrivKeyTweakAdd_2(); |
||||||
|
|
||||||
|
//Test privKeyTweakMul() 4
|
||||||
|
testPrivKeyTweakMul_2(); |
||||||
|
|
||||||
|
//Test randomize()
|
||||||
|
testRandomize(); |
||||||
|
|
||||||
|
//Test ECDH
|
||||||
|
testCreateECDHSecret(); |
||||||
|
|
||||||
|
NativeSecp256k1.cleanup(); |
||||||
|
|
||||||
|
System.out.println(" All tests passed." ); |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2014-2016 the libsecp256k1 contributors |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.bitcoin; |
||||||
|
|
||||||
|
public class NativeSecp256k1Util{ |
||||||
|
|
||||||
|
public static void assertEquals( int val, int val2, String message ) throws AssertFailException{ |
||||||
|
if( val != val2 ) |
||||||
|
throw new AssertFailException("FAIL: " + message); |
||||||
|
} |
||||||
|
|
||||||
|
public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{ |
||||||
|
if( val != val2 ) |
||||||
|
throw new AssertFailException("FAIL: " + message); |
||||||
|
else |
||||||
|
System.out.println("PASS: " + message); |
||||||
|
} |
||||||
|
|
||||||
|
public static void assertEquals( String val, String val2, String message ) throws AssertFailException{ |
||||||
|
if( !val.equals(val2) ) |
||||||
|
throw new AssertFailException("FAIL: " + message); |
||||||
|
else |
||||||
|
System.out.println("PASS: " + message); |
||||||
|
} |
||||||
|
|
||||||
|
public static class AssertFailException extends Exception { |
||||||
|
public AssertFailException(String message) { |
||||||
|
super( message ); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,51 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2014-2016 the libsecp256k1 contributors |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.bitcoin; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class holds the context reference used in native methods |
||||||
|
* to handle ECDSA operations. |
||||||
|
*/ |
||||||
|
public class Secp256k1Context { |
||||||
|
private static final boolean enabled; //true if the library is loaded
|
||||||
|
private static final long context; //ref to pointer to context obj
|
||||||
|
|
||||||
|
static { //static initializer
|
||||||
|
boolean isEnabled = true; |
||||||
|
long contextRef = -1; |
||||||
|
try { |
||||||
|
System.loadLibrary("secp256k1"); |
||||||
|
contextRef = secp256k1_init_context(); |
||||||
|
} catch (UnsatisfiedLinkError e) { |
||||||
|
System.out.println("UnsatisfiedLinkError: " + e.toString()); |
||||||
|
isEnabled = false; |
||||||
|
} |
||||||
|
enabled = isEnabled; |
||||||
|
context = contextRef; |
||||||
|
} |
||||||
|
|
||||||
|
public static boolean isEnabled() { |
||||||
|
return enabled; |
||||||
|
} |
||||||
|
|
||||||
|
public static long getContext() { |
||||||
|
if(!enabled) return -1; //sanity check
|
||||||
|
return context; |
||||||
|
} |
||||||
|
|
||||||
|
private static native long secp256k1_init_context(); |
||||||
|
} |
@ -1,23 +1,411 @@ |
|||||||
|
#include <stdlib.h> |
||||||
|
#include <stdint.h> |
||||||
|
#include <string.h> |
||||||
#include "org_bitcoin_NativeSecp256k1.h" |
#include "org_bitcoin_NativeSecp256k1.h" |
||||||
#include "include/secp256k1.h" |
#include "include/secp256k1.h" |
||||||
|
#include "include/secp256k1_ecdh.h" |
||||||
|
#include "include/secp256k1_recovery.h" |
||||||
|
#include "include/secp256k1_schnorr.h" |
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify |
|
||||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject) |
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone |
||||||
|
(JNIEnv* env, jclass classObject, jlong ctx_l) |
||||||
|
{ |
||||||
|
const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||||
|
|
||||||
|
jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx); |
||||||
|
|
||||||
|
(void)classObject;(void)env; |
||||||
|
|
||||||
|
return ctx_clone_l; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize |
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) |
||||||
|
{ |
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||||
|
|
||||||
|
const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||||
|
|
||||||
|
(void)classObject; |
||||||
|
|
||||||
|
return secp256k1_context_randomize(ctx, seed); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context |
||||||
|
(JNIEnv* env, jclass classObject, jlong ctx_l) |
||||||
|
{ |
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||||
|
|
||||||
|
secp256k1_context_destroy(ctx); |
||||||
|
|
||||||
|
(void)classObject;(void)env; |
||||||
|
} |
||||||
|
|
||||||
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify |
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen) |
||||||
{ |
{ |
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||||
|
|
||||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||||
int sigLen = *((int*)(data + 32)); |
const unsigned char* sigdata = { (unsigned char*) (data + 32) }; |
||||||
int pubLen = *((int*)(data + 32 + 4)); |
const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) }; |
||||||
|
|
||||||
|
secp256k1_ecdsa_signature sig; |
||||||
|
secp256k1_pubkey pubkey; |
||||||
|
|
||||||
|
int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen); |
||||||
|
|
||||||
|
if( ret ) { |
||||||
|
ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); |
||||||
|
|
||||||
|
if( ret ) { |
||||||
|
ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
(void)classObject; |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign |
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) |
||||||
|
{ |
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||||
|
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||||
|
unsigned char* secKey = (unsigned char*) (data + 32); |
||||||
|
|
||||||
|
jobjectArray retArray; |
||||||
|
jbyteArray sigArray, intsByteArray; |
||||||
|
unsigned char intsarray[2]; |
||||||
|
|
||||||
|
secp256k1_ecdsa_signature sig[72]; |
||||||
|
|
||||||
|
int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL ); |
||||||
|
|
||||||
|
unsigned char outputSer[72]; |
||||||
|
size_t outputLen = 72; |
||||||
|
|
||||||
|
if( ret ) { |
||||||
|
int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2; |
||||||
|
} |
||||||
|
|
||||||
|
intsarray[0] = outputLen; |
||||||
|
intsarray[1] = ret; |
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2, |
||||||
|
(*env)->FindClass(env, "[B"), |
||||||
|
(*env)->NewByteArray(env, 1)); |
||||||
|
|
||||||
|
sigArray = (*env)->NewByteArray(env, outputLen); |
||||||
|
(*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray); |
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2); |
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); |
||||||
|
|
||||||
|
(void)classObject; |
||||||
|
|
||||||
|
return retArray; |
||||||
|
} |
||||||
|
|
||||||
|
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify |
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) |
||||||
|
{ |
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||||
|
unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||||
|
|
||||||
|
(void)classObject; |
||||||
|
|
||||||
|
return secp256k1_ec_seckey_verify(ctx, secKey); |
||||||
|
} |
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create |
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) |
||||||
|
{ |
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||||
|
const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||||
|
|
||||||
|
secp256k1_pubkey pubkey; |
||||||
|
|
||||||
|
jobjectArray retArray; |
||||||
|
jbyteArray pubkeyArray, intsByteArray; |
||||||
|
unsigned char intsarray[2]; |
||||||
|
|
||||||
|
int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey); |
||||||
|
|
||||||
|
unsigned char outputSer[65]; |
||||||
|
size_t outputLen = 65; |
||||||
|
|
||||||
|
if( ret ) { |
||||||
|
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; |
||||||
|
} |
||||||
|
|
||||||
|
intsarray[0] = outputLen; |
||||||
|
intsarray[1] = ret; |
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2, |
||||||
|
(*env)->FindClass(env, "[B"), |
||||||
|
(*env)->NewByteArray(env, 1)); |
||||||
|
|
||||||
|
pubkeyArray = (*env)->NewByteArray(env, outputLen); |
||||||
|
(*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray); |
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2); |
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); |
||||||
|
|
||||||
|
(void)classObject; |
||||||
|
|
||||||
|
return retArray; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add |
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) |
||||||
|
{ |
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||||
|
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||||
|
const unsigned char* tweak = (unsigned char*) (privkey + 32); |
||||||
|
|
||||||
|
jobjectArray retArray; |
||||||
|
jbyteArray privArray, intsByteArray; |
||||||
|
unsigned char intsarray[2]; |
||||||
|
|
||||||
|
int privkeylen = 32; |
||||||
|
|
||||||
return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen); |
int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak); |
||||||
|
|
||||||
|
intsarray[0] = privkeylen; |
||||||
|
intsarray[1] = ret; |
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2, |
||||||
|
(*env)->FindClass(env, "[B"), |
||||||
|
(*env)->NewByteArray(env, 1)); |
||||||
|
|
||||||
|
privArray = (*env)->NewByteArray(env, privkeylen); |
||||||
|
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, privArray); |
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2); |
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); |
||||||
|
|
||||||
|
(void)classObject; |
||||||
|
|
||||||
|
return retArray; |
||||||
|
} |
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul |
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) |
||||||
|
{ |
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||||
|
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||||
|
const unsigned char* tweak = (unsigned char*) (privkey + 32); |
||||||
|
|
||||||
|
jobjectArray retArray; |
||||||
|
jbyteArray privArray, intsByteArray; |
||||||
|
unsigned char intsarray[2]; |
||||||
|
|
||||||
|
int privkeylen = 32; |
||||||
|
|
||||||
|
int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak); |
||||||
|
|
||||||
|
intsarray[0] = privkeylen; |
||||||
|
intsarray[1] = ret; |
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2, |
||||||
|
(*env)->FindClass(env, "[B"), |
||||||
|
(*env)->NewByteArray(env, 1)); |
||||||
|
|
||||||
|
privArray = (*env)->NewByteArray(env, privkeylen); |
||||||
|
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, privArray); |
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2); |
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); |
||||||
|
|
||||||
|
(void)classObject; |
||||||
|
|
||||||
|
return retArray; |
||||||
} |
} |
||||||
|
|
||||||
static void __javasecp256k1_attach(void) __attribute__((constructor)); |
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add |
||||||
static void __javasecp256k1_detach(void) __attribute__((destructor)); |
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) |
||||||
|
{ |
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||||
|
/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/ |
||||||
|
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||||
|
const unsigned char* tweak = (unsigned char*) (pkey + publen); |
||||||
|
|
||||||
|
jobjectArray retArray; |
||||||
|
jbyteArray pubArray, intsByteArray; |
||||||
|
unsigned char intsarray[2]; |
||||||
|
unsigned char outputSer[65]; |
||||||
|
size_t outputLen = 65; |
||||||
|
|
||||||
|
secp256k1_pubkey pubkey; |
||||||
|
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); |
||||||
|
|
||||||
|
if( ret ) { |
||||||
|
ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak); |
||||||
|
} |
||||||
|
|
||||||
|
if( ret ) { |
||||||
|
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; |
||||||
|
} |
||||||
|
|
||||||
|
intsarray[0] = outputLen; |
||||||
|
intsarray[1] = ret; |
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2, |
||||||
|
(*env)->FindClass(env, "[B"), |
||||||
|
(*env)->NewByteArray(env, 1)); |
||||||
|
|
||||||
|
pubArray = (*env)->NewByteArray(env, outputLen); |
||||||
|
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray); |
||||||
|
|
||||||
static void __javasecp256k1_attach(void) { |
intsByteArray = (*env)->NewByteArray(env, 2); |
||||||
secp256k1_start(SECP256K1_START_VERIFY); |
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); |
||||||
|
|
||||||
|
(void)classObject; |
||||||
|
|
||||||
|
return retArray; |
||||||
} |
} |
||||||
|
|
||||||
static void __javasecp256k1_detach(void) { |
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul |
||||||
secp256k1_stop(); |
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) |
||||||
|
{ |
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||||
|
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||||
|
const unsigned char* tweak = (unsigned char*) (pkey + publen); |
||||||
|
|
||||||
|
jobjectArray retArray; |
||||||
|
jbyteArray pubArray, intsByteArray; |
||||||
|
unsigned char intsarray[2]; |
||||||
|
unsigned char outputSer[65]; |
||||||
|
size_t outputLen = 65; |
||||||
|
|
||||||
|
secp256k1_pubkey pubkey; |
||||||
|
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); |
||||||
|
|
||||||
|
if ( ret ) { |
||||||
|
ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak); |
||||||
|
} |
||||||
|
|
||||||
|
if( ret ) { |
||||||
|
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; |
||||||
|
} |
||||||
|
|
||||||
|
intsarray[0] = outputLen; |
||||||
|
intsarray[1] = ret; |
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2, |
||||||
|
(*env)->FindClass(env, "[B"), |
||||||
|
(*env)->NewByteArray(env, 1)); |
||||||
|
|
||||||
|
pubArray = (*env)->NewByteArray(env, outputLen); |
||||||
|
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray); |
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 2); |
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); |
||||||
|
|
||||||
|
(void)classObject; |
||||||
|
|
||||||
|
return retArray; |
||||||
|
} |
||||||
|
|
||||||
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine |
||||||
|
(JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys) |
||||||
|
{ |
||||||
|
(void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign |
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) |
||||||
|
{ |
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||||
|
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||||
|
unsigned char* secKey = (unsigned char*) (data + 32); |
||||||
|
|
||||||
|
jobjectArray retArray; |
||||||
|
jbyteArray sigArray, intsByteArray; |
||||||
|
unsigned char intsarray[1]; |
||||||
|
unsigned char sig[64]; |
||||||
|
|
||||||
|
int ret = secp256k1_schnorr_sign(ctx, sig, data, secKey, NULL, NULL); |
||||||
|
|
||||||
|
intsarray[0] = ret; |
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2, |
||||||
|
(*env)->FindClass(env, "[B"), |
||||||
|
(*env)->NewByteArray(env, 1)); |
||||||
|
|
||||||
|
sigArray = (*env)->NewByteArray(env, 64); |
||||||
|
(*env)->SetByteArrayRegion(env, sigArray, 0, 64, (jbyte*)sig); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray); |
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 1); |
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); |
||||||
|
|
||||||
|
(void)classObject; |
||||||
|
|
||||||
|
return retArray; |
||||||
|
} |
||||||
|
|
||||||
|
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh |
||||||
|
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) |
||||||
|
{ |
||||||
|
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||||
|
const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||||
|
const unsigned char* pubdata = (const unsigned char*) (secdata + 32); |
||||||
|
|
||||||
|
jobjectArray retArray; |
||||||
|
jbyteArray outArray, intsByteArray; |
||||||
|
unsigned char intsarray[1]; |
||||||
|
secp256k1_pubkey pubkey; |
||||||
|
unsigned char nonce_res[32]; |
||||||
|
size_t outputLen = 32; |
||||||
|
|
||||||
|
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); |
||||||
|
|
||||||
|
if (ret) { |
||||||
|
ret = secp256k1_ecdh( |
||||||
|
ctx, |
||||||
|
nonce_res, |
||||||
|
&pubkey, |
||||||
|
secdata |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
intsarray[0] = ret; |
||||||
|
|
||||||
|
retArray = (*env)->NewObjectArray(env, 2, |
||||||
|
(*env)->FindClass(env, "[B"), |
||||||
|
(*env)->NewByteArray(env, 1)); |
||||||
|
|
||||||
|
outArray = (*env)->NewByteArray(env, outputLen); |
||||||
|
(*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 0, outArray); |
||||||
|
|
||||||
|
intsByteArray = (*env)->NewByteArray(env, 1); |
||||||
|
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); |
||||||
|
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); |
||||||
|
|
||||||
|
(void)classObject; |
||||||
|
|
||||||
|
return retArray; |
||||||
} |
} |
||||||
|
@ -0,0 +1,15 @@ |
|||||||
|
#include <stdlib.h> |
||||||
|
#include <stdint.h> |
||||||
|
#include "org_bitcoin_Secp256k1Context.h" |
||||||
|
#include "include/secp256k1.h" |
||||||
|
|
||||||
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context |
||||||
|
(JNIEnv* env, jclass classObject) |
||||||
|
{ |
||||||
|
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); |
||||||
|
|
||||||
|
(void)classObject;(void)env; |
||||||
|
|
||||||
|
return (uintptr_t)ctx; |
||||||
|
} |
||||||
|
|
@ -0,0 +1,22 @@ |
|||||||
|
/* DO NOT EDIT THIS FILE - it is machine generated */ |
||||||
|
#include <jni.h> |
||||||
|
#include "include/secp256k1.h" |
||||||
|
/* Header for class org_bitcoin_Secp256k1Context */ |
||||||
|
|
||||||
|
#ifndef _Included_org_bitcoin_Secp256k1Context |
||||||
|
#define _Included_org_bitcoin_Secp256k1Context |
||||||
|
#ifdef __cplusplus |
||||||
|
extern "C" { |
||||||
|
#endif |
||||||
|
/*
|
||||||
|
* Class: org_bitcoin_Secp256k1Context |
||||||
|
* Method: secp256k1_init_context |
||||||
|
* Signature: ()J |
||||||
|
*/ |
||||||
|
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context |
||||||
|
(JNIEnv *, jclass); |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
} |
||||||
|
#endif |
||||||
|
#endif |
Loading…
Reference in new issue