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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 |
||||
|
@ -1,60 +1,478 @@
@@ -1,60 +1,478 @@
|
||||
/* |
||||
* Copyright 2013 Google Inc. |
||||
* Copyright 2014-2016 the libsecp256k1 contributors |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.bitcoin; |
||||
|
||||
import java.nio.ByteBuffer; |
||||
import java.nio.ByteOrder; |
||||
|
||||
import java.math.BigInteger; |
||||
import com.google.common.base.Preconditions; |
||||
|
||||
import java.util.concurrent.locks.Lock; |
||||
import java.util.concurrent.locks.ReentrantReadWriteLock; |
||||
import static org.bitcoin.NativeSecp256k1Util.*; |
||||
|
||||
/** |
||||
* This class holds native methods to handle ECDSA verification. |
||||
* You can find an example library that can be used for this at |
||||
* https://github.com/sipa/secp256k1
|
||||
* <p>This class holds native methods to handle ECDSA verification.</p> |
||||
* |
||||
* <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
|
||||
* |
||||
* <p>To build secp256k1 for use with bitcoinj, run |
||||
* `./configure --enable-jni --enable-experimental --enable-module-schnorr --enable-module-ecdh` |
||||
* and `make` then copy `.libs/libsecp256k1.so` to your system library path |
||||
* or point the JVM to the folder containing it with -Djava.library.path |
||||
* </p> |
||||
*/ |
||||
public class NativeSecp256k1 { |
||||
public static final boolean enabled; |
||||
static { |
||||
boolean isEnabled = true; |
||||
try { |
||||
System.loadLibrary("javasecp256k1"); |
||||
} catch (UnsatisfiedLinkError e) { |
||||
isEnabled = false; |
||||
} |
||||
enabled = isEnabled; |
||||
} |
||||
|
||||
|
||||
private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); |
||||
private static final Lock r = rwl.readLock(); |
||||
private static final Lock w = rwl.writeLock(); |
||||
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>(); |
||||
/** |
||||
* Verifies the given secp256k1 signature in native code. |
||||
* Calling when enabled == false is undefined (probably library not loaded) |
||||
* |
||||
* |
||||
* @param data The data which was signed, must be exactly 32 bytes |
||||
* @param signature The signature |
||||
* @param pub The public key which did the signing |
||||
*/ |
||||
public static boolean verify(byte[] data, byte[] signature, byte[] pub) { |
||||
public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{ |
||||
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); |
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get(); |
||||
if (byteBuff == null) { |
||||
byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520); |
||||
if (byteBuff == null || byteBuff.capacity() < 520) { |
||||
byteBuff = ByteBuffer.allocateDirect(520); |
||||
byteBuff.order(ByteOrder.nativeOrder()); |
||||
nativeECDSABuffer.set(byteBuff); |
||||
} |
||||
byteBuff.rewind(); |
||||
byteBuff.put(data); |
||||
byteBuff.putInt(signature.length); |
||||
byteBuff.putInt(pub.length); |
||||
byteBuff.put(signature); |
||||
byteBuff.put(pub); |
||||
return secp256k1_ecdsa_verify(byteBuff) == 1; |
||||
|
||||
byte[][] retByteArray; |
||||
|
||||
r.lock(); |
||||
try { |
||||
return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1; |
||||
} finally { |
||||
r.unlock(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* libsecp256k1 Create an ECDSA signature. |
||||
* |
||||
* @param data Message hash, 32 bytes |
||||
* @param key Secret key, 32 bytes |
||||
* |
||||
* Return values |
||||
* @param sig byte array of signature |
||||
*/ |
||||
public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{ |
||||
Preconditions.checkArgument(data.length == 32 && sec.length <= 32); |
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get(); |
||||
if (byteBuff == null || byteBuff.capacity() < 32 + 32) { |
||||
byteBuff = ByteBuffer.allocateDirect(32 + 32); |
||||
byteBuff.order(ByteOrder.nativeOrder()); |
||||
nativeECDSABuffer.set(byteBuff); |
||||
} |
||||
byteBuff.rewind(); |
||||
byteBuff.put(data); |
||||
byteBuff.put(sec); |
||||
|
||||
byte[][] retByteArray; |
||||
|
||||
r.lock(); |
||||
try { |
||||
retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext()); |
||||
} finally { |
||||
r.unlock(); |
||||
} |
||||
|
||||
byte[] sigArr = retByteArray[0]; |
||||
int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); |
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); |
||||
|
||||
assertEquals(sigArr.length, sigLen, "Got bad signature length."); |
||||
|
||||
return retVal == 0 ? new byte[0] : sigArr; |
||||
} |
||||
|
||||
/** |
||||
* libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid |
||||
* |
||||
* @param seckey ECDSA Secret key, 32 bytes |
||||
*/ |
||||
public static boolean secKeyVerify(byte[] seckey) { |
||||
Preconditions.checkArgument(seckey.length == 32); |
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get(); |
||||
if (byteBuff == null || byteBuff.capacity() < seckey.length) { |
||||
byteBuff = ByteBuffer.allocateDirect(seckey.length); |
||||
byteBuff.order(ByteOrder.nativeOrder()); |
||||
nativeECDSABuffer.set(byteBuff); |
||||
} |
||||
byteBuff.rewind(); |
||||
byteBuff.put(seckey); |
||||
|
||||
r.lock(); |
||||
try { |
||||
return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1; |
||||
} finally { |
||||
r.unlock(); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* libsecp256k1 Compute Pubkey - computes public key from secret key |
||||
* |
||||
* @param seckey ECDSA Secret key, 32 bytes |
||||
* |
||||
* Return values |
||||
* @param pubkey ECDSA Public key, 33 or 65 bytes |
||||
*/ |
||||
//TODO add a 'compressed' arg
|
||||
public static byte[] computePubkey(byte[] seckey) throws AssertFailException{ |
||||
Preconditions.checkArgument(seckey.length == 32); |
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get(); |
||||
if (byteBuff == null || byteBuff.capacity() < seckey.length) { |
||||
byteBuff = ByteBuffer.allocateDirect(seckey.length); |
||||
byteBuff.order(ByteOrder.nativeOrder()); |
||||
nativeECDSABuffer.set(byteBuff); |
||||
} |
||||
byteBuff.rewind(); |
||||
byteBuff.put(seckey); |
||||
|
||||
byte[][] retByteArray; |
||||
|
||||
r.lock(); |
||||
try { |
||||
retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext()); |
||||
} finally { |
||||
r.unlock(); |
||||
} |
||||
|
||||
byte[] pubArr = retByteArray[0]; |
||||
int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); |
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); |
||||
|
||||
assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); |
||||
|
||||
return retVal == 0 ? new byte[0]: pubArr; |
||||
} |
||||
|
||||
/** |
||||
* libsecp256k1 Cleanup - This destroys the secp256k1 context object |
||||
* This should be called at the end of the program for proper cleanup of the context. |
||||
*/ |
||||
public static synchronized void cleanup() { |
||||
w.lock(); |
||||
try { |
||||
secp256k1_destroy_context(Secp256k1Context.getContext()); |
||||
} finally { |
||||
w.unlock(); |
||||
} |
||||
} |
||||
|
||||
public static long cloneContext() { |
||||
r.lock(); |
||||
try { |
||||
return secp256k1_ctx_clone(Secp256k1Context.getContext()); |
||||
} finally { r.unlock(); } |
||||
} |
||||
|
||||
/** |
||||
* libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it |
||||
* |
||||
* @param tweak some bytes to tweak with |
||||
* @param seckey 32-byte seckey |
||||
*/ |
||||
public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{ |
||||
Preconditions.checkArgument(privkey.length == 32); |
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get(); |
||||
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { |
||||
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); |
||||
byteBuff.order(ByteOrder.nativeOrder()); |
||||
nativeECDSABuffer.set(byteBuff); |
||||
} |
||||
byteBuff.rewind(); |
||||
byteBuff.put(privkey); |
||||
byteBuff.put(tweak); |
||||
|
||||
byte[][] retByteArray; |
||||
r.lock(); |
||||
try { |
||||
retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext()); |
||||
} finally { |
||||
r.unlock(); |
||||
} |
||||
|
||||
byte[] privArr = retByteArray[0]; |
||||
|
||||
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; |
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); |
||||
|
||||
assertEquals(privArr.length, privLen, "Got bad pubkey length."); |
||||
|
||||
assertEquals(retVal, 1, "Failed return value check."); |
||||
|
||||
return privArr; |
||||
} |
||||
|
||||
/** |
||||
* @param byteBuff signature format is byte[32] data, |
||||
* native-endian int signatureLength, native-endian int pubkeyLength, |
||||
* byte[signatureLength] signature, byte[pubkeyLength] pub |
||||
* @returns 1 for valid signature, anything else for invalid |
||||
* libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it |
||||
* |
||||
* @param tweak some bytes to tweak with |
||||
* @param seckey 32-byte seckey |
||||
*/ |
||||
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff); |
||||
public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{ |
||||
Preconditions.checkArgument(privkey.length == 32); |
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get(); |
||||
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { |
||||
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); |
||||
byteBuff.order(ByteOrder.nativeOrder()); |
||||
nativeECDSABuffer.set(byteBuff); |
||||
} |
||||
byteBuff.rewind(); |
||||
byteBuff.put(privkey); |
||||
byteBuff.put(tweak); |
||||
|
||||
byte[][] retByteArray; |
||||
r.lock(); |
||||
try { |
||||
retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext()); |
||||
} finally { |
||||
r.unlock(); |
||||
} |
||||
|
||||
byte[] privArr = retByteArray[0]; |
||||
|
||||
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; |
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); |
||||
|
||||
assertEquals(privArr.length, privLen, "Got bad pubkey length."); |
||||
|
||||
assertEquals(retVal, 1, "Failed return value check."); |
||||
|
||||
return privArr; |
||||
} |
||||
|
||||
/** |
||||
* libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it |
||||
* |
||||
* @param tweak some bytes to tweak with |
||||
* @param pubkey 32-byte seckey |
||||
*/ |
||||
public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{ |
||||
Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); |
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get(); |
||||
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { |
||||
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); |
||||
byteBuff.order(ByteOrder.nativeOrder()); |
||||
nativeECDSABuffer.set(byteBuff); |
||||
} |
||||
byteBuff.rewind(); |
||||
byteBuff.put(pubkey); |
||||
byteBuff.put(tweak); |
||||
|
||||
byte[][] retByteArray; |
||||
r.lock(); |
||||
try { |
||||
retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length); |
||||
} finally { |
||||
r.unlock(); |
||||
} |
||||
|
||||
byte[] pubArr = retByteArray[0]; |
||||
|
||||
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; |
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); |
||||
|
||||
assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); |
||||
|
||||
assertEquals(retVal, 1, "Failed return value check."); |
||||
|
||||
return pubArr; |
||||
} |
||||
|
||||
/** |
||||
* libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it |
||||
* |
||||
* @param tweak some bytes to tweak with |
||||
* @param pubkey 32-byte seckey |
||||
*/ |
||||
public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{ |
||||
Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); |
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get(); |
||||
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { |
||||
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); |
||||
byteBuff.order(ByteOrder.nativeOrder()); |
||||
nativeECDSABuffer.set(byteBuff); |
||||
} |
||||
byteBuff.rewind(); |
||||
byteBuff.put(pubkey); |
||||
byteBuff.put(tweak); |
||||
|
||||
byte[][] retByteArray; |
||||
r.lock(); |
||||
try { |
||||
retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length); |
||||
} finally { |
||||
r.unlock(); |
||||
} |
||||
|
||||
byte[] pubArr = retByteArray[0]; |
||||
|
||||
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; |
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); |
||||
|
||||
assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); |
||||
|
||||
assertEquals(retVal, 1, "Failed return value check."); |
||||
|
||||
return pubArr; |
||||
} |
||||
|
||||
/** |
||||
* libsecp256k1 create ECDH secret - constant time ECDH calculation |
||||
* |
||||
* @param seckey byte array of secret key used in exponentiaion |
||||
* @param pubkey byte array of public key used in exponentiaion |
||||
*/ |
||||
public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{ |
||||
Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65); |
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get(); |
||||
if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) { |
||||
byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length); |
||||
byteBuff.order(ByteOrder.nativeOrder()); |
||||
nativeECDSABuffer.set(byteBuff); |
||||
} |
||||
byteBuff.rewind(); |
||||
byteBuff.put(seckey); |
||||
byteBuff.put(pubkey); |
||||
|
||||
byte[][] retByteArray; |
||||
r.lock(); |
||||
try { |
||||
retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length); |
||||
} finally { |
||||
r.unlock(); |
||||
} |
||||
|
||||
byte[] resArr = retByteArray[0]; |
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); |
||||
|
||||
assertEquals(resArr.length, 32, "Got bad result length."); |
||||
assertEquals(retVal, 1, "Failed return value check."); |
||||
|
||||
return resArr; |
||||
} |
||||
|
||||
/** |
||||
* libsecp256k1 randomize - updates the context randomization |
||||
* |
||||
* @param seed 32-byte random seed |
||||
*/ |
||||
public static synchronized boolean randomize(byte[] seed) throws AssertFailException{ |
||||
Preconditions.checkArgument(seed.length == 32 || seed == null); |
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get(); |
||||
if (byteBuff == null || byteBuff.capacity() < seed.length) { |
||||
byteBuff = ByteBuffer.allocateDirect(seed.length); |
||||
byteBuff.order(ByteOrder.nativeOrder()); |
||||
nativeECDSABuffer.set(byteBuff); |
||||
} |
||||
byteBuff.rewind(); |
||||
byteBuff.put(seed); |
||||
|
||||
w.lock(); |
||||
try { |
||||
return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1; |
||||
} finally { |
||||
w.unlock(); |
||||
} |
||||
} |
||||
|
||||
public static byte[] schnorrSign(byte[] data, byte[] sec) throws AssertFailException { |
||||
Preconditions.checkArgument(data.length == 32 && sec.length <= 32); |
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get(); |
||||
if (byteBuff == null) { |
||||
byteBuff = ByteBuffer.allocateDirect(32 + 32); |
||||
byteBuff.order(ByteOrder.nativeOrder()); |
||||
nativeECDSABuffer.set(byteBuff); |
||||
} |
||||
byteBuff.rewind(); |
||||
byteBuff.put(data); |
||||
byteBuff.put(sec); |
||||
|
||||
byte[][] retByteArray; |
||||
|
||||
r.lock(); |
||||
try { |
||||
retByteArray = secp256k1_schnorr_sign(byteBuff, Secp256k1Context.getContext()); |
||||
} finally { |
||||
r.unlock(); |
||||
} |
||||
|
||||
byte[] sigArr = retByteArray[0]; |
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); |
||||
|
||||
assertEquals(sigArr.length, 64, "Got bad signature length."); |
||||
|
||||
return retVal == 0 ? new byte[0] : sigArr; |
||||
} |
||||
|
||||
private static native long secp256k1_ctx_clone(long context); |
||||
|
||||
private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context); |
||||
|
||||
private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context); |
||||
|
||||
private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context); |
||||
|
||||
private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen); |
||||
|
||||
private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen); |
||||
|
||||
private static native void secp256k1_destroy_context(long context); |
||||
|
||||
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen); |
||||
|
||||
private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); |
||||
|
||||
private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context); |
||||
|
||||
private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context); |
||||
|
||||
private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen); |
||||
|
||||
private static native byte[][] secp256k1_schnorr_sign(ByteBuffer byteBuff, long context); |
||||
|
||||
private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen); |
||||
|
||||
} |
||||
|
@ -0,0 +1,247 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -1,23 +1,411 @@
|
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
#include "org_bitcoin_NativeSecp256k1.h" |
||||
#include "include/secp256k1.h" |
||||
#include "include/secp256k1_ecdh.h" |
||||
#include "include/secp256k1_recovery.h" |
||||
#include "include/secp256k1_schnorr.h" |
||||
|
||||
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify |
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject) |
||||
|
||||
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone |
||||
(JNIEnv* env, jclass classObject, jlong ctx_l) |
||||
{ |
||||
const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||
|
||||
jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx); |
||||
|
||||
(void)classObject;(void)env; |
||||
|
||||
return ctx_clone_l; |
||||
|
||||
} |
||||
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize |
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) |
||||
{ |
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||
|
||||
const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||
|
||||
(void)classObject; |
||||
|
||||
return secp256k1_context_randomize(ctx, seed); |
||||
|
||||
} |
||||
|
||||
SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context |
||||
(JNIEnv* env, jclass classObject, jlong ctx_l) |
||||
{ |
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||
|
||||
secp256k1_context_destroy(ctx); |
||||
|
||||
(void)classObject;(void)env; |
||||
} |
||||
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify |
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen) |
||||
{ |
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||
|
||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||
const unsigned char* sigdata = { (unsigned char*) (data + 32) }; |
||||
const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) }; |
||||
|
||||
secp256k1_ecdsa_signature sig; |
||||
secp256k1_pubkey pubkey; |
||||
|
||||
int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen); |
||||
|
||||
if( ret ) { |
||||
ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); |
||||
|
||||
if( ret ) { |
||||
ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey); |
||||
} |
||||
} |
||||
|
||||
(void)classObject; |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign |
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) |
||||
{ |
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||
unsigned char* secKey = (unsigned char*) (data + 32); |
||||
|
||||
jobjectArray retArray; |
||||
jbyteArray sigArray, intsByteArray; |
||||
unsigned char intsarray[2]; |
||||
|
||||
secp256k1_ecdsa_signature sig[72]; |
||||
|
||||
int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL ); |
||||
|
||||
unsigned char outputSer[72]; |
||||
size_t outputLen = 72; |
||||
|
||||
if( ret ) { |
||||
int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2; |
||||
} |
||||
|
||||
intsarray[0] = outputLen; |
||||
intsarray[1] = ret; |
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2, |
||||
(*env)->FindClass(env, "[B"), |
||||
(*env)->NewByteArray(env, 1)); |
||||
|
||||
sigArray = (*env)->NewByteArray(env, outputLen); |
||||
(*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer); |
||||
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray); |
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2); |
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); |
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); |
||||
|
||||
(void)classObject; |
||||
|
||||
return retArray; |
||||
} |
||||
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify |
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) |
||||
{ |
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||
unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||
|
||||
(void)classObject; |
||||
|
||||
return secp256k1_ec_seckey_verify(ctx, secKey); |
||||
} |
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create |
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) |
||||
{ |
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||
const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||
|
||||
secp256k1_pubkey pubkey; |
||||
|
||||
jobjectArray retArray; |
||||
jbyteArray pubkeyArray, intsByteArray; |
||||
unsigned char intsarray[2]; |
||||
|
||||
int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey); |
||||
|
||||
unsigned char outputSer[65]; |
||||
size_t outputLen = 65; |
||||
|
||||
if( ret ) { |
||||
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; |
||||
} |
||||
|
||||
intsarray[0] = outputLen; |
||||
intsarray[1] = ret; |
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2, |
||||
(*env)->FindClass(env, "[B"), |
||||
(*env)->NewByteArray(env, 1)); |
||||
|
||||
pubkeyArray = (*env)->NewByteArray(env, outputLen); |
||||
(*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer); |
||||
(*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray); |
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2); |
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); |
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); |
||||
|
||||
(void)classObject; |
||||
|
||||
return retArray; |
||||
|
||||
} |
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add |
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) |
||||
{ |
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||
const unsigned char* tweak = (unsigned char*) (privkey + 32); |
||||
|
||||
jobjectArray retArray; |
||||
jbyteArray privArray, intsByteArray; |
||||
unsigned char intsarray[2]; |
||||
|
||||
int privkeylen = 32; |
||||
|
||||
int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak); |
||||
|
||||
intsarray[0] = privkeylen; |
||||
intsarray[1] = ret; |
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2, |
||||
(*env)->FindClass(env, "[B"), |
||||
(*env)->NewByteArray(env, 1)); |
||||
|
||||
privArray = (*env)->NewByteArray(env, privkeylen); |
||||
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); |
||||
(*env)->SetObjectArrayElement(env, retArray, 0, privArray); |
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2); |
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); |
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); |
||||
|
||||
(void)classObject; |
||||
|
||||
return retArray; |
||||
} |
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul |
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) |
||||
{ |
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||
const unsigned char* tweak = (unsigned char*) (privkey + 32); |
||||
|
||||
jobjectArray retArray; |
||||
jbyteArray privArray, intsByteArray; |
||||
unsigned char intsarray[2]; |
||||
|
||||
int privkeylen = 32; |
||||
|
||||
int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak); |
||||
|
||||
intsarray[0] = privkeylen; |
||||
intsarray[1] = ret; |
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2, |
||||
(*env)->FindClass(env, "[B"), |
||||
(*env)->NewByteArray(env, 1)); |
||||
|
||||
privArray = (*env)->NewByteArray(env, privkeylen); |
||||
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); |
||||
(*env)->SetObjectArrayElement(env, retArray, 0, privArray); |
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2); |
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); |
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); |
||||
|
||||
(void)classObject; |
||||
|
||||
return retArray; |
||||
} |
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add |
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) |
||||
{ |
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; |
||||
/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/ |
||||
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||
const unsigned char* tweak = (unsigned char*) (pkey + publen); |
||||
|
||||
jobjectArray retArray; |
||||
jbyteArray pubArray, intsByteArray; |
||||
unsigned char intsarray[2]; |
||||
unsigned char outputSer[65]; |
||||
size_t outputLen = 65; |
||||
|
||||
secp256k1_pubkey pubkey; |
||||
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); |
||||
|
||||
if( ret ) { |
||||
ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak); |
||||
} |
||||
|
||||
if( ret ) { |
||||
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; |
||||
} |
||||
|
||||
intsarray[0] = outputLen; |
||||
intsarray[1] = ret; |
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2, |
||||
(*env)->FindClass(env, "[B"), |
||||
(*env)->NewByteArray(env, 1)); |
||||
|
||||
pubArray = (*env)->NewByteArray(env, outputLen); |
||||
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); |
||||
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray); |
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2); |
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); |
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); |
||||
|
||||
(void)classObject; |
||||
|
||||
return retArray; |
||||
} |
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul |
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) |
||||
{ |
||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); |
||||
int sigLen = *((int*)(data + 32)); |
||||
int pubLen = *((int*)(data + 32 + 4)); |
||||
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); |
||||
|
||||
return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen); |
||||
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)); |
||||
static void __javasecp256k1_detach(void) __attribute__((destructor)); |
||||
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; |
||||
|
||||
static void __javasecp256k1_attach(void) { |
||||
secp256k1_start(SECP256K1_START_VERIFY); |
||||
return 0; |
||||
} |
||||
|
||||
static void __javasecp256k1_detach(void) { |
||||
secp256k1_stop(); |
||||
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 @@
@@ -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 @@
@@ -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