Browse Source
Add Makefile target update-secp256k1, and run it. The only API change is that len is now an IN-OUT parameter to serialization functions. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>ppa-0.6.1
Rusty Russell
9 years ago
60 changed files with 6444 additions and 557 deletions
@ -0,0 +1,3 @@ |
|||
secp256k1 imported from https://github.com/bitcoin-core/secp256k1 |
|||
|
|||
secp256k1 version: b3be8521e694eaf45dd29baea035055183c42fe2 |
@ -0,0 +1,150 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2015 Pieter Wuille * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#include <string.h> |
|||
#include <secp256k1.h> |
|||
|
|||
#include "lax_der_parsing.h" |
|||
|
|||
int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { |
|||
size_t rpos, rlen, spos, slen; |
|||
size_t pos = 0; |
|||
size_t lenbyte; |
|||
unsigned char tmpsig[64] = {0}; |
|||
int overflow = 0; |
|||
|
|||
/* Hack to initialize sig with a correctly-parsed but invalid signature. */ |
|||
secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); |
|||
|
|||
/* Sequence tag byte */ |
|||
if (pos == inputlen || input[pos] != 0x30) { |
|||
return 0; |
|||
} |
|||
pos++; |
|||
|
|||
/* Sequence length bytes */ |
|||
if (pos == inputlen) { |
|||
return 0; |
|||
} |
|||
lenbyte = input[pos++]; |
|||
if (lenbyte & 0x80) { |
|||
lenbyte -= 0x80; |
|||
if (pos + lenbyte > inputlen) { |
|||
return 0; |
|||
} |
|||
pos += lenbyte; |
|||
} |
|||
|
|||
/* Integer tag byte for R */ |
|||
if (pos == inputlen || input[pos] != 0x02) { |
|||
return 0; |
|||
} |
|||
pos++; |
|||
|
|||
/* Integer length for R */ |
|||
if (pos == inputlen) { |
|||
return 0; |
|||
} |
|||
lenbyte = input[pos++]; |
|||
if (lenbyte & 0x80) { |
|||
lenbyte -= 0x80; |
|||
if (pos + lenbyte > inputlen) { |
|||
return 0; |
|||
} |
|||
while (lenbyte > 0 && input[pos] == 0) { |
|||
pos++; |
|||
lenbyte--; |
|||
} |
|||
if (lenbyte >= sizeof(size_t)) { |
|||
return 0; |
|||
} |
|||
rlen = 0; |
|||
while (lenbyte > 0) { |
|||
rlen = (rlen << 8) + input[pos]; |
|||
pos++; |
|||
lenbyte--; |
|||
} |
|||
} else { |
|||
rlen = lenbyte; |
|||
} |
|||
if (rlen > inputlen - pos) { |
|||
return 0; |
|||
} |
|||
rpos = pos; |
|||
pos += rlen; |
|||
|
|||
/* Integer tag byte for S */ |
|||
if (pos == inputlen || input[pos] != 0x02) { |
|||
return 0; |
|||
} |
|||
pos++; |
|||
|
|||
/* Integer length for S */ |
|||
if (pos == inputlen) { |
|||
return 0; |
|||
} |
|||
lenbyte = input[pos++]; |
|||
if (lenbyte & 0x80) { |
|||
lenbyte -= 0x80; |
|||
if (pos + lenbyte > inputlen) { |
|||
return 0; |
|||
} |
|||
while (lenbyte > 0 && input[pos] == 0) { |
|||
pos++; |
|||
lenbyte--; |
|||
} |
|||
if (lenbyte >= sizeof(size_t)) { |
|||
return 0; |
|||
} |
|||
slen = 0; |
|||
while (lenbyte > 0) { |
|||
slen = (slen << 8) + input[pos]; |
|||
pos++; |
|||
lenbyte--; |
|||
} |
|||
} else { |
|||
slen = lenbyte; |
|||
} |
|||
if (slen > inputlen - pos) { |
|||
return 0; |
|||
} |
|||
spos = pos; |
|||
pos += slen; |
|||
|
|||
/* Ignore leading zeroes in R */ |
|||
while (rlen > 0 && input[rpos] == 0) { |
|||
rlen--; |
|||
rpos++; |
|||
} |
|||
/* Copy R value */ |
|||
if (rlen > 32) { |
|||
overflow = 1; |
|||
} else { |
|||
memcpy(tmpsig + 32 - rlen, input + rpos, rlen); |
|||
} |
|||
|
|||
/* Ignore leading zeroes in S */ |
|||
while (slen > 0 && input[spos] == 0) { |
|||
slen--; |
|||
spos++; |
|||
} |
|||
/* Copy S value */ |
|||
if (slen > 32) { |
|||
overflow = 1; |
|||
} else { |
|||
memcpy(tmpsig + 64 - slen, input + spos, slen); |
|||
} |
|||
|
|||
if (!overflow) { |
|||
overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); |
|||
} |
|||
if (overflow) { |
|||
memset(tmpsig, 0, 64); |
|||
secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); |
|||
} |
|||
return 1; |
|||
} |
|||
|
@ -0,0 +1,91 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2015 Pieter Wuille * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
/****
|
|||
* Please do not link this file directly. It is not part of the libsecp256k1 |
|||
* project and does not promise any stability in its API, functionality or |
|||
* presence. Projects which use this code should instead copy this header |
|||
* and its accompanying .c file directly into their codebase. |
|||
****/ |
|||
|
|||
/* This file defines a function that parses DER with various errors and
|
|||
* violations. This is not a part of the library itself, because the allowed |
|||
* violations are chosen arbitrarily and do not follow or establish any |
|||
* standard. |
|||
* |
|||
* In many places it matters that different implementations do not only accept |
|||
* the same set of valid signatures, but also reject the same set of signatures. |
|||
* The only means to accomplish that is by strictly obeying a standard, and not |
|||
* accepting anything else. |
|||
* |
|||
* Nonetheless, sometimes there is a need for compatibility with systems that |
|||
* use signatures which do not strictly obey DER. The snippet below shows how |
|||
* certain violations are easily supported. You may need to adapt it. |
|||
* |
|||
* Do not use this for new systems. Use well-defined DER or compact signatures |
|||
* instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and |
|||
* secp256k1_ecdsa_signature_parse_compact). |
|||
* |
|||
* The supported violations are: |
|||
* - All numbers are parsed as nonnegative integers, even though X.609-0207 |
|||
* section 8.3.3 specifies that integers are always encoded as two's |
|||
* complement. |
|||
* - Integers can have length 0, even though section 8.3.1 says they can't. |
|||
* - Integers with overly long padding are accepted, violation section |
|||
* 8.3.2. |
|||
* - 127-byte long length descriptors are accepted, even though section |
|||
* 8.1.3.5.c says that they are not. |
|||
* - Trailing garbage data inside or after the signature is ignored. |
|||
* - The length descriptor of the sequence is ignored. |
|||
* |
|||
* Compared to for example OpenSSL, many violations are NOT supported: |
|||
* - Using overly long tag descriptors for the sequence or integers inside, |
|||
* violating section 8.1.2.2. |
|||
* - Encoding primitive integers as constructed values, violating section |
|||
* 8.3.1. |
|||
*/ |
|||
|
|||
#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ |
|||
#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ |
|||
|
|||
#include <secp256k1.h> |
|||
|
|||
# ifdef __cplusplus |
|||
extern "C" { |
|||
# endif |
|||
|
|||
/** Parse a signature in "lax DER" format
|
|||
* |
|||
* Returns: 1 when the signature could be parsed, 0 otherwise. |
|||
* Args: ctx: a secp256k1 context object |
|||
* Out: sig: a pointer to a signature object |
|||
* In: input: a pointer to the signature to be parsed |
|||
* inputlen: the length of the array pointed to be input |
|||
* |
|||
* This function will accept any valid DER encoded signature, even if the |
|||
* encoded numbers are out of range. In addition, it will accept signatures |
|||
* which violate the DER spec in various ways. Its purpose is to allow |
|||
* validation of the Bitcoin blockchain, which includes non-DER signatures |
|||
* from before the network rules were updated to enforce DER. Note that |
|||
* the set of supported violations is a strict subset of what OpenSSL will |
|||
* accept. |
|||
* |
|||
* After the call, sig will always be initialized. If parsing failed or the |
|||
* encoded numbers are out of range, signature validation with it is |
|||
* guaranteed to fail for every message and public key. |
|||
*/ |
|||
int ecdsa_signature_parse_der_lax( |
|||
const secp256k1_context* ctx, |
|||
secp256k1_ecdsa_signature* sig, |
|||
const unsigned char *input, |
|||
size_t inputlen |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
|
|||
#endif |
@ -0,0 +1,113 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2014, 2015 Pieter Wuille * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
#include <string.h> |
|||
#include <secp256k1.h> |
|||
|
|||
#include "lax_der_privatekey_parsing.h" |
|||
|
|||
int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) { |
|||
const unsigned char *end = privkey + privkeylen; |
|||
int lenb = 0; |
|||
int len = 0; |
|||
memset(out32, 0, 32); |
|||
/* sequence header */ |
|||
if (end < privkey+1 || *privkey != 0x30) { |
|||
return 0; |
|||
} |
|||
privkey++; |
|||
/* sequence length constructor */ |
|||
if (end < privkey+1 || !(*privkey & 0x80)) { |
|||
return 0; |
|||
} |
|||
lenb = *privkey & ~0x80; privkey++; |
|||
if (lenb < 1 || lenb > 2) { |
|||
return 0; |
|||
} |
|||
if (end < privkey+lenb) { |
|||
return 0; |
|||
} |
|||
/* sequence length */ |
|||
len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); |
|||
privkey += lenb; |
|||
if (end < privkey+len) { |
|||
return 0; |
|||
} |
|||
/* sequence element 0: version number (=1) */ |
|||
if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { |
|||
return 0; |
|||
} |
|||
privkey += 3; |
|||
/* sequence element 1: octet string, up to 32 bytes */ |
|||
if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { |
|||
return 0; |
|||
} |
|||
memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); |
|||
if (!secp256k1_ec_seckey_verify(ctx, out32)) { |
|||
memset(out32, 0, 32); |
|||
return 0; |
|||
} |
|||
return 1; |
|||
} |
|||
|
|||
int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { |
|||
secp256k1_pubkey pubkey; |
|||
size_t pubkeylen = 0; |
|||
if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { |
|||
*privkeylen = 0; |
|||
return 0; |
|||
} |
|||
if (compressed) { |
|||
static const unsigned char begin[] = { |
|||
0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 |
|||
}; |
|||
static const unsigned char middle[] = { |
|||
0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, |
|||
0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, |
|||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, |
|||
0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, |
|||
0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, |
|||
0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, |
|||
0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, |
|||
0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, |
|||
0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 |
|||
}; |
|||
unsigned char *ptr = privkey; |
|||
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); |
|||
memcpy(ptr, key32, 32); ptr += 32; |
|||
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); |
|||
pubkeylen = 33; |
|||
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); |
|||
ptr += pubkeylen; |
|||
*privkeylen = ptr - privkey; |
|||
} else { |
|||
static const unsigned char begin[] = { |
|||
0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 |
|||
}; |
|||
static const unsigned char middle[] = { |
|||
0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, |
|||
0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, |
|||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, |
|||
0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, |
|||
0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, |
|||
0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, |
|||
0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, |
|||
0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, |
|||
0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, |
|||
0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, |
|||
0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 |
|||
}; |
|||
unsigned char *ptr = privkey; |
|||
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); |
|||
memcpy(ptr, key32, 32); ptr += 32; |
|||
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); |
|||
pubkeylen = 65; |
|||
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); |
|||
ptr += pubkeylen; |
|||
*privkeylen = ptr - privkey; |
|||
} |
|||
return 1; |
|||
} |
@ -0,0 +1,90 @@ |
|||
/**********************************************************************
|
|||
* Copyright (c) 2014, 2015 Pieter Wuille * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
|||
**********************************************************************/ |
|||
|
|||
/****
|
|||
* Please do not link this file directly. It is not part of the libsecp256k1 |
|||
* project and does not promise any stability in its API, functionality or |
|||
* presence. Projects which use this code should instead copy this header |
|||
* and its accompanying .c file directly into their codebase. |
|||
****/ |
|||
|
|||
/* This file contains code snippets that parse DER private keys with
|
|||
* various errors and violations. This is not a part of the library |
|||
* itself, because the allowed violations are chosen arbitrarily and |
|||
* do not follow or establish any standard. |
|||
* |
|||
* It also contains code to serialize private keys in a compatible |
|||
* manner. |
|||
* |
|||
* These functions are meant for compatibility with applications |
|||
* that require BER encoded keys. When working with secp256k1-specific |
|||
* code, the simple 32-byte private keys normally used by the |
|||
* library are sufficient. |
|||
*/ |
|||
|
|||
#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ |
|||
#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ |
|||
|
|||
#include <secp256k1.h> |
|||
|
|||
# ifdef __cplusplus |
|||
extern "C" { |
|||
# endif |
|||
|
|||
/** Export a private key in DER format.
|
|||
* |
|||
* Returns: 1 if the private key was valid. |
|||
* Args: ctx: pointer to a context object, initialized for signing (cannot |
|||
* be NULL) |
|||
* Out: privkey: pointer to an array for storing the private key in BER. |
|||
* Should have space for 279 bytes, and cannot be NULL. |
|||
* privkeylen: Pointer to an int where the length of the private key in |
|||
* privkey will be stored. |
|||
* In: seckey: pointer to a 32-byte secret key to export. |
|||
* compressed: 1 if the key should be exported in |
|||
* compressed format, 0 otherwise |
|||
* |
|||
* This function is purely meant for compatibility with applications that |
|||
* require BER encoded keys. When working with secp256k1-specific code, the |
|||
* simple 32-byte private keys are sufficient. |
|||
* |
|||
* Note that this function does not guarantee correct DER output. It is |
|||
* guaranteed to be parsable by secp256k1_ec_privkey_import_der |
|||
*/ |
|||
SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der( |
|||
const secp256k1_context* ctx, |
|||
unsigned char *privkey, |
|||
size_t *privkeylen, |
|||
const unsigned char *seckey, |
|||
int compressed |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); |
|||
|
|||
/** Import a private key in DER format.
|
|||
* Returns: 1 if a private key was extracted. |
|||
* Args: ctx: pointer to a context object (cannot be NULL). |
|||
* Out: seckey: pointer to a 32-byte array for storing the private key. |
|||
* (cannot be NULL). |
|||
* In: privkey: pointer to a private key in DER format (cannot be NULL). |
|||
* privkeylen: length of the DER private key pointed to be privkey. |
|||
* |
|||
* This function will accept more than just strict DER, and even allow some BER |
|||
* violations. The public key stored inside the DER-encoded private key is not |
|||
* verified for correctness, nor are the curve parameters. Use this function |
|||
* only if you know in advance it is supposed to contain a secp256k1 private |
|||
* key. |
|||
*/ |
|||
SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der( |
|||
const secp256k1_context* ctx, |
|||
unsigned char *seckey, |
|||
const unsigned char *privkey, |
|||
size_t privkeylen |
|||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
|
|||
#endif |
@ -0,0 +1,322 @@ |
|||
# This code supports verifying group implementations which have branches |
|||
# or conditional statements (like cmovs), by allowing each execution path |
|||
# to independently set assumptions on input or intermediary variables. |
|||
# |
|||
# The general approach is: |
|||
# * A constraint is a tuple of two sets of of symbolic expressions: |
|||
# the first of which are required to evaluate to zero, the second of which |
|||
# are required to evaluate to nonzero. |
|||
# - A constraint is said to be conflicting if any of its nonzero expressions |
|||
# is in the ideal with basis the zero expressions (in other words: when the |
|||
# zero expressions imply that one of the nonzero expressions are zero). |
|||
# * There is a list of laws that describe the intended behaviour, including |
|||
# laws for addition and doubling. Each law is called with the symbolic point |
|||
# coordinates as arguments, and returns: |
|||
# - A constraint describing the assumptions under which it is applicable, |
|||
# called "assumeLaw" |
|||
# - A constraint describing the requirements of the law, called "require" |
|||
# * Implementations are transliterated into functions that operate as well on |
|||
# algebraic input points, and are called once per combination of branches |
|||
# exectured. Each execution returns: |
|||
# - A constraint describing the assumptions this implementation requires |
|||
# (such as Z1=1), called "assumeFormula" |
|||
# - A constraint describing the assumptions this specific branch requires, |
|||
# but which is by construction guaranteed to cover the entire space by |
|||
# merging the results from all branches, called "assumeBranch" |
|||
# - The result of the computation |
|||
# * All combinations of laws with implementation branches are tried, and: |
|||
# - If the combination of assumeLaw, assumeFormula, and assumeBranch results |
|||
# in a conflict, it means this law does not apply to this branch, and it is |
|||
# skipped. |
|||
# - For others, we try to prove the require constraints hold, assuming the |
|||
# information in assumeLaw + assumeFormula + assumeBranch, and if this does |
|||
# not succeed, we fail. |
|||
# + To prove an expression is zero, we check whether it belongs to the |
|||
# ideal with the assumed zero expressions as basis. This test is exact. |
|||
# + To prove an expression is nonzero, we check whether each of its |
|||
# factors is contained in the set of nonzero assumptions' factors. |
|||
# This test is not exact, so various combinations of original and |
|||
# reduced expressions' factors are tried. |
|||
# - If we succeed, we print out the assumptions from assumeFormula that |
|||
# weren't implied by assumeLaw already. Those from assumeBranch are skipped, |
|||
# as we assume that all constraints in it are complementary with each other. |
|||
# |
|||
# Based on the sage verification scripts used in the Explicit-Formulas Database |
|||
# by Tanja Lange and others, see http://hyperelliptic.org/EFD |
|||
|
|||
class fastfrac: |
|||
"""Fractions over rings.""" |
|||
|
|||
def __init__(self,R,top,bot=1): |
|||
"""Construct a fractional, given a ring, a numerator, and denominator.""" |
|||
self.R = R |
|||
if parent(top) == ZZ or parent(top) == R: |
|||
self.top = R(top) |
|||
self.bot = R(bot) |
|||
elif top.__class__ == fastfrac: |
|||
self.top = top.top |
|||
self.bot = top.bot * bot |
|||
else: |
|||
self.top = R(numerator(top)) |
|||
self.bot = R(denominator(top)) * bot |
|||
|
|||
def iszero(self,I): |
|||
"""Return whether this fraction is zero given an ideal.""" |
|||
return self.top in I and self.bot not in I |
|||
|
|||
def reduce(self,assumeZero): |
|||
zero = self.R.ideal(map(numerator, assumeZero)) |
|||
return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot)) |
|||
|
|||
def __add__(self,other): |
|||
"""Add two fractions.""" |
|||
if parent(other) == ZZ: |
|||
return fastfrac(self.R,self.top + self.bot * other,self.bot) |
|||
if other.__class__ == fastfrac: |
|||
return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot) |
|||
return NotImplemented |
|||
|
|||
def __sub__(self,other): |
|||
"""Subtract two fractions.""" |
|||
if parent(other) == ZZ: |
|||
return fastfrac(self.R,self.top - self.bot * other,self.bot) |
|||
if other.__class__ == fastfrac: |
|||
return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot) |
|||
return NotImplemented |
|||
|
|||
def __neg__(self): |
|||
"""Return the negation of a fraction.""" |
|||
return fastfrac(self.R,-self.top,self.bot) |
|||
|
|||
def __mul__(self,other): |
|||
"""Multiply two fractions.""" |
|||
if parent(other) == ZZ: |
|||
return fastfrac(self.R,self.top * other,self.bot) |
|||
if other.__class__ == fastfrac: |
|||
return fastfrac(self.R,self.top * other.top,self.bot * other.bot) |
|||
return NotImplemented |
|||
|
|||
def __rmul__(self,other): |
|||
"""Multiply something else with a fraction.""" |
|||
return self.__mul__(other) |
|||
|
|||
def __div__(self,other): |
|||
"""Divide two fractions.""" |
|||
if parent(other) == ZZ: |
|||
return fastfrac(self.R,self.top,self.bot * other) |
|||
if other.__class__ == fastfrac: |
|||
return fastfrac(self.R,self.top * other.bot,self.bot * other.top) |
|||
return NotImplemented |
|||
|
|||
def __pow__(self,other): |
|||
"""Compute a power of a fraction.""" |
|||
if parent(other) == ZZ: |
|||
if other < 0: |
|||
# Negative powers require flipping top and bottom |
|||
return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other)) |
|||
else: |
|||
return fastfrac(self.R,self.top ^ other,self.bot ^ other) |
|||
return NotImplemented |
|||
|
|||
def __str__(self): |
|||
return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))" |
|||
def __repr__(self): |
|||
return "%s" % self |
|||
|
|||
def numerator(self): |
|||
return self.top |
|||
|
|||
class constraints: |
|||
"""A set of constraints, consisting of zero and nonzero expressions. |
|||
|
|||
Constraints can either be used to express knowledge or a requirement. |
|||
|
|||
Both the fields zero and nonzero are maps from expressions to description |
|||
strings. The expressions that are the keys in zero are required to be zero, |
|||
and the expressions that are the keys in nonzero are required to be nonzero. |
|||
|
|||
Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in |
|||
nonzero could be multiplied into a single key. This is often much less |
|||
efficient to work with though, so we keep them separate inside the |
|||
constraints. This allows higher-level code to do fast checks on the individual |
|||
nonzero elements, or combine them if needed for stronger checks. |
|||
|
|||
We can't multiply the different zero elements, as it would suffice for one of |
|||
the factors to be zero, instead of all of them. Instead, the zero elements are |
|||
typically combined into an ideal first. |
|||
""" |
|||
|
|||
def __init__(self, **kwargs): |
|||
if 'zero' in kwargs: |
|||
self.zero = dict(kwargs['zero']) |
|||
else: |
|||
self.zero = dict() |
|||
if 'nonzero' in kwargs: |
|||
self.nonzero = dict(kwargs['nonzero']) |
|||
else: |
|||
self.nonzero = dict() |
|||
|
|||
def negate(self): |
|||
return constraints(zero=self.nonzero, nonzero=self.zero) |
|||
|
|||
def __add__(self, other): |
|||
zero = self.zero.copy() |
|||
zero.update(other.zero) |
|||
nonzero = self.nonzero.copy() |
|||
nonzero.update(other.nonzero) |
|||
return constraints(zero=zero, nonzero=nonzero) |
|||
|
|||
def __str__(self): |
|||
return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero) |
|||
|
|||
def __repr__(self): |
|||
return "%s" % self |
|||
|
|||
|
|||
def conflicts(R, con): |
|||
"""Check whether any of the passed non-zero assumptions is implied by the zero assumptions""" |
|||
zero = R.ideal(map(numerator, con.zero)) |
|||
if 1 in zero: |
|||
return True |
|||
# First a cheap check whether any of the individual nonzero terms conflict on |
|||
# their own. |
|||
for nonzero in con.nonzero: |
|||
if nonzero.iszero(zero): |
|||
return True |
|||
# It can be the case that entries in the nonzero set do not individually |
|||
# conflict with the zero set, but their combination does. For example, knowing |
|||
# that either x or y is zero is equivalent to having x*y in the zero set. |
|||
# Having x or y individually in the nonzero set is not a conflict, but both |
|||
# simultaneously is, so that is the right thing to check for. |
|||
if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero): |
|||
return True |
|||
return False |
|||
|
|||
|
|||
def get_nonzero_set(R, assume): |
|||
"""Calculate a simple set of nonzero expressions""" |
|||
zero = R.ideal(map(numerator, assume.zero)) |
|||
nonzero = set() |
|||
for nz in map(numerator, assume.nonzero): |
|||
for (f,n) in nz.factor(): |
|||
nonzero.add(f) |
|||
rnz = zero.reduce(nz) |
|||
for (f,n) in rnz.factor(): |
|||
nonzero.add(f) |
|||
return nonzero |
|||
|
|||
|
|||
def prove_nonzero(R, exprs, assume): |
|||
"""Check whether an expression is provably nonzero, given assumptions""" |
|||
zero = R.ideal(map(numerator, assume.zero)) |
|||
nonzero = get_nonzero_set(R, assume) |
|||
expl = set() |
|||
ok = True |
|||
for expr in exprs: |
|||
if numerator(expr) in zero: |
|||
return (False, [exprs[expr]]) |
|||
allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1) |
|||
for (f, n) in allexprs.factor(): |
|||
if f not in nonzero: |
|||
ok = False |
|||
if ok: |
|||
return (True, None) |
|||
ok = True |
|||
for (f, n) in zero.reduce(numerator(allexprs)).factor(): |
|||
if f not in nonzero: |
|||
ok = False |
|||
if ok: |
|||
return (True, None) |
|||
ok = True |
|||
for expr in exprs: |
|||
for (f,n) in numerator(expr).factor(): |
|||
if f not in nonzero: |
|||
ok = False |
|||
if ok: |
|||
return (True, None) |
|||
ok = True |
|||
for expr in exprs: |
|||
for (f,n) in zero.reduce(numerator(expr)).factor(): |
|||
if f not in nonzero: |
|||
expl.add(exprs[expr]) |
|||
if expl: |
|||
return (False, list(expl)) |
|||
else: |
|||
return (True, None) |
|||
|
|||
|
|||
def prove_zero(R, exprs, assume): |
|||
"""Check whether all of the passed expressions are provably zero, given assumptions""" |
|||
r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume) |
|||
if not r: |
|||
return (False, map(lambda x: "Possibly zero denominator: %s" % x, e)) |
|||
zero = R.ideal(map(numerator, assume.zero)) |
|||
nonzero = prod(x for x in assume.nonzero) |
|||
expl = [] |
|||
for expr in exprs: |
|||
if not expr.iszero(zero): |
|||
expl.append(exprs[expr]) |
|||
if not expl: |
|||
return (True, None) |
|||
return (False, expl) |
|||
|
|||
|
|||
def describe_extra(R, assume, assumeExtra): |
|||
"""Describe what assumptions are added, given existing assumptions""" |
|||
zerox = assume.zero.copy() |
|||
zerox.update(assumeExtra.zero) |
|||
zero = R.ideal(map(numerator, assume.zero)) |
|||
zeroextra = R.ideal(map(numerator, zerox)) |
|||
nonzero = get_nonzero_set(R, assume) |
|||
ret = set() |
|||
# Iterate over the extra zero expressions |
|||
for base in assumeExtra.zero: |
|||
if base not in zero: |
|||
add = [] |
|||
for (f, n) in numerator(base).factor(): |
|||
if f not in nonzero: |
|||
add += ["%s" % f] |
|||
if add: |
|||
ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base]) |
|||
# Iterate over the extra nonzero expressions |
|||
for nz in assumeExtra.nonzero: |
|||
nzr = zeroextra.reduce(numerator(nz)) |
|||
if nzr not in zeroextra: |
|||
for (f,n) in nzr.factor(): |
|||
if zeroextra.reduce(f) not in nonzero: |
|||
ret.add("%s != 0" % zeroextra.reduce(f)) |
|||
return ", ".join(x for x in ret) |
|||
|
|||
|
|||
def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require): |
|||
"""Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions""" |
|||
assume = assumeLaw + assumeAssert + assumeBranch |
|||
|
|||
if conflicts(R, assume): |
|||
# This formula does not apply |
|||
return None |
|||
|
|||
describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert) |
|||
|
|||
ok, msg = prove_zero(R, require.zero, assume) |
|||
if not ok: |
|||
return "FAIL, %s fails (assuming %s)" % (str(msg), describe) |
|||
|
|||
res, expl = prove_nonzero(R, require.nonzero, assume) |
|||
if not res: |
|||
return "FAIL, %s fails (assuming %s)" % (str(expl), describe) |
|||
|
|||
if describe != "": |
|||
return "OK (assuming %s)" % describe |
|||
else: |
|||
return "OK" |
|||
|
|||
|
|||
def concrete_verify(c): |
|||
for k in c.zero: |
|||
if k != 0: |
|||
return (False, c.zero[k]) |
|||
for k in c.nonzero: |
|||
if k == 0: |
|||
return (False, c.nonzero[k]) |
|||
return (True, None) |
@ -0,0 +1,306 @@ |
|||
# Test libsecp256k1' group operation implementations using prover.sage |
|||
|
|||
import sys |
|||
|
|||
load("group_prover.sage") |
|||
load("weierstrass_prover.sage") |
|||
|
|||
def formula_secp256k1_gej_double_var(a): |
|||
"""libsecp256k1's secp256k1_gej_double_var, used by various addition functions""" |
|||
rz = a.Z * a.Y |
|||
rz = rz * 2 |
|||
t1 = a.X^2 |
|||
t1 = t1 * 3 |
|||
t2 = t1^2 |
|||
t3 = a.Y^2 |
|||
t3 = t3 * 2 |
|||
t4 = t3^2 |
|||
t4 = t4 * 2 |
|||
t3 = t3 * a.X |
|||
rx = t3 |
|||
rx = rx * 4 |
|||
rx = -rx |
|||
rx = rx + t2 |
|||
t2 = -t2 |
|||
t3 = t3 * 6 |
|||
t3 = t3 + t2 |
|||
ry = t1 * t3 |
|||
t2 = -t4 |
|||
ry = ry + t2 |
|||
return jacobianpoint(rx, ry, rz) |
|||
|
|||
def formula_secp256k1_gej_add_var(branch, a, b): |
|||
"""libsecp256k1's secp256k1_gej_add_var""" |
|||
if branch == 0: |
|||
return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b) |
|||
if branch == 1: |
|||
return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) |
|||
z22 = b.Z^2 |
|||
z12 = a.Z^2 |
|||
u1 = a.X * z22 |
|||
u2 = b.X * z12 |
|||
s1 = a.Y * z22 |
|||
s1 = s1 * b.Z |
|||
s2 = b.Y * z12 |
|||
s2 = s2 * a.Z |
|||
h = -u1 |
|||
h = h + u2 |
|||
i = -s1 |
|||
i = i + s2 |
|||
if branch == 2: |
|||
r = formula_secp256k1_gej_double_var(a) |
|||
return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r) |
|||
if branch == 3: |
|||
return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity()) |
|||
i2 = i^2 |
|||
h2 = h^2 |
|||
h3 = h2 * h |
|||
h = h * b.Z |
|||
rz = a.Z * h |
|||
t = u1 * h2 |
|||
rx = t |
|||
rx = rx * 2 |
|||
rx = rx + h3 |
|||
rx = -rx |
|||
rx = rx + i2 |
|||
ry = -rx |
|||
ry = ry + t |
|||
ry = ry * i |
|||
h3 = h3 * s1 |
|||
h3 = -h3 |
|||
ry = ry + h3 |
|||
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) |
|||
|
|||
def formula_secp256k1_gej_add_ge_var(branch, a, b): |
|||
"""libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1""" |
|||
if branch == 0: |
|||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b) |
|||
if branch == 1: |
|||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) |
|||
z12 = a.Z^2 |
|||
u1 = a.X |
|||
u2 = b.X * z12 |
|||
s1 = a.Y |
|||
s2 = b.Y * z12 |
|||
s2 = s2 * a.Z |
|||
h = -u1 |
|||
h = h + u2 |
|||
i = -s1 |
|||
i = i + s2 |
|||
if (branch == 2): |
|||
r = formula_secp256k1_gej_double_var(a) |
|||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) |
|||
if (branch == 3): |
|||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) |
|||
i2 = i^2 |
|||
h2 = h^2 |
|||
h3 = h * h2 |
|||
rz = a.Z * h |
|||
t = u1 * h2 |
|||
rx = t |
|||
rx = rx * 2 |
|||
rx = rx + h3 |
|||
rx = -rx |
|||
rx = rx + i2 |
|||
ry = -rx |
|||
ry = ry + t |
|||
ry = ry * i |
|||
h3 = h3 * s1 |
|||
h3 = -h3 |
|||
ry = ry + h3 |
|||
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) |
|||
|
|||
def formula_secp256k1_gej_add_zinv_var(branch, a, b): |
|||
"""libsecp256k1's secp256k1_gej_add_zinv_var""" |
|||
bzinv = b.Z^(-1) |
|||
if branch == 0: |
|||
return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a) |
|||
if branch == 1: |
|||
bzinv2 = bzinv^2 |
|||
bzinv3 = bzinv2 * bzinv |
|||
rx = b.X * bzinv2 |
|||
ry = b.Y * bzinv3 |
|||
rz = 1 |
|||
return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz)) |
|||
azz = a.Z * bzinv |
|||
z12 = azz^2 |
|||
u1 = a.X |
|||
u2 = b.X * z12 |
|||
s1 = a.Y |
|||
s2 = b.Y * z12 |
|||
s2 = s2 * azz |
|||
h = -u1 |
|||
h = h + u2 |
|||
i = -s1 |
|||
i = i + s2 |
|||
if branch == 2: |
|||
r = formula_secp256k1_gej_double_var(a) |
|||
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) |
|||
if branch == 3: |
|||
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) |
|||
i2 = i^2 |
|||
h2 = h^2 |
|||
h3 = h * h2 |
|||
rz = a.Z |
|||
rz = rz * h |
|||
t = u1 * h2 |
|||
rx = t |
|||
rx = rx * 2 |
|||
rx = rx + h3 |
|||
rx = -rx |
|||
rx = rx + i2 |
|||
ry = -rx |
|||
ry = ry + t |
|||
ry = ry * i |
|||
h3 = h3 * s1 |
|||
h3 = -h3 |
|||
ry = ry + h3 |
|||
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) |
|||
|
|||
def formula_secp256k1_gej_add_ge(branch, a, b): |
|||
"""libsecp256k1's secp256k1_gej_add_ge""" |
|||
zeroes = {} |
|||
nonzeroes = {} |
|||
a_infinity = False |
|||
if (branch & 4) != 0: |
|||
nonzeroes.update({a.Infinity : 'a_infinite'}) |
|||
a_infinity = True |
|||
else: |
|||
zeroes.update({a.Infinity : 'a_finite'}) |
|||
zz = a.Z^2 |
|||
u1 = a.X |
|||
u2 = b.X * zz |
|||
s1 = a.Y |
|||
s2 = b.Y * zz |
|||
s2 = s2 * a.Z |
|||
t = u1 |
|||
t = t + u2 |
|||
m = s1 |
|||
m = m + s2 |
|||
rr = t^2 |
|||
m_alt = -u2 |
|||
tt = u1 * m_alt |
|||
rr = rr + tt |
|||
degenerate = (branch & 3) == 3 |
|||
if (branch & 1) != 0: |
|||
zeroes.update({m : 'm_zero'}) |
|||
else: |
|||
nonzeroes.update({m : 'm_nonzero'}) |
|||
if (branch & 2) != 0: |
|||
zeroes.update({rr : 'rr_zero'}) |
|||
else: |
|||
nonzeroes.update({rr : 'rr_nonzero'}) |
|||
rr_alt = s1 |
|||
rr_alt = rr_alt * 2 |
|||
m_alt = m_alt + u1 |
|||
if not degenerate: |
|||
rr_alt = rr |
|||
m_alt = m |
|||
n = m_alt^2 |
|||
q = n * t |
|||
n = n^2 |
|||
if degenerate: |
|||
n = m |
|||
t = rr_alt^2 |
|||
rz = a.Z * m_alt |
|||
infinity = False |
|||
if (branch & 8) != 0: |
|||
if not a_infinity: |
|||
infinity = True |
|||
zeroes.update({rz : 'r.z=0'}) |
|||
else: |
|||
nonzeroes.update({rz : 'r.z!=0'}) |
|||
rz = rz * 2 |
|||
q = -q |
|||
t = t + q |
|||
rx = t |
|||
t = t * 2 |
|||
t = t + q |
|||
t = t * rr_alt |
|||
t = t + n |
|||
ry = -t |
|||
rx = rx * 4 |
|||
ry = ry * 4 |
|||
if a_infinity: |
|||
rx = b.X |
|||
ry = b.Y |
|||
rz = 1 |
|||
if infinity: |
|||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) |
|||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) |
|||
|
|||
def formula_secp256k1_gej_add_ge_old(branch, a, b): |
|||
"""libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx""" |
|||
a_infinity = (branch & 1) != 0 |
|||
zero = {} |
|||
nonzero = {} |
|||
if a_infinity: |
|||
nonzero.update({a.Infinity : 'a_infinite'}) |
|||
else: |
|||
zero.update({a.Infinity : 'a_finite'}) |
|||
zz = a.Z^2 |
|||
u1 = a.X |
|||
u2 = b.X * zz |
|||
s1 = a.Y |
|||
s2 = b.Y * zz |
|||
s2 = s2 * a.Z |
|||
z = a.Z |
|||
t = u1 |
|||
t = t + u2 |
|||
m = s1 |
|||
m = m + s2 |
|||
n = m^2 |
|||
q = n * t |
|||
n = n^2 |
|||
rr = t^2 |
|||
t = u1 * u2 |
|||
t = -t |
|||
rr = rr + t |
|||
t = rr^2 |
|||
rz = m * z |
|||
infinity = False |
|||
if (branch & 2) != 0: |
|||
if not a_infinity: |
|||
infinity = True |
|||
else: |
|||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity()) |
|||
zero.update({rz : 'r.z=0'}) |
|||
else: |
|||
nonzero.update({rz : 'r.z!=0'}) |
|||
rz = rz * (0 if a_infinity else 2) |
|||
rx = t |
|||
q = -q |
|||
rx = rx + q |
|||
q = q * 3 |
|||
t = t * 2 |
|||
t = t + q |
|||
t = t * rr |
|||
t = t + n |
|||
ry = -t |
|||
rx = rx * (0 if a_infinity else 4) |
|||
ry = ry * (0 if a_infinity else 4) |
|||
t = b.X |
|||
t = t * (1 if a_infinity else 0) |
|||
rx = rx + t |
|||
t = b.Y |
|||
t = t * (1 if a_infinity else 0) |
|||
ry = ry + t |
|||
t = (1 if a_infinity else 0) |
|||
rz = rz + t |
|||
if infinity: |
|||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity()) |
|||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz)) |
|||
|
|||
if __name__ == "__main__": |
|||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var) |
|||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var) |
|||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var) |
|||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge) |
|||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old) |
|||
|
|||
if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": |
|||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43) |
|||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43) |
|||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43) |
|||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43) |
|||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43) |
@ -0,0 +1,264 @@ |
|||
# Prover implementation for Weierstrass curves of the form |
|||
# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws |
|||
# operating on affine and Jacobian coordinates, including the point at infinity |
|||
# represented by a 4th variable in coordinates. |
|||
|
|||
load("group_prover.sage") |
|||
|
|||
|
|||
class affinepoint: |
|||
def __init__(self, x, y, infinity=0): |
|||
self.x = x |
|||
self.y = y |
|||
self.infinity = infinity |
|||
def __str__(self): |
|||
return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity) |
|||
|
|||
|
|||
class jacobianpoint: |
|||
def __init__(self, x, y, z, infinity=0): |
|||
self.X = x |
|||
self.Y = y |
|||
self.Z = z |
|||
self.Infinity = infinity |
|||
def __str__(self): |
|||
return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity) |
|||
|
|||
|
|||
def point_at_infinity(): |
|||
return jacobianpoint(1, 1, 1, 1) |
|||
|
|||
|
|||
def negate(p): |
|||
if p.__class__ == affinepoint: |
|||
return affinepoint(p.x, -p.y) |
|||
if p.__class__ == jacobianpoint: |
|||
return jacobianpoint(p.X, -p.Y, p.Z) |
|||
assert(False) |
|||
|
|||
|
|||
def on_weierstrass_curve(A, B, p): |
|||
"""Return a set of zero-expressions for an affine point to be on the curve""" |
|||
return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'}) |
|||
|
|||
|
|||
def tangential_to_weierstrass_curve(A, B, p12, p3): |
|||
"""Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)""" |
|||
return constraints(zero={ |
|||
(p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve' |
|||
}) |
|||
|
|||
|
|||
def colinear(p1, p2, p3): |
|||
"""Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear""" |
|||
return constraints(zero={ |
|||
(p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1', |
|||
(p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2', |
|||
(p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3' |
|||
}) |
|||
|
|||
|
|||
def good_affine_point(p): |
|||
return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'}) |
|||
|
|||
|
|||
def good_jacobian_point(p): |
|||
return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'}) |
|||
|
|||
|
|||
def good_point(p): |
|||
return constraints(nonzero={p.Z^6 : 'nonzero_X'}) |
|||
|
|||
|
|||
def finite(p, *affine_fns): |
|||
con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'}) |
|||
if p.Z != 0: |
|||
return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con) |
|||
else: |
|||
return con |
|||
|
|||
def infinite(p): |
|||
return constraints(nonzero={p.Infinity : 'infinite_point'}) |
|||
|
|||
|
|||
def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC): |
|||
"""Check whether the passed set of coordinates is a valid Jacobian add, given assumptions""" |
|||
assumeLaw = (good_affine_point(pa) + |
|||
good_affine_point(pb) + |
|||
good_jacobian_point(pA) + |
|||
good_jacobian_point(pB) + |
|||
on_weierstrass_curve(A, B, pa) + |
|||
on_weierstrass_curve(A, B, pb) + |
|||
finite(pA) + |
|||
finite(pB) + |
|||
constraints(nonzero={pa.x - pb.x : 'different_x'})) |
|||
require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + |
|||
colinear(pa, pb, negate(pc)))) |
|||
return (assumeLaw, require) |
|||
|
|||
|
|||
def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC): |
|||
"""Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions""" |
|||
assumeLaw = (good_affine_point(pa) + |
|||
good_affine_point(pb) + |
|||
good_jacobian_point(pA) + |
|||
good_jacobian_point(pB) + |
|||
on_weierstrass_curve(A, B, pa) + |
|||
on_weierstrass_curve(A, B, pb) + |
|||
finite(pA) + |
|||
finite(pB) + |
|||
constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'})) |
|||
require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + |
|||
tangential_to_weierstrass_curve(A, B, pa, negate(pc)))) |
|||
return (assumeLaw, require) |
|||
|
|||
|
|||
def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC): |
|||
assumeLaw = (good_affine_point(pa) + |
|||
good_affine_point(pb) + |
|||
good_jacobian_point(pA) + |
|||
good_jacobian_point(pB) + |
|||
on_weierstrass_curve(A, B, pa) + |
|||
on_weierstrass_curve(A, B, pb) + |
|||
finite(pA) + |
|||
finite(pB) + |
|||
constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'})) |
|||
require = infinite(pC) |
|||
return (assumeLaw, require) |
|||
|
|||
|
|||
def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC): |
|||
assumeLaw = (good_affine_point(pa) + |
|||
good_affine_point(pb) + |
|||
good_jacobian_point(pA) + |
|||
good_jacobian_point(pB) + |
|||
on_weierstrass_curve(A, B, pb) + |
|||
infinite(pA) + |
|||
finite(pB)) |
|||
require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'})) |
|||
return (assumeLaw, require) |
|||
|
|||
|
|||
def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC): |
|||
assumeLaw = (good_affine_point(pa) + |
|||
good_affine_point(pb) + |
|||
good_jacobian_point(pA) + |
|||
good_jacobian_point(pB) + |
|||
on_weierstrass_curve(A, B, pa) + |
|||
infinite(pB) + |
|||
finite(pA)) |
|||
require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'})) |
|||
return (assumeLaw, require) |
|||
|
|||
|
|||
def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC): |
|||
assumeLaw = (good_affine_point(pa) + |
|||
good_affine_point(pb) + |
|||
good_jacobian_point(pA) + |
|||
good_jacobian_point(pB) + |
|||
infinite(pA) + |
|||
infinite(pB)) |
|||
require = infinite(pC) |
|||
return (assumeLaw, require) |
|||
|
|||
|
|||
laws_jacobian_weierstrass = { |
|||
'add': law_jacobian_weierstrass_add, |
|||
'double': law_jacobian_weierstrass_double, |
|||
'add_opposite': law_jacobian_weierstrass_add_opposites, |
|||
'add_infinite_a': law_jacobian_weierstrass_add_infinite_a, |
|||
'add_infinite_b': law_jacobian_weierstrass_add_infinite_b, |
|||
'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab |
|||
} |
|||
|
|||
|
|||
def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p): |
|||
"""Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field""" |
|||
F = Integers(p) |
|||
print "Formula %s on Z%i:" % (name, p) |
|||
points = [] |
|||
for x in xrange(0, p): |
|||
for y in xrange(0, p): |
|||
point = affinepoint(F(x), F(y)) |
|||
r, e = concrete_verify(on_weierstrass_curve(A, B, point)) |
|||
if r: |
|||
points.append(point) |
|||
|
|||
for za in xrange(1, p): |
|||
for zb in xrange(1, p): |
|||
for pa in points: |
|||
for pb in points: |
|||
for ia in xrange(2): |
|||
for ib in xrange(2): |
|||
pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia) |
|||
pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib) |
|||
for branch in xrange(0, branches): |
|||
assumeAssert, assumeBranch, pC = formula(branch, pA, pB) |
|||
pC.X = F(pC.X) |
|||
pC.Y = F(pC.Y) |
|||
pC.Z = F(pC.Z) |
|||
pC.Infinity = F(pC.Infinity) |
|||
r, e = concrete_verify(assumeAssert + assumeBranch) |
|||
if r: |
|||
match = False |
|||
for key in laws_jacobian_weierstrass: |
|||
assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC) |
|||
r, e = concrete_verify(assumeLaw) |
|||
if r: |
|||
if match: |
|||
print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity) |
|||
else: |
|||
match = True |
|||
r, e = concrete_verify(require) |
|||
if not r: |
|||
print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e) |
|||
print |
|||
|
|||
|
|||
def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC): |
|||
assumeLaw, require = f(A, B, pa, pb, pA, pB, pC) |
|||
return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require) |
|||
|
|||
def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula): |
|||
"""Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically""" |
|||
R.<ax,bx,ay,by,Az,Bz,Ai,Bi> = PolynomialRing(QQ,8,order='invlex') |
|||
lift = lambda x: fastfrac(R,x) |
|||
ax = lift(ax) |
|||
ay = lift(ay) |
|||
Az = lift(Az) |
|||
bx = lift(bx) |
|||
by = lift(by) |
|||
Bz = lift(Bz) |
|||
Ai = lift(Ai) |
|||
Bi = lift(Bi) |
|||
|
|||
pa = affinepoint(ax, ay, Ai) |
|||
pb = affinepoint(bx, by, Bi) |
|||
pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai) |
|||
pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi) |
|||
|
|||
res = {} |
|||
|
|||
for key in laws_jacobian_weierstrass: |
|||
res[key] = [] |
|||
|
|||
print ("Formula " + name + ":") |
|||
count = 0 |
|||
for branch in xrange(branches): |
|||
assumeFormula, assumeBranch, pC = formula(branch, pA, pB) |
|||
pC.X = lift(pC.X) |
|||
pC.Y = lift(pC.Y) |
|||
pC.Z = lift(pC.Z) |
|||
pC.Infinity = lift(pC.Infinity) |
|||
|
|||
for key in laws_jacobian_weierstrass: |
|||
res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch)) |
|||
|
|||
for key in res: |
|||
print " %s:" % key |
|||
val = res[key] |
|||
for x in val: |
|||
if x[0] is not None: |
|||
print " branch %i: %s" % (x[1], x[0]) |
|||
|
|||
print |
@ -0,0 +1,919 @@ |
|||
@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm: |
|||
/********************************************************************** |
|||
* Copyright (c) 2014 Wladimir J. van der Laan * |
|||
* Distributed under the MIT software license, see the accompanying * |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.* |
|||
**********************************************************************/ |
|||
/* |
|||
ARM implementation of field_10x26 inner loops. |
|||
|
|||
Note: |
|||
|
|||
- To avoid unnecessary loads and make use of available registers, two |
|||
'passes' have every time been interleaved, with the odd passes accumulating c' and d' |
|||
which will be added to c and d respectively in the the even passes |
|||
|
|||
*/ |
|||
|
|||
.syntax unified |
|||
.arch armv7-a |
|||
@ eabi attributes - see readelf -A |
|||
.eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes |
|||
.eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no |
|||
.eabi_attribute 10, 0 @ Tag_FP_arch = none |
|||
.eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte |
|||
.eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP |
|||
.eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed |
|||
.eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6 |
|||
.text |
|||
|
|||
@ Field constants |
|||
.set field_R0, 0x3d10 |
|||
.set field_R1, 0x400 |
|||
.set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff |
|||
|
|||
.align 2 |
|||
.global secp256k1_fe_mul_inner |
|||
.type secp256k1_fe_mul_inner, %function |
|||
@ Arguments: |
|||
@ r0 r Restrict: can overlap with a, not with b |
|||
@ r1 a |
|||
@ r2 b |
|||
@ Stack (total 4+10*4 = 44) |
|||
@ sp + #0 saved 'r' pointer |
|||
@ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 |
|||
secp256k1_fe_mul_inner: |
|||
stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} |
|||
sub sp, sp, #48 @ frame=44 + alignment |
|||
str r0, [sp, #0] @ save result address, we need it only at the end |
|||
|
|||
/****************************************** |
|||
* Main computation code. |
|||
****************************************** |
|||
|
|||
Allocation: |
|||
r0,r14,r7,r8 scratch |
|||
r1 a (pointer) |
|||
r2 b (pointer) |
|||
r3:r4 c |
|||
r5:r6 d |
|||
r11:r12 c' |
|||
r9:r10 d' |
|||
|
|||
Note: do not write to r[] here, it may overlap with a[] |
|||
*/ |
|||
|
|||
/* A - interleaved with B */ |
|||
ldr r7, [r1, #0*4] @ a[0] |
|||
ldr r8, [r2, #9*4] @ b[9] |
|||
ldr r0, [r1, #1*4] @ a[1] |
|||
umull r5, r6, r7, r8 @ d = a[0] * b[9] |
|||
ldr r14, [r2, #8*4] @ b[8] |
|||
umull r9, r10, r0, r8 @ d' = a[1] * b[9] |
|||
ldr r7, [r1, #2*4] @ a[2] |
|||
umlal r5, r6, r0, r14 @ d += a[1] * b[8] |
|||
ldr r8, [r2, #7*4] @ b[7] |
|||
umlal r9, r10, r7, r14 @ d' += a[2] * b[8] |
|||
ldr r0, [r1, #3*4] @ a[3] |
|||
umlal r5, r6, r7, r8 @ d += a[2] * b[7] |
|||
ldr r14, [r2, #6*4] @ b[6] |
|||
umlal r9, r10, r0, r8 @ d' += a[3] * b[7] |
|||
ldr r7, [r1, #4*4] @ a[4] |
|||
umlal r5, r6, r0, r14 @ d += a[3] * b[6] |
|||
ldr r8, [r2, #5*4] @ b[5] |
|||
umlal r9, r10, r7, r14 @ d' += a[4] * b[6] |
|||
ldr r0, [r1, #5*4] @ a[5] |
|||
umlal r5, r6, r7, r8 @ d += a[4] * b[5] |
|||
ldr r14, [r2, #4*4] @ b[4] |
|||
umlal r9, r10, r0, r8 @ d' += a[5] * b[5] |
|||
ldr r7, [r1, #6*4] @ a[6] |
|||
umlal r5, r6, r0, r14 @ d += a[5] * b[4] |
|||
ldr r8, [r2, #3*4] @ b[3] |
|||
umlal r9, r10, r7, r14 @ d' += a[6] * b[4] |
|||
ldr r0, [r1, #7*4] @ a[7] |
|||
umlal r5, r6, r7, r8 @ d += a[6] * b[3] |
|||
ldr r14, [r2, #2*4] @ b[2] |
|||
umlal r9, r10, r0, r8 @ d' += a[7] * b[3] |
|||
ldr r7, [r1, #8*4] @ a[8] |
|||
umlal r5, r6, r0, r14 @ d += a[7] * b[2] |
|||
ldr r8, [r2, #1*4] @ b[1] |
|||
umlal r9, r10, r7, r14 @ d' += a[8] * b[2] |
|||
ldr r0, [r1, #9*4] @ a[9] |
|||
umlal r5, r6, r7, r8 @ d += a[8] * b[1] |
|||
ldr r14, [r2, #0*4] @ b[0] |
|||
umlal r9, r10, r0, r8 @ d' += a[9] * b[1] |
|||
ldr r7, [r1, #0*4] @ a[0] |
|||
umlal r5, r6, r0, r14 @ d += a[9] * b[0] |
|||
@ r7,r14 used in B |
|||
|
|||
bic r0, r5, field_not_M @ t9 = d & M |
|||
str r0, [sp, #4 + 4*9] |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
|
|||
/* B */ |
|||
umull r3, r4, r7, r14 @ c = a[0] * b[0] |
|||
adds r5, r5, r9 @ d += d' |
|||
adc r6, r6, r10 |
|||
|
|||
bic r0, r5, field_not_M @ u0 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u0 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
bic r14, r3, field_not_M @ t0 = c & M |
|||
str r14, [sp, #4 + 0*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u0 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* C - interleaved with D */ |
|||
ldr r7, [r1, #0*4] @ a[0] |
|||
ldr r8, [r2, #2*4] @ b[2] |
|||
ldr r14, [r2, #1*4] @ b[1] |
|||
umull r11, r12, r7, r8 @ c' = a[0] * b[2] |
|||
ldr r0, [r1, #1*4] @ a[1] |
|||
umlal r3, r4, r7, r14 @ c += a[0] * b[1] |
|||
ldr r8, [r2, #0*4] @ b[0] |
|||
umlal r11, r12, r0, r14 @ c' += a[1] * b[1] |
|||
ldr r7, [r1, #2*4] @ a[2] |
|||
umlal r3, r4, r0, r8 @ c += a[1] * b[0] |
|||
ldr r14, [r2, #9*4] @ b[9] |
|||
umlal r11, r12, r7, r8 @ c' += a[2] * b[0] |
|||
ldr r0, [r1, #3*4] @ a[3] |
|||
umlal r5, r6, r7, r14 @ d += a[2] * b[9] |
|||
ldr r8, [r2, #8*4] @ b[8] |
|||
umull r9, r10, r0, r14 @ d' = a[3] * b[9] |
|||
ldr r7, [r1, #4*4] @ a[4] |
|||
umlal r5, r6, r0, r8 @ d += a[3] * b[8] |
|||
ldr r14, [r2, #7*4] @ b[7] |
|||
umlal r9, r10, r7, r8 @ d' += a[4] * b[8] |
|||
ldr r0, [r1, #5*4] @ a[5] |
|||
umlal r5, r6, r7, r14 @ d += a[4] * b[7] |
|||
ldr r8, [r2, #6*4] @ b[6] |
|||
umlal r9, r10, r0, r14 @ d' += a[5] * b[7] |
|||
ldr r7, [r1, #6*4] @ a[6] |
|||
umlal r5, r6, r0, r8 @ d += a[5] * b[6] |
|||
ldr r14, [r2, #5*4] @ b[5] |
|||
umlal r9, r10, r7, r8 @ d' += a[6] * b[6] |
|||
ldr r0, [r1, #7*4] @ a[7] |
|||
umlal r5, r6, r7, r14 @ d += a[6] * b[5] |
|||
ldr r8, [r2, #4*4] @ b[4] |
|||
umlal r9, r10, r0, r14 @ d' += a[7] * b[5] |
|||
ldr r7, [r1, #8*4] @ a[8] |
|||
umlal r5, r6, r0, r8 @ d += a[7] * b[4] |
|||
ldr r14, [r2, #3*4] @ b[3] |
|||
umlal r9, r10, r7, r8 @ d' += a[8] * b[4] |
|||
ldr r0, [r1, #9*4] @ a[9] |
|||
umlal r5, r6, r7, r14 @ d += a[8] * b[3] |
|||
ldr r8, [r2, #2*4] @ b[2] |
|||
umlal r9, r10, r0, r14 @ d' += a[9] * b[3] |
|||
umlal r5, r6, r0, r8 @ d += a[9] * b[2] |
|||
|
|||
bic r0, r5, field_not_M @ u1 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u1 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
bic r14, r3, field_not_M @ t1 = c & M |
|||
str r14, [sp, #4 + 1*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u1 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* D */ |
|||
adds r3, r3, r11 @ c += c' |
|||
adc r4, r4, r12 |
|||
adds r5, r5, r9 @ d += d' |
|||
adc r6, r6, r10 |
|||
|
|||
bic r0, r5, field_not_M @ u2 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u2 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
bic r14, r3, field_not_M @ t2 = c & M |
|||
str r14, [sp, #4 + 2*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u2 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* E - interleaved with F */ |
|||
ldr r7, [r1, #0*4] @ a[0] |
|||
ldr r8, [r2, #4*4] @ b[4] |
|||
umull r11, r12, r7, r8 @ c' = a[0] * b[4] |
|||
ldr r8, [r2, #3*4] @ b[3] |
|||
umlal r3, r4, r7, r8 @ c += a[0] * b[3] |
|||
ldr r7, [r1, #1*4] @ a[1] |
|||
umlal r11, r12, r7, r8 @ c' += a[1] * b[3] |
|||
ldr r8, [r2, #2*4] @ b[2] |
|||
umlal r3, r4, r7, r8 @ c += a[1] * b[2] |
|||
ldr r7, [r1, #2*4] @ a[2] |
|||
umlal r11, r12, r7, r8 @ c' += a[2] * b[2] |
|||
ldr r8, [r2, #1*4] @ b[1] |
|||
umlal r3, r4, r7, r8 @ c += a[2] * b[1] |
|||
ldr r7, [r1, #3*4] @ a[3] |
|||
umlal r11, r12, r7, r8 @ c' += a[3] * b[1] |
|||
ldr r8, [r2, #0*4] @ b[0] |
|||
umlal r3, r4, r7, r8 @ c += a[3] * b[0] |
|||
ldr r7, [r1, #4*4] @ a[4] |
|||
umlal r11, r12, r7, r8 @ c' += a[4] * b[0] |
|||
ldr r8, [r2, #9*4] @ b[9] |
|||
umlal r5, r6, r7, r8 @ d += a[4] * b[9] |
|||
ldr r7, [r1, #5*4] @ a[5] |
|||
umull r9, r10, r7, r8 @ d' = a[5] * b[9] |
|||
ldr r8, [r2, #8*4] @ b[8] |
|||
umlal r5, r6, r7, r8 @ d += a[5] * b[8] |
|||
ldr r7, [r1, #6*4] @ a[6] |
|||
umlal r9, r10, r7, r8 @ d' += a[6] * b[8] |
|||
ldr r8, [r2, #7*4] @ b[7] |
|||
umlal r5, r6, r7, r8 @ d += a[6] * b[7] |
|||
ldr r7, [r1, #7*4] @ a[7] |
|||
umlal r9, r10, r7, r8 @ d' += a[7] * b[7] |
|||
ldr r8, [r2, #6*4] @ b[6] |
|||
umlal r5, r6, r7, r8 @ d += a[7] * b[6] |
|||
ldr r7, [r1, #8*4] @ a[8] |
|||
umlal r9, r10, r7, r8 @ d' += a[8] * b[6] |
|||
ldr r8, [r2, #5*4] @ b[5] |
|||
umlal r5, r6, r7, r8 @ d += a[8] * b[5] |
|||
ldr r7, [r1, #9*4] @ a[9] |
|||
umlal r9, r10, r7, r8 @ d' += a[9] * b[5] |
|||
ldr r8, [r2, #4*4] @ b[4] |
|||
umlal r5, r6, r7, r8 @ d += a[9] * b[4] |
|||
|
|||
bic r0, r5, field_not_M @ u3 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u3 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
bic r14, r3, field_not_M @ t3 = c & M |
|||
str r14, [sp, #4 + 3*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u3 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* F */ |
|||
adds r3, r3, r11 @ c += c' |
|||
adc r4, r4, r12 |
|||
adds r5, r5, r9 @ d += d' |
|||
adc r6, r6, r10 |
|||
|
|||
bic r0, r5, field_not_M @ u4 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u4 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
bic r14, r3, field_not_M @ t4 = c & M |
|||
str r14, [sp, #4 + 4*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u4 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* G - interleaved with H */ |
|||
ldr r7, [r1, #0*4] @ a[0] |
|||
ldr r8, [r2, #6*4] @ b[6] |
|||
ldr r14, [r2, #5*4] @ b[5] |
|||
umull r11, r12, r7, r8 @ c' = a[0] * b[6] |
|||
ldr r0, [r1, #1*4] @ a[1] |
|||
umlal r3, r4, r7, r14 @ c += a[0] * b[5] |
|||
ldr r8, [r2, #4*4] @ b[4] |
|||
umlal r11, r12, r0, r14 @ c' += a[1] * b[5] |
|||
ldr r7, [r1, #2*4] @ a[2] |
|||
umlal r3, r4, r0, r8 @ c += a[1] * b[4] |
|||
ldr r14, [r2, #3*4] @ b[3] |
|||
umlal r11, r12, r7, r8 @ c' += a[2] * b[4] |
|||
ldr r0, [r1, #3*4] @ a[3] |
|||
umlal r3, r4, r7, r14 @ c += a[2] * b[3] |
|||
ldr r8, [r2, #2*4] @ b[2] |
|||
umlal r11, r12, r0, r14 @ c' += a[3] * b[3] |
|||
ldr r7, [r1, #4*4] @ a[4] |
|||
umlal r3, r4, r0, r8 @ c += a[3] * b[2] |
|||
ldr r14, [r2, #1*4] @ b[1] |
|||
umlal r11, r12, r7, r8 @ c' += a[4] * b[2] |
|||
ldr r0, [r1, #5*4] @ a[5] |
|||
umlal r3, r4, r7, r14 @ c += a[4] * b[1] |
|||
ldr r8, [r2, #0*4] @ b[0] |
|||
umlal r11, r12, r0, r14 @ c' += a[5] * b[1] |
|||
ldr r7, [r1, #6*4] @ a[6] |
|||
umlal r3, r4, r0, r8 @ c += a[5] * b[0] |
|||
ldr r14, [r2, #9*4] @ b[9] |
|||
umlal r11, r12, r7, r8 @ c' += a[6] * b[0] |
|||
ldr r0, [r1, #7*4] @ a[7] |
|||
umlal r5, r6, r7, r14 @ d += a[6] * b[9] |
|||
ldr r8, [r2, #8*4] @ b[8] |
|||
umull r9, r10, r0, r14 @ d' = a[7] * b[9] |
|||
ldr r7, [r1, #8*4] @ a[8] |
|||
umlal r5, r6, r0, r8 @ d += a[7] * b[8] |
|||
ldr r14, [r2, #7*4] @ b[7] |
|||
umlal r9, r10, r7, r8 @ d' += a[8] * b[8] |
|||
ldr r0, [r1, #9*4] @ a[9] |
|||
umlal r5, r6, r7, r14 @ d += a[8] * b[7] |
|||
ldr r8, [r2, #6*4] @ b[6] |
|||
umlal r9, r10, r0, r14 @ d' += a[9] * b[7] |
|||
umlal r5, r6, r0, r8 @ d += a[9] * b[6] |
|||
|
|||
bic r0, r5, field_not_M @ u5 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u5 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
bic r14, r3, field_not_M @ t5 = c & M |
|||
str r14, [sp, #4 + 5*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u5 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* H */ |
|||
adds r3, r3, r11 @ c += c' |
|||
adc r4, r4, r12 |
|||
adds r5, r5, r9 @ d += d' |
|||
adc r6, r6, r10 |
|||
|
|||
bic r0, r5, field_not_M @ u6 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u6 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
bic r14, r3, field_not_M @ t6 = c & M |
|||
str r14, [sp, #4 + 6*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u6 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* I - interleaved with J */ |
|||
ldr r8, [r2, #8*4] @ b[8] |
|||
ldr r7, [r1, #0*4] @ a[0] |
|||
ldr r14, [r2, #7*4] @ b[7] |
|||
umull r11, r12, r7, r8 @ c' = a[0] * b[8] |
|||
ldr r0, [r1, #1*4] @ a[1] |
|||
umlal r3, r4, r7, r14 @ c += a[0] * b[7] |
|||
ldr r8, [r2, #6*4] @ b[6] |
|||
umlal r11, r12, r0, r14 @ c' += a[1] * b[7] |
|||
ldr r7, [r1, #2*4] @ a[2] |
|||
umlal r3, r4, r0, r8 @ c += a[1] * b[6] |
|||
ldr r14, [r2, #5*4] @ b[5] |
|||
umlal r11, r12, r7, r8 @ c' += a[2] * b[6] |
|||
ldr r0, [r1, #3*4] @ a[3] |
|||
umlal r3, r4, r7, r14 @ c += a[2] * b[5] |
|||
ldr r8, [r2, #4*4] @ b[4] |
|||
umlal r11, r12, r0, r14 @ c' += a[3] * b[5] |
|||
ldr r7, [r1, #4*4] @ a[4] |
|||
umlal r3, r4, r0, r8 @ c += a[3] * b[4] |
|||
ldr r14, [r2, #3*4] @ b[3] |
|||
umlal r11, r12, r7, r8 @ c' += a[4] * b[4] |
|||
ldr r0, [r1, #5*4] @ a[5] |
|||
umlal r3, r4, r7, r14 @ c += a[4] * b[3] |
|||
ldr r8, [r2, #2*4] @ b[2] |
|||
umlal r11, r12, r0, r14 @ c' += a[5] * b[3] |
|||
ldr r7, [r1, #6*4] @ a[6] |
|||
umlal r3, r4, r0, r8 @ c += a[5] * b[2] |
|||
ldr r14, [r2, #1*4] @ b[1] |
|||
umlal r11, r12, r7, r8 @ c' += a[6] * b[2] |
|||
ldr r0, [r1, #7*4] @ a[7] |
|||
umlal r3, r4, r7, r14 @ c += a[6] * b[1] |
|||
ldr r8, [r2, #0*4] @ b[0] |
|||
umlal r11, r12, r0, r14 @ c' += a[7] * b[1] |
|||
ldr r7, [r1, #8*4] @ a[8] |
|||
umlal r3, r4, r0, r8 @ c += a[7] * b[0] |
|||
ldr r14, [r2, #9*4] @ b[9] |
|||
umlal r11, r12, r7, r8 @ c' += a[8] * b[0] |
|||
ldr r0, [r1, #9*4] @ a[9] |
|||
umlal r5, r6, r7, r14 @ d += a[8] * b[9] |
|||
ldr r8, [r2, #8*4] @ b[8] |
|||
umull r9, r10, r0, r14 @ d' = a[9] * b[9] |
|||
umlal r5, r6, r0, r8 @ d += a[9] * b[8] |
|||
|
|||
bic r0, r5, field_not_M @ u7 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u7 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
bic r14, r3, field_not_M @ t7 = c & M |
|||
str r14, [sp, #4 + 7*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u7 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* J */ |
|||
adds r3, r3, r11 @ c += c' |
|||
adc r4, r4, r12 |
|||
adds r5, r5, r9 @ d += d' |
|||
adc r6, r6, r10 |
|||
|
|||
bic r0, r5, field_not_M @ u8 = d & M |
|||
str r0, [sp, #4 + 8*4] |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u8 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/****************************************** |
|||
* compute and write back result |
|||
****************************************** |
|||
Allocation: |
|||
r0 r |
|||
r3:r4 c |
|||
r5:r6 d |
|||
r7 t0 |
|||
r8 t1 |
|||
r9 t2 |
|||
r11 u8 |
|||
r12 t9 |
|||
r1,r2,r10,r14 scratch |
|||
|
|||
Note: do not read from a[] after here, it may overlap with r[] |
|||
*/ |
|||
ldr r0, [sp, #0] |
|||
add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 |
|||
ldmia r1, {r2,r7,r8,r9,r10,r11,r12} |
|||
add r1, r0, #3*4 |
|||
stmia r1, {r2,r7,r8,r9,r10} |
|||
|
|||
bic r2, r3, field_not_M @ r[8] = c & M |
|||
str r2, [r0, #8*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u8 * R1 |
|||
umlal r3, r4, r11, r14 |
|||
movw r14, field_R0 @ c += d * R0 |
|||
umlal r3, r4, r5, r14 |
|||
adds r3, r3, r12 @ c += t9 |
|||
adc r4, r4, #0 |
|||
|
|||
add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 |
|||
ldmia r1, {r7,r8,r9} |
|||
|
|||
ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) |
|||
str r2, [r0, #9*4] |
|||
mov r3, r3, lsr #22 @ c >>= 22 |
|||
orr r3, r3, r4, asl #10 |
|||
mov r4, r4, lsr #22 |
|||
movw r14, field_R1 << 4 @ c += d * (R1 << 4) |
|||
umlal r3, r4, r5, r14 |
|||
|
|||
movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) |
|||
umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) |
|||
adds r5, r5, r7 @ d.lo += t0 |
|||
mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) |
|||
adc r6, r6, 0 @ d.hi += carry |
|||
|
|||
bic r2, r5, field_not_M @ r[0] = d & M |
|||
str r2, [r0, #0*4] |
|||
|
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
|
|||
movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) |
|||
umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) |
|||
adds r5, r5, r8 @ d.lo += t1 |
|||
adc r6, r6, #0 @ d.hi += carry |
|||
adds r5, r5, r1 @ d.lo += tmp.lo |
|||
mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) |
|||
adc r6, r6, r2 @ d.hi += carry + tmp.hi |
|||
|
|||
bic r2, r5, field_not_M @ r[1] = d & M |
|||
str r2, [r0, #1*4] |
|||
mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) |
|||
orr r5, r5, r6, asl #6 |
|||
|
|||
add r5, r5, r9 @ d += t2 |
|||
str r5, [r0, #2*4] @ r[2] = d |
|||
|
|||
add sp, sp, #48 |
|||
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} |
|||
.size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner |
|||
|
|||
.align 2 |
|||
.global secp256k1_fe_sqr_inner |
|||
.type secp256k1_fe_sqr_inner, %function |
|||
@ Arguments: |
|||
@ r0 r Can overlap with a |
|||
@ r1 a |
|||
@ Stack (total 4+10*4 = 44) |
|||
@ sp + #0 saved 'r' pointer |
|||
@ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 |
|||
secp256k1_fe_sqr_inner: |
|||
stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} |
|||
sub sp, sp, #48 @ frame=44 + alignment |
|||
str r0, [sp, #0] @ save result address, we need it only at the end |
|||
/****************************************** |
|||
* Main computation code. |
|||
****************************************** |
|||
|
|||
Allocation: |
|||
r0,r14,r2,r7,r8 scratch |
|||
r1 a (pointer) |
|||
r3:r4 c |
|||
r5:r6 d |
|||
r11:r12 c' |
|||
r9:r10 d' |
|||
|
|||
Note: do not write to r[] here, it may overlap with a[] |
|||
*/ |
|||
/* A interleaved with B */ |
|||
ldr r0, [r1, #1*4] @ a[1]*2 |
|||
ldr r7, [r1, #0*4] @ a[0] |
|||
mov r0, r0, asl #1 |
|||
ldr r14, [r1, #9*4] @ a[9] |
|||
umull r3, r4, r7, r7 @ c = a[0] * a[0] |
|||
ldr r8, [r1, #8*4] @ a[8] |
|||
mov r7, r7, asl #1 |
|||
umull r5, r6, r7, r14 @ d = a[0]*2 * a[9] |
|||
ldr r7, [r1, #2*4] @ a[2]*2 |
|||
umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9] |
|||
ldr r14, [r1, #7*4] @ a[7] |
|||
umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8] |
|||
mov r7, r7, asl #1 |
|||
ldr r0, [r1, #3*4] @ a[3]*2 |
|||
umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8] |
|||
ldr r8, [r1, #6*4] @ a[6] |
|||
umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7] |
|||
mov r0, r0, asl #1 |
|||
ldr r7, [r1, #4*4] @ a[4]*2 |
|||
umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7] |
|||
ldr r14, [r1, #5*4] @ a[5] |
|||
mov r7, r7, asl #1 |
|||
umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6] |
|||
umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6] |
|||
umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5] |
|||
umlal r9, r10, r14, r14 @ d' += a[5] * a[5] |
|||
|
|||
bic r0, r5, field_not_M @ t9 = d & M |
|||
str r0, [sp, #4 + 9*4] |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
|
|||
/* B */ |
|||
adds r5, r5, r9 @ d += d' |
|||
adc r6, r6, r10 |
|||
|
|||
bic r0, r5, field_not_M @ u0 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u0 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
bic r14, r3, field_not_M @ t0 = c & M |
|||
str r14, [sp, #4 + 0*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u0 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* C interleaved with D */ |
|||
ldr r0, [r1, #0*4] @ a[0]*2 |
|||
ldr r14, [r1, #1*4] @ a[1] |
|||
mov r0, r0, asl #1 |
|||
ldr r8, [r1, #2*4] @ a[2] |
|||
umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1] |
|||
mov r7, r8, asl #1 @ a[2]*2 |
|||
umull r11, r12, r14, r14 @ c' = a[1] * a[1] |
|||
ldr r14, [r1, #9*4] @ a[9] |
|||
umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2] |
|||
ldr r0, [r1, #3*4] @ a[3]*2 |
|||
ldr r8, [r1, #8*4] @ a[8] |
|||
umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9] |
|||
mov r0, r0, asl #1 |
|||
ldr r7, [r1, #4*4] @ a[4]*2 |
|||
umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9] |
|||
ldr r14, [r1, #7*4] @ a[7] |
|||
umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8] |
|||
mov r7, r7, asl #1 |
|||
ldr r0, [r1, #5*4] @ a[5]*2 |
|||
umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8] |
|||
ldr r8, [r1, #6*4] @ a[6] |
|||
mov r0, r0, asl #1 |
|||
umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7] |
|||
umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7] |
|||
umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6] |
|||
umlal r9, r10, r8, r8 @ d' += a[6] * a[6] |
|||
|
|||
bic r0, r5, field_not_M @ u1 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u1 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
bic r14, r3, field_not_M @ t1 = c & M |
|||
str r14, [sp, #4 + 1*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u1 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* D */ |
|||
adds r3, r3, r11 @ c += c' |
|||
adc r4, r4, r12 |
|||
adds r5, r5, r9 @ d += d' |
|||
adc r6, r6, r10 |
|||
|
|||
bic r0, r5, field_not_M @ u2 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u2 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
bic r14, r3, field_not_M @ t2 = c & M |
|||
str r14, [sp, #4 + 2*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u2 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* E interleaved with F */ |
|||
ldr r7, [r1, #0*4] @ a[0]*2 |
|||
ldr r0, [r1, #1*4] @ a[1]*2 |
|||
ldr r14, [r1, #2*4] @ a[2] |
|||
mov r7, r7, asl #1 |
|||
ldr r8, [r1, #3*4] @ a[3] |
|||
ldr r2, [r1, #4*4] |
|||
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3] |
|||
mov r0, r0, asl #1 |
|||
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4] |
|||
mov r2, r2, asl #1 @ a[4]*2 |
|||
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3] |
|||
ldr r8, [r1, #9*4] @ a[9] |
|||
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2] |
|||
ldr r0, [r1, #5*4] @ a[5]*2 |
|||
umlal r11, r12, r14, r14 @ c' += a[2] * a[2] |
|||
ldr r14, [r1, #8*4] @ a[8] |
|||
mov r0, r0, asl #1 |
|||
umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9] |
|||
ldr r7, [r1, #6*4] @ a[6]*2 |
|||
umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9] |
|||
mov r7, r7, asl #1 |
|||
ldr r8, [r1, #7*4] @ a[7] |
|||
umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8] |
|||
umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8] |
|||
umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7] |
|||
umlal r9, r10, r8, r8 @ d' += a[7] * a[7] |
|||
|
|||
bic r0, r5, field_not_M @ u3 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u3 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
bic r14, r3, field_not_M @ t3 = c & M |
|||
str r14, [sp, #4 + 3*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u3 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* F */ |
|||
adds r3, r3, r11 @ c += c' |
|||
adc r4, r4, r12 |
|||
adds r5, r5, r9 @ d += d' |
|||
adc r6, r6, r10 |
|||
|
|||
bic r0, r5, field_not_M @ u4 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u4 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
bic r14, r3, field_not_M @ t4 = c & M |
|||
str r14, [sp, #4 + 4*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u4 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* G interleaved with H */ |
|||
ldr r7, [r1, #0*4] @ a[0]*2 |
|||
ldr r0, [r1, #1*4] @ a[1]*2 |
|||
mov r7, r7, asl #1 |
|||
ldr r8, [r1, #5*4] @ a[5] |
|||
ldr r2, [r1, #6*4] @ a[6] |
|||
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5] |
|||
ldr r14, [r1, #4*4] @ a[4] |
|||
mov r0, r0, asl #1 |
|||
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6] |
|||
ldr r7, [r1, #2*4] @ a[2]*2 |
|||
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5] |
|||
mov r7, r7, asl #1 |
|||
ldr r8, [r1, #3*4] @ a[3] |
|||
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4] |
|||
mov r0, r2, asl #1 @ a[6]*2 |
|||
umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4] |
|||
ldr r14, [r1, #9*4] @ a[9] |
|||
umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3] |
|||
ldr r7, [r1, #7*4] @ a[7]*2 |
|||
umlal r11, r12, r8, r8 @ c' += a[3] * a[3] |
|||
mov r7, r7, asl #1 |
|||
ldr r8, [r1, #8*4] @ a[8] |
|||
umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9] |
|||
umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9] |
|||
umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8] |
|||
umlal r9, r10, r8, r8 @ d' += a[8] * a[8] |
|||
|
|||
bic r0, r5, field_not_M @ u5 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u5 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
bic r14, r3, field_not_M @ t5 = c & M |
|||
str r14, [sp, #4 + 5*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u5 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* H */ |
|||
adds r3, r3, r11 @ c += c' |
|||
adc r4, r4, r12 |
|||
adds r5, r5, r9 @ d += d' |
|||
adc r6, r6, r10 |
|||
|
|||
bic r0, r5, field_not_M @ u6 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u6 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
bic r14, r3, field_not_M @ t6 = c & M |
|||
str r14, [sp, #4 + 6*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u6 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* I interleaved with J */ |
|||
ldr r7, [r1, #0*4] @ a[0]*2 |
|||
ldr r0, [r1, #1*4] @ a[1]*2 |
|||
mov r7, r7, asl #1 |
|||
ldr r8, [r1, #7*4] @ a[7] |
|||
ldr r2, [r1, #8*4] @ a[8] |
|||
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7] |
|||
ldr r14, [r1, #6*4] @ a[6] |
|||
mov r0, r0, asl #1 |
|||
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8] |
|||
ldr r7, [r1, #2*4] @ a[2]*2 |
|||
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7] |
|||
ldr r8, [r1, #5*4] @ a[5] |
|||
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6] |
|||
ldr r0, [r1, #3*4] @ a[3]*2 |
|||
mov r7, r7, asl #1 |
|||
umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6] |
|||
ldr r14, [r1, #4*4] @ a[4] |
|||
mov r0, r0, asl #1 |
|||
umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5] |
|||
mov r2, r2, asl #1 @ a[8]*2 |
|||
umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5] |
|||
umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4] |
|||
umlal r11, r12, r14, r14 @ c' += a[4] * a[4] |
|||
ldr r8, [r1, #9*4] @ a[9] |
|||
umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9] |
|||
@ r8 will be used in J |
|||
|
|||
bic r0, r5, field_not_M @ u7 = d & M |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u7 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
bic r14, r3, field_not_M @ t7 = c & M |
|||
str r14, [sp, #4 + 7*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u7 * R1 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/* J */ |
|||
adds r3, r3, r11 @ c += c' |
|||
adc r4, r4, r12 |
|||
umlal r5, r6, r8, r8 @ d += a[9] * a[9] |
|||
|
|||
bic r0, r5, field_not_M @ u8 = d & M |
|||
str r0, [sp, #4 + 8*4] |
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
movw r14, field_R0 @ c += u8 * R0 |
|||
umlal r3, r4, r0, r14 |
|||
|
|||
/****************************************** |
|||
* compute and write back result |
|||
****************************************** |
|||
Allocation: |
|||
r0 r |
|||
r3:r4 c |
|||
r5:r6 d |
|||
r7 t0 |
|||
r8 t1 |
|||
r9 t2 |
|||
r11 u8 |
|||
r12 t9 |
|||
r1,r2,r10,r14 scratch |
|||
|
|||
Note: do not read from a[] after here, it may overlap with r[] |
|||
*/ |
|||
ldr r0, [sp, #0] |
|||
add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 |
|||
ldmia r1, {r2,r7,r8,r9,r10,r11,r12} |
|||
add r1, r0, #3*4 |
|||
stmia r1, {r2,r7,r8,r9,r10} |
|||
|
|||
bic r2, r3, field_not_M @ r[8] = c & M |
|||
str r2, [r0, #8*4] |
|||
mov r3, r3, lsr #26 @ c >>= 26 |
|||
orr r3, r3, r4, asl #6 |
|||
mov r4, r4, lsr #26 |
|||
mov r14, field_R1 @ c += u8 * R1 |
|||
umlal r3, r4, r11, r14 |
|||
movw r14, field_R0 @ c += d * R0 |
|||
umlal r3, r4, r5, r14 |
|||
adds r3, r3, r12 @ c += t9 |
|||
adc r4, r4, #0 |
|||
|
|||
add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 |
|||
ldmia r1, {r7,r8,r9} |
|||
|
|||
ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) |
|||
str r2, [r0, #9*4] |
|||
mov r3, r3, lsr #22 @ c >>= 22 |
|||
orr r3, r3, r4, asl #10 |
|||
mov r4, r4, lsr #22 |
|||
movw r14, field_R1 << 4 @ c += d * (R1 << 4) |
|||
umlal r3, r4, r5, r14 |
|||
|
|||
movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) |
|||
umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) |
|||
adds r5, r5, r7 @ d.lo += t0 |
|||
mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) |
|||
adc r6, r6, 0 @ d.hi += carry |
|||
|
|||
bic r2, r5, field_not_M @ r[0] = d & M |
|||
str r2, [r0, #0*4] |
|||
|
|||
mov r5, r5, lsr #26 @ d >>= 26 |
|||
orr r5, r5, r6, asl #6 |
|||
mov r6, r6, lsr #26 |
|||
|
|||
movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) |
|||
umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) |
|||
adds r5, r5, r8 @ d.lo += t1 |
|||
adc r6, r6, #0 @ d.hi += carry |
|||
adds r5, r5, r1 @ d.lo += tmp.lo |
|||
mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) |
|||
adc r6, r6, r2 @ d.hi += carry + tmp.hi |
|||
|
|||
bic r2, r5, field_not_M @ r[1] = d & M |
|||
str r2, [r0, #1*4] |
|||
mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) |
|||
orr r5, r5, r6, asl #6 |
|||
|
|||
add r5, r5, r9 @ d += t2 |
|||
str r5, [r0, #2*4] @ r[2] = d |
|||
|
|||
add sp, sp, #48 |
|||
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} |
|||
.size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner |
|||
|
@ -0,0 +1,247 @@ |
|||
package org.bitcoin; |
|||
|
|||
import com.google.common.io.BaseEncoding; |
|||
import java.util.Arrays; |
|||
import java.math.BigInteger; |
|||
import javax.xml.bind.DatatypeConverter; |
|||
import static org.bitcoin.NativeSecp256k1Util.*; |
|||
|
|||
/** |
|||
* This class holds test cases defined for testing this library. |
|||
*/ |
|||
public class NativeSecp256k1Test { |
|||
|
|||
//TODO improve comments/add more tests
|
|||
/** |
|||
* This tests verify() for a valid signature |
|||
*/ |
|||
public static void testVerifyPos() throws AssertFailException{ |
|||
boolean result = false; |
|||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
|||
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); |
|||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); |
|||
|
|||
result = NativeSecp256k1.verify( data, sig, pub); |
|||
assertEquals( result, true , "testVerifyPos"); |
|||
} |
|||
|
|||
/** |
|||
* This tests verify() for a non-valid signature |
|||
*/ |
|||
public static void testVerifyNeg() throws AssertFailException{ |
|||
boolean result = false; |
|||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing"
|
|||
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); |
|||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); |
|||
|
|||
result = NativeSecp256k1.verify( data, sig, pub); |
|||
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
|||
assertEquals( result, false , "testVerifyNeg"); |
|||
} |
|||
|
|||
/** |
|||
* This tests secret key verify() for a valid secretkey |
|||
*/ |
|||
public static void testSecKeyVerifyPos() throws AssertFailException{ |
|||
boolean result = false; |
|||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
|||
|
|||
result = NativeSecp256k1.secKeyVerify( sec ); |
|||
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
|||
assertEquals( result, true , "testSecKeyVerifyPos"); |
|||
} |
|||
|
|||
/** |
|||
* This tests secret key verify() for a invalid secretkey |
|||
*/ |
|||
public static void testSecKeyVerifyNeg() throws AssertFailException{ |
|||
boolean result = false; |
|||
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); |
|||
|
|||
result = NativeSecp256k1.secKeyVerify( sec ); |
|||
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
|||
assertEquals( result, false , "testSecKeyVerifyNeg"); |
|||
} |
|||
|
|||
/** |
|||
* This tests public key create() for a valid secretkey |
|||
*/ |
|||
public static void testPubKeyCreatePos() throws AssertFailException{ |
|||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
|||
|
|||
byte[] resultArr = NativeSecp256k1.computePubkey( sec); |
|||
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
|||
assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos"); |
|||
} |
|||
|
|||
/** |
|||
* This tests public key create() for a invalid secretkey |
|||
*/ |
|||
public static void testPubKeyCreateNeg() throws AssertFailException{ |
|||
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); |
|||
|
|||
byte[] resultArr = NativeSecp256k1.computePubkey( sec); |
|||
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
|||
assertEquals( pubkeyString, "" , "testPubKeyCreateNeg"); |
|||
} |
|||
|
|||
/** |
|||
* This tests sign() for a valid secretkey |
|||
*/ |
|||
public static void testSignPos() throws AssertFailException{ |
|||
|
|||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
|||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
|||
|
|||
byte[] resultArr = NativeSecp256k1.sign(data, sec); |
|||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
|||
assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos"); |
|||
} |
|||
|
|||
/** |
|||
* This tests sign() for a invalid secretkey |
|||
*/ |
|||
public static void testSignNeg() throws AssertFailException{ |
|||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
|||
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); |
|||
|
|||
byte[] resultArr = NativeSecp256k1.sign(data, sec); |
|||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
|||
assertEquals( sigString, "" , "testSignNeg"); |
|||
} |
|||
|
|||
/** |
|||
* This tests private key tweak-add |
|||
*/ |
|||
public static void testPrivKeyTweakAdd_1() throws AssertFailException { |
|||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
|||
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
|||
|
|||
byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data ); |
|||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
|||
assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1"); |
|||
} |
|||
|
|||
/** |
|||
* This tests private key tweak-mul |
|||
*/ |
|||
public static void testPrivKeyTweakMul_1() throws AssertFailException { |
|||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
|||
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
|||
|
|||
byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data ); |
|||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
|||
assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1"); |
|||
} |
|||
|
|||
/** |
|||
* This tests private key tweak-add uncompressed |
|||
*/ |
|||
public static void testPrivKeyTweakAdd_2() throws AssertFailException { |
|||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); |
|||
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
|||
|
|||
byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data ); |
|||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
|||
assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2"); |
|||
} |
|||
|
|||
/** |
|||
* This tests private key tweak-mul uncompressed |
|||
*/ |
|||
public static void testPrivKeyTweakMul_2() throws AssertFailException { |
|||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); |
|||
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
|||
|
|||
byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data ); |
|||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
|||
assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2"); |
|||
} |
|||
|
|||
/** |
|||
* This tests seed randomization |
|||
*/ |
|||
public static void testRandomize() throws AssertFailException { |
|||
byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random"
|
|||
boolean result = NativeSecp256k1.randomize(seed); |
|||
assertEquals( result, true, "testRandomize"); |
|||
} |
|||
|
|||
/** |
|||
* This tests signSchnorr() for a valid secretkey |
|||
*/ |
|||
public static void testSchnorrSign() throws AssertFailException{ |
|||
|
|||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
|||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
|||
|
|||
byte[] resultArr = NativeSecp256k1.schnorrSign(data, sec); |
|||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
|||
assertEquals( sigString, "C5E929AA058B982048760422D3B563749B7D0E50C5EBD8CD2FFC23214BD6A2F1B072C13880997EBA847CF20F2F90FCE07C1CA33A890A4127095A351127F8D95F" , "testSchnorrSign"); |
|||
} |
|||
|
|||
/** |
|||
* This tests signSchnorr() for a valid secretkey |
|||
*/ |
|||
public static void testCreateECDHSecret() throws AssertFailException{ |
|||
|
|||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); |
|||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); |
|||
|
|||
byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub); |
|||
String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); |
|||
assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret"); |
|||
} |
|||
|
|||
public static void main(String[] args) throws AssertFailException{ |
|||
|
|||
|
|||
System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n"); |
|||
|
|||
assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" ); |
|||
|
|||
//Test verify() success/fail
|
|||
testVerifyPos(); |
|||
testVerifyNeg(); |
|||
|
|||
//Test secKeyVerify() success/fail
|
|||
testSecKeyVerifyPos(); |
|||
testSecKeyVerifyNeg(); |
|||
|
|||
//Test computePubkey() success/fail
|
|||
testPubKeyCreatePos(); |
|||
testPubKeyCreateNeg(); |
|||
|
|||
//Test sign() success/fail
|
|||
testSignPos(); |
|||
testSignNeg(); |
|||
|
|||
//Test Schnorr (partial support) //TODO
|
|||
testSchnorrSign(); |
|||
//testSchnorrVerify
|
|||
//testSchnorrRecovery
|
|||
|
|||
//Test privKeyTweakAdd() 1
|
|||
testPrivKeyTweakAdd_1(); |
|||
|
|||
//Test privKeyTweakMul() 2
|
|||
testPrivKeyTweakMul_1(); |
|||
|
|||
//Test privKeyTweakAdd() 3
|
|||
testPrivKeyTweakAdd_2(); |
|||
|
|||
//Test privKeyTweakMul() 4
|
|||
testPrivKeyTweakMul_2(); |
|||
|
|||
//Test randomize()
|
|||
testRandomize(); |
|||
|
|||
//Test ECDH
|
|||
testCreateECDHSecret(); |
|||
|
|||
NativeSecp256k1.cleanup(); |
|||
|
|||
System.out.println(" All tests passed." ); |
|||
|
|||
} |
|||
} |
@ -0,0 +1,29 @@ |
|||
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,35 @@ |
|||
package org.bitcoin; |
|||
|
|||
/** |
|||
* This class holds the context reference used in native methods |
|||
to handle ECDSA operations. |
|||
*/ |
|||
public class Secp256k1Context { |
|||
private static final boolean enabled; //true if the library is loaded
|
|||
private static final long context; //ref to pointer to context obj
|
|||
|
|||
static { //static initializer
|
|||
boolean isEnabled = true; |
|||
long contextRef = -1; |
|||
try { |
|||
System.loadLibrary("secp256k1"); |
|||
contextRef = secp256k1_init_context(); |
|||
} catch (UnsatisfiedLinkError e) { |
|||
System.out.println("UnsatisfiedLinkError: " + e.toString()); |
|||
isEnabled = false; |
|||
} |
|||
enabled = isEnabled; |
|||
context = contextRef; |
|||
} |
|||
|
|||
public static boolean isEnabled() { |
|||
return enabled; |
|||
} |
|||
|
|||
public static long getContext() { |
|||
if(!enabled) return -1; //sanity check
|
|||
return context; |
|||
} |
|||
|
|||
private static native long secp256k1_init_context(); |
|||
} |
@ -1,23 +1,411 @@ |
|||
#include <stdlib.h> |
|||
#include <stdint.h> |
|||
#include <string.h> |
|||
#include "org_bitcoin_NativeSecp256k1.h" |
|||
#include "include/secp256k1.h" |
|||
#include "include/secp256k1_ecdh.h" |
|||
#include "include/secp256k1_recovery.h" |
|||
#include "include/secp256k1_schnorr.h" |
|||
|
|||
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify |
|||
(JNIEnv* env, jclass classObject, jobject byteBufferObject) |
|||
|
|||
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone |
|||
(JNIEnv* env, jclass classObject, jlong ctx_l) |
|||
{ |
|||
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 @@ |
|||
#include <stdlib.h> |
|||
#include <stdint.h> |
|||
#include "org_bitcoin_Secp256k1Context.h" |
|||
#include "include/secp256k1.h" |
|||
|
|||
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context |
|||
(JNIEnv* env, jclass classObject) |
|||
{ |
|||
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); |
|||
|
|||
(void)classObject;(void)env; |
|||
|
|||
return (uintptr_t)ctx; |
|||
} |
|||
|
@ -0,0 +1,22 @@ |
|||
/* DO NOT EDIT THIS FILE - it is machine generated */ |
|||
#include <jni.h> |
|||
#include "include/secp256k1.h" |
|||
/* Header for class org_bitcoin_Secp256k1Context */ |
|||
|
|||
#ifndef _Included_org_bitcoin_Secp256k1Context |
|||
#define _Included_org_bitcoin_Secp256k1Context |
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
/*
|
|||
* Class: org_bitcoin_Secp256k1Context |
|||
* Method: secp256k1_init_context |
|||
* Signature: ()J |
|||
*/ |
|||
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context |
|||
(JNIEnv *, jclass); |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
#endif |
File diff suppressed because it is too large
Loading…
Reference in new issue