Squashed 'src/secp256k1/' changes from 0cbc860..9d560f9

9d560f9 Merge #428: Exhaustive recovery
2cee5fd exhaustive tests: add recovery module
8225239 Merge #433: Make the libcrypto detection fail the newer API.
12de863 Make the libcrypto detection fail the newer API.
678b0e5 exhaustive tests: remove erroneous comment from ecdsa_sig_sign
2928420 Merge #427: Remove Schnorr from travis as well
03ff8c2 group_impl.h: remove unused `secp256k1_ge_set_infinity` function
a724d72 configure: add --enable-coverage to set options for coverage analysis
b595163 recovery: add tests to cover API misusage
8eecc4a Remove Schnorr from travis as well
6f8ae2f ecdh: test NULL-checking of arguments
25e3cfb ecdsa_impl: replace scalar if-checks with VERIFY_CHECKs in ecdsa_sig_sign
a8abae7 Merge #310: Add exhaustive test for group functions on a low-order subgroup
b4ceedf Add exhaustive test for verification
83836a9 Add exhaustive tests for group arithmetic, signing, and ecmult on a small group
20b8877 Add exhaustive test for group functions on a low-order subgroup
80773a6 Merge #425: Remove Schnorr experiment
e06e878 Remove Schnorr experiment
04c8ef3 Merge #407: Modify parameter order of internal functions to match API parameter order
6e06696 Merge #411: Remove guarantees about memcmp-ability
40c8d7e Merge #421: Update scalar_4x64_impl.h
a922365 Merge #422: Restructure nonce clearing
3769783 Restructure nonce clearing
0f9e69d Restructure nonce clearing
9d67afa Update scalar_4x64_impl.h
7d15cd7 Merge #413: fix auto-enabled static precompuatation
00c5d2e fix auto-enabled static precompuatation
91219a1 Remove guarantees about memcmp-ability
7a49cac Merge #410: Add string.h include to ecmult_impl
0bbd5d4 Add string.h include to ecmult_impl
353c1bf Fix secp256k1_ge_set_table_gej_var parameter order
541b783 Fix secp256k1_ge_set_all_gej_var parameter order
7d893f4 Fix secp256k1_fe_inv_all_var parameter order
c5b32e1 Merge #405: Make secp256k1_fe_sqrt constant time
926836a Make secp256k1_fe_sqrt constant time
e2a8e92 Merge #404: Replace 3M + 4S doubling formula with 2M + 5S one
8ec49d8 Add note about 2M + 5S doubling formula
5a91bd7 Merge #400: A couple minor cleanups
ac01378 build: add -DSECP256K1_BUILD to benchmark_internal build flags
a6c6f99 Remove a bunch of unused stdlib #includes
65285a6 Merge #403: configure: add flag to disable OpenSSL tests
a9b2a5d configure: add flag to disable OpenSSL tests
b340123 Merge #402: Add support for testing quadratic residues
e6e9805 Add function for testing quadratic residue field/group elements.
efd953a Add Jacobi symbol test via GMP
fa36a0d Merge #401: ecmult_const: unify endomorphism and non-endomorphism skew cases
c6191fd ecmult_const: unify endomorphism and non-endomorphism skew cases
0b3e618 Merge #378: .gitignore build-aux cleanup
6042217 Merge #384: JNI: align shared files copyright/comments to bitcoinj's
24ad20f Merge #399: build: verify that the native compiler works for static precomp
b3be852 Merge #398: Test whether ECDH and Schnorr are enabled for JNI
aa0b1fd build: verify that the native compiler works for static precomp
eee808d Test whether ECDH and Schnorr are enabled for JNI
7b0fb18 Merge #366: ARM assembly implementation of field_10x26 inner (rebase of #173)
001f176 ARM assembly implementation of field_10x26 inner
0172be9 Merge #397: Small fixes for sha256
3f8b78e Fix undefs in hash_impl.h
2ab4695 Fix state size in sha256 struct
6875b01 Merge #386: Add some missing `VERIFY_CHECK(ctx != NULL)`
2c52b5d Merge #389: Cast pointers through uintptr_t under JNI
43097a4 Merge #390: Update bitcoin-core GitHub links
31c9c12 Merge #391: JNI: Only call ecdsa_verify if its inputs parsed correctly
1cb2302 Merge #392: Add testcase which hits additional branch in secp256k1_scalar_sqr
d2ee340 Merge #388: bench_ecdh: fix call to secp256k1_context_create
093a497 Add testcase which hits additional branch in secp256k1_scalar_sqr
a40c701 JNI: Only call ecdsa_verify if its inputs parsed correctly
faa2a11 Update bitcoin-core GitHub links
47b9e78 Cast pointers through uintptr_t under JNI
f36f9c6 bench_ecdh: fix call to secp256k1_context_create
bcc4881 Add some missing `VERIFY_CHECK(ctx != NULL)` for functions that use `ARG_CHECK`
6ceea2c align shared files copyright/comments to bitcoinj's
70141a8 Update .gitignore
7b549b1 Merge #373: build: fix x86_64 asm detection for some compilers
bc7c93c Merge #374: Add note about y=0 being possible on one of the sextic twists
e457018 Merge #364: JNI rebased
86e2d07 JNI library: cleanup, removed unimplemented code
3093576 JNI library
bd2895f Merge pull request #371
e72e93a Add note about y=0 being possible on one of the sextic twists
3f8fdfb build: fix x86_64 asm detection for some compilers
e5a9047 [Trivial] Remove double semicolons
c18b869 Merge pull request #360
3026daa Merge pull request #302
03d4611 Add sage verification script for the group laws
a965937 Merge pull request #361
83221ec Add experimental features to configure
5d4c5a3 Prevent damage_array in the signature test from going out of bounds.
419bf7f Merge pull request #356
6c527ec Merge pull request #357
445f7f1 Fix for Windows compile issue
03d84a4 Benchmark against OpenSSL verification
2bfb82b Merge pull request #351
06aeea5 Turn secp256k1_ec_pubkey_serialize outlen to in/out
970164d Merge pull request #348
64666251 Improvements for coordinate decompression
e2100ad Merge pull request #347
8e48787 Change secp256k1_ec_pubkey_combine's count argument to size_t.
c69dea0 Clear output in more cases for pubkey_combine, adds tests.
269d422 Comment copyediting.
b4d17da Merge pull request #344
4709265 Merge pull request #345
26abce7 Adds 32 static test vectors for scalar mul, sqr, inv.
5b71a3f Better error case handling for pubkey_create & pubkey_serialize, more tests.
3b7bc69 Merge pull request #343
eed87af Change contrib/laxder from headers-only to files compilable as standalone C
d7eb1ae Merge pull request #342
7914a6e Make lax_der_privatekey_parsing.h not depend on internal code
73f64ff Merge pull request #339
9234391 Overhaul flags handling
1a36898 Make flags more explicit, add runtime checks.
1a3e03a Merge pull request #340
96be204 Add additional tests for eckey and arg-checks.
bb5aa4d Make the tweak function zeroize-output-on-fail behavior consistent.
4a243da Move secp256k1_ec_privkey_import/export to contrib.
1b3efc1 Move secp256k1_ecdsa_sig_recover into the recovery module.
e3cd679 Eliminate all side-effects from VERIFY_CHECK() usage.
b30fc85 Avoid nonce_function_rfc6979 algo16 argument emulation.
70d4640 Make secp256k1_ec_pubkey_create skip processing invalid secret keys.
6c476a8 Minor comment improvements.
131afe5 Merge pull request #334
0c6ab2f Introduce explicit lower-S normalization
fea19e7 Add contrib/lax_der_parsing.h
3bb9c44 Rewrite ECDSA signature parsing code
fa57f1b Use secp256k1_rand_int and secp256k1_rand_bits more
49b3749 Add new tests for the extra testrand functions
f684d7d Faster secp256k1_rand_int implementation
251b1a6 Improve testrand: add extra random functions
31994c8 Merge pull request #338
f79aa88 Bugfix: swap arguments to noncefp
c98df26 Merge pull request #319
67f7da4 Extensive interface and operations tests for secp256k1_ec_pubkey_parse.
ee2cb40 Add ARG_CHECKs to secp256k1_ec_pubkey_parse/secp256k1_ec_pubkey_serialize
7450ef1 Merge pull request #328
68a3c76 Merge pull request #329
98135ee Merge pull request #332
37100d7 improve ECDH header-doc
b13d749 Fix couple of typos in API comments
7c823e3 travis: fixup module configs
cc3141a Merge pull request #325
ee58fae Merge pull request #326
213aa67 Do not force benchmarks to be statically linked.
338fc8b Add API exports to secp256k1_nonce_function_default and secp256k1_nonce_function_rfc6979.
52fd03f Merge pull request #320
9f6993f Remove some dead code.
357f8cd Merge pull request #314
118cd82 Use explicit symbol visibility.
4e64608 Include public module headers when compiling modules.
1f41437 Merge pull request #316
fe0d463 Merge pull request #317
cfe0ed9 Fix miscellaneous style nits that irritate overactive static analysis.
2b199de Use the explicit NULL macro for pointer comparisons.
9e90516 Merge pull request #294
dd891e0 Get rid of _t as it is POSIX reserved
201819b Merge pull request #313
912f203 Eliminate a few unbraced statements that crept into the code.
eeab823 Merge pull request #299
486b9bb Use a flags bitfield for compressed option to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export
05732c5 Callback data: Accept pointers to either const or non-const data
1973c73 Bugfix: Reinitialise buffer lengths that have been used as outputs
788038d Use size_t for lengths (at least in external API)
c9d7c2a secp256k1_context_set_{error,illegal}_callback: Restore default handler by passing NULL as function argument
9aac008 secp256k1_context_destroy: Allow NULL argument as a no-op
64b730b secp256k1_context_create: Use unsigned type for flags bitfield
cb04ab5 Merge pull request #309
a551669 Merge pull request #295
81e45ff Update group_impl.h
85e3a2c Merge pull request #112
b2eb63b Merge pull request #293
dc0ce9f [API BREAK] Change argument order to out/outin/in
6d947ca Merge pull request #298
c822693 Merge pull request #301
6d04350 Merge pull request #303
7ab311c Merge pull request #304
5fb3229 Fixes a bug where bench_sign would fail due to passing in too small a buffer.
263dcbc remove unused assignment
b183b41 bugfix: "ARG_CHECK(ctx != NULL)" makes no sense
6da1446 build: fix parallel build
5eb4356 Merge pull request #291
c996d53 Print success
9f443be Move pubkey recovery code to separate module
d49abbd Separate ECDSA recovery tests
439d34a Separate recoverable and normal signatures
a7b046e Merge pull request #289
f66907f Improve/reformat API documentation secp256k1.h
2f77487 Add context building benchmarks
cc623d5 Merge pull request #287
de7e398 small typo fix
9d96e36 Merge pull request #280
432e1ce Merge pull request #283
14727fd Use correct name in gitignore
356b0e9 Actually test static precomputation in Travis
ff3a5df Merge pull request #284
2587208 Merge pull request #212
a5a66c7 Add support for custom EC-Schnorr-SHA256 signatures
d84a378 Merge pull request #252
72ae443 Improve perf. of cmov-based table lookup
92e53fc Implement endomorphism optimization for secp256k1_ecmult_const
ed35d43 Make `secp256k1_scalar_add_bit` conditional; make `secp256k1_scalar_split_lambda_var` constant time
91c0ce9 Add benchmarks for ECDH and const-time multiplication
0739bbb Add ECDH module which works by hashing the output of ecmult_const
4401500 Add constant-time multiply `secp256k1_ecmult_const` for ECDH
e4ce393 build: fix hard-coded usage of "gen_context"
b8e39ac build: don't use BUILT_SOURCES for the static context header
baa75da tests: add a couple tests
ae4f0c6 Merge pull request #278
995c548 Introduce callback functions for dealing with errors.
c333074 Merge pull request #282
18c329c Remove the internal secp256k1_ecdsa_sig_t type
74a2acd Add a secp256k1_ecdsa_signature_t type
23cfa91 Introduce secp256k1_pubkey_t type
4c63780 Merge pull request #269
3e6f1e2 Change rfc6979 implementation to be a generic PRNG
ed5334a Update configure.ac to make it build on OpenBSD
1b68366 Merge pull request #274
a83bb48 Make ecmult static precomputation default
166b32f Merge pull request #276
c37812f Add gen_context src/ecmult_static_context.h to CLEANFILES to fix distclean.
125c15d Merge pull request #275
76f6769 Fix build with static ecmult altroot and make dist.
5133f78 Merge pull request #254
b0a60e6 Merge pull request #258
733c1e6 Add travis build to test the static context.
fbecc38 Add ability to use a statically generated ecmult context.
4fb174d Merge pull request #263
4ab8990 Merge pull request #270
bdf0e0c Merge pull request #271
31d0c1f Merge pull request #273
eb2c8ff Add missing casts to SECP256K1_FE_CONST_INNER
55399c2 Further performance improvements to _ecmult_wnaf
99fd963 Add secp256k1_ec_pubkey_compress(), with test similar to the related decompress() function.
145cc6e Improve performance of _ecmult_wnaf
36b305a Verify the result of GMP modular inverse using non-GMP code
e2a07c7 Fix compilation with C++
2b4cf41 Use pkg-config always when possible, with failover to manual checks for libcrypto

git-subtree-dir: src/secp256k1
git-subtree-split: 9d560f992db26612ce2630b194aef5f44d63a530
This commit is contained in:
Vinnie Falco
2017-02-01 12:36:05 -05:00
parent 94f13fb606
commit a1a8ba7f53
81 changed files with 11200 additions and 2069 deletions

View File

@@ -0,0 +1,8 @@
include_HEADERS += include/secp256k1_ecdh.h
noinst_HEADERS += src/modules/ecdh/main_impl.h
noinst_HEADERS += src/modules/ecdh/tests_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_ecdh
bench_ecdh_SOURCES = src/bench_ecdh.c
bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif

View File

@@ -0,0 +1,54 @@
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_MODULE_ECDH_MAIN_
#define _SECP256K1_MODULE_ECDH_MAIN_
#include "include/secp256k1_ecdh.h"
#include "ecmult_const_impl.h"
int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) {
int ret = 0;
int overflow = 0;
secp256k1_gej res;
secp256k1_ge pt;
secp256k1_scalar s;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(result != NULL);
ARG_CHECK(point != NULL);
ARG_CHECK(scalar != NULL);
secp256k1_pubkey_load(ctx, &pt, point);
secp256k1_scalar_set_b32(&s, scalar, &overflow);
if (overflow || secp256k1_scalar_is_zero(&s)) {
ret = 0;
} else {
unsigned char x[32];
unsigned char y[1];
secp256k1_sha256_t sha;
secp256k1_ecmult_const(&res, &pt, &s);
secp256k1_ge_set_gej(&pt, &res);
/* Compute a hash of the point in compressed form
* Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not
* expect its output to be secret and has a timing sidechannel. */
secp256k1_fe_normalize(&pt.x);
secp256k1_fe_normalize(&pt.y);
secp256k1_fe_get_b32(x, &pt.x);
y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y);
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, y, sizeof(y));
secp256k1_sha256_write(&sha, x, sizeof(x));
secp256k1_sha256_finalize(&sha, result);
ret = 1;
}
secp256k1_scalar_clear(&s);
return ret;
}
#endif

View File

@@ -0,0 +1,105 @@
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_MODULE_ECDH_TESTS_
#define _SECP256K1_MODULE_ECDH_TESTS_
void test_ecdh_api(void) {
/* Setup context that just counts errors */
secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_pubkey point;
unsigned char res[32];
unsigned char s_one[32] = { 0 };
int32_t ecount = 0;
s_one[31] = 1;
secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount);
CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
/* Check all NULLs are detected */
CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
CHECK(ecount == 3);
/* Cleanup */
secp256k1_context_destroy(tctx);
}
void test_ecdh_generator_basepoint(void) {
unsigned char s_one[32] = { 0 };
secp256k1_pubkey point[2];
int i;
s_one[31] = 1;
/* Check against pubkey creation when the basepoint is the generator */
for (i = 0; i < 100; ++i) {
secp256k1_sha256_t sha;
unsigned char s_b32[32];
unsigned char output_ecdh[32];
unsigned char output_ser[32];
unsigned char point_ser[33];
size_t point_ser_len = sizeof(point_ser);
secp256k1_scalar s;
random_scalar_order(&s);
secp256k1_scalar_get_b32(s_b32, &s);
/* compute using ECDH function */
CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1);
CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1);
/* compute "explicitly" */
CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1);
CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1);
CHECK(point_ser_len == sizeof(point_ser));
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, point_ser, point_ser_len);
secp256k1_sha256_finalize(&sha, output_ser);
/* compare */
CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0);
}
}
void test_bad_scalar(void) {
unsigned char s_zero[32] = { 0 };
unsigned char s_overflow[32] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41
};
unsigned char s_rand[32] = { 0 };
unsigned char output[32];
secp256k1_scalar rand;
secp256k1_pubkey point;
/* Create random point */
random_scalar_order(&rand);
secp256k1_scalar_get_b32(s_rand, &rand);
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1);
/* Try to multiply it by bad values */
CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0);
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0);
/* ...and a good one */
s_overflow[31] -= 1;
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1);
}
void run_ecdh_tests(void) {
test_ecdh_api();
test_ecdh_generator_basepoint();
test_bad_scalar();
}
#endif

View File

@@ -0,0 +1,8 @@
include_HEADERS += include/secp256k1_recovery.h
noinst_HEADERS += src/modules/recovery/main_impl.h
noinst_HEADERS += src/modules/recovery/tests_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_recover
bench_recover_SOURCES = src/bench_recover.c
bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif

193
src/modules/recovery/main_impl.h Executable file
View File

@@ -0,0 +1,193 @@
/**********************************************************************
* Copyright (c) 2013-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_MODULE_RECOVERY_MAIN_
#define _SECP256K1_MODULE_RECOVERY_MAIN_
#include "include/secp256k1_recovery.h"
static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) {
(void)ctx;
if (sizeof(secp256k1_scalar) == 32) {
/* When the secp256k1_scalar type is exactly 32 byte, use its
* representation inside secp256k1_ecdsa_signature, as conversion is very fast.
* Note that secp256k1_ecdsa_signature_save must use the same representation. */
memcpy(r, &sig->data[0], 32);
memcpy(s, &sig->data[32], 32);
} else {
secp256k1_scalar_set_b32(r, &sig->data[0], NULL);
secp256k1_scalar_set_b32(s, &sig->data[32], NULL);
}
*recid = sig->data[64];
}
static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s, int recid) {
if (sizeof(secp256k1_scalar) == 32) {
memcpy(&sig->data[0], r, 32);
memcpy(&sig->data[32], s, 32);
} else {
secp256k1_scalar_get_b32(&sig->data[0], r);
secp256k1_scalar_get_b32(&sig->data[32], s);
}
sig->data[64] = recid;
}
int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) {
secp256k1_scalar r, s;
int ret = 1;
int overflow = 0;
(void)ctx;
ARG_CHECK(sig != NULL);
ARG_CHECK(input64 != NULL);
ARG_CHECK(recid >= 0 && recid <= 3);
secp256k1_scalar_set_b32(&r, &input64[0], &overflow);
ret &= !overflow;
secp256k1_scalar_set_b32(&s, &input64[32], &overflow);
ret &= !overflow;
if (ret) {
secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid);
} else {
memset(sig, 0, sizeof(*sig));
}
return ret;
}
int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig) {
secp256k1_scalar r, s;
(void)ctx;
ARG_CHECK(output64 != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(recid != NULL);
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig);
secp256k1_scalar_get_b32(&output64[0], &r);
secp256k1_scalar_get_b32(&output64[32], &s);
return 1;
}
int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const secp256k1_ecdsa_recoverable_signature* sigin) {
secp256k1_scalar r, s;
int recid;
(void)ctx;
ARG_CHECK(sig != NULL);
ARG_CHECK(sigin != NULL);
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin);
secp256k1_ecdsa_signature_save(sig, &r, &s);
return 1;
}
static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) {
unsigned char brx[32];
secp256k1_fe fx;
secp256k1_ge x;
secp256k1_gej xj;
secp256k1_scalar rn, u1, u2;
secp256k1_gej qj;
int r;
if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {
return 0;
}
secp256k1_scalar_get_b32(brx, sigr);
r = secp256k1_fe_set_b32(&fx, brx);
(void)r;
VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */
if (recid & 2) {
if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
return 0;
}
secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe);
}
if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) {
return 0;
}
secp256k1_gej_set_ge(&xj, &x);
secp256k1_scalar_inverse_var(&rn, sigr);
secp256k1_scalar_mul(&u1, &rn, message);
secp256k1_scalar_negate(&u1, &u1);
secp256k1_scalar_mul(&u2, &rn, sigs);
secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1);
secp256k1_ge_set_gej_var(pubkey, &qj);
return !secp256k1_gej_is_infinity(&qj);
}
int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
secp256k1_scalar r, s;
secp256k1_scalar sec, non, msg;
int recid;
int ret = 0;
int overflow = 0;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(msg32 != NULL);
ARG_CHECK(signature != NULL);
ARG_CHECK(seckey != NULL);
if (noncefp == NULL) {
noncefp = secp256k1_nonce_function_default;
}
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
/* Fail if the secret key is invalid. */
if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
unsigned char nonce32[32];
unsigned int count = 0;
secp256k1_scalar_set_b32(&msg, msg32, NULL);
while (1) {
ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
if (!ret) {
break;
}
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
if (!secp256k1_scalar_is_zero(&non) && !overflow) {
if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) {
break;
}
}
count++;
}
memset(nonce32, 0, 32);
secp256k1_scalar_clear(&msg);
secp256k1_scalar_clear(&non);
secp256k1_scalar_clear(&sec);
}
if (ret) {
secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);
} else {
memset(signature, 0, sizeof(*signature));
}
return ret;
}
int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32) {
secp256k1_ge q;
secp256k1_scalar r, s;
secp256k1_scalar m;
int recid;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(msg32 != NULL);
ARG_CHECK(signature != NULL);
ARG_CHECK(pubkey != NULL);
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature);
VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */
secp256k1_scalar_set_b32(&m, msg32, NULL);
if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) {
secp256k1_pubkey_save(pubkey, &q);
return 1;
} else {
memset(pubkey, 0, sizeof(*pubkey));
return 0;
}
}
#endif

View File

@@ -0,0 +1,393 @@
/**********************************************************************
* Copyright (c) 2013-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_
#define _SECP256K1_MODULE_RECOVERY_TESTS_
static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
(void) msg32;
(void) key32;
(void) algo16;
(void) data;
/* On the first run, return 0 to force a second run */
if (counter == 0) {
memset(nonce32, 0, 32);
return 1;
}
/* On the second run, return an overflow to force a third run */
if (counter == 1) {
memset(nonce32, 0xff, 32);
return 1;
}
/* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */
memset(nonce32, 1, 32);
return secp256k1_rand_bits(1);
}
void test_ecdsa_recovery_api(void) {
/* Setup contexts that just count errors */
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
secp256k1_pubkey pubkey;
secp256k1_pubkey recpubkey;
secp256k1_ecdsa_signature normal_sig;
secp256k1_ecdsa_recoverable_signature recsig;
unsigned char privkey[32] = { 1 };
unsigned char message[32] = { 2 };
int32_t ecount = 0;
int recid = 0;
unsigned char sig[74];
unsigned char zero_privkey[32] = { 0 };
unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
/* Construct and verify corresponding public key. */
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
/* Check bad contexts and NULLs for signing */
ecount = 0;
CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0);
CHECK(ecount == 5);
/* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */
secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL);
CHECK(ecount == 5);
/* These will all fail, but not in ARG_CHECK way */
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0);
/* This one will succeed. */
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(ecount == 5);
/* Check signing with a goofy nonce function */
/* Check bad contexts and NULLs for recovery */
ecount = 0;
CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0);
CHECK(ecount == 5);
/* Check NULLs for conversion */
CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1);
ecount = 0;
CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1);
/* Check NULLs for de/serialization */
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
ecount = 0;
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0);
CHECK(ecount == 7);
/* overflow in signature will fail but not affect ecount */
memcpy(sig, over_privkey, 32);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0);
CHECK(ecount == 7);
/* cleanup */
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(vrfy);
secp256k1_context_destroy(both);
}
void test_ecdsa_recovery_end_to_end(void) {
unsigned char extra[32] = {0x00};
unsigned char privkey[32];
unsigned char message[32];
secp256k1_ecdsa_signature signature[5];
secp256k1_ecdsa_recoverable_signature rsignature[5];
unsigned char sig[74];
secp256k1_pubkey pubkey;
secp256k1_pubkey recpubkey;
int recid = 0;
/* Generate a random key and message. */
{
secp256k1_scalar msg, key;
random_scalar_order_test(&msg);
random_scalar_order_test(&key);
secp256k1_scalar_get_b32(privkey, &key);
secp256k1_scalar_get_b32(message, &msg);
}
/* Construct and verify corresponding public key. */
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
/* Serialize/parse compact and verify/recover. */
extra[0] = 0;
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1);
CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1);
extra[31] = 1;
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1);
extra[31] = 0;
extra[0] = 1;
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
CHECK(memcmp(&signature[4], &signature[0], 64) == 0);
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);
memset(&rsignature[4], 0, sizeof(rsignature[4]));
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);
/* Parse compact (with recovery id) and recover. */
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1);
CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
/* Serialize/destroy/parse signature and verify again. */
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0);
/* Recover again */
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 ||
memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
}
/* Tests several edge cases. */
void test_ecdsa_recovery_edge_cases(void) {
const unsigned char msg32[32] = {
'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
'a', ' ', 'v', 'e', 'r', 'y', ' ', 's',
'e', 'c', 'r', 'e', 't', ' ', 'm', 'e',
's', 's', 'a', 'g', 'e', '.', '.', '.'
};
const unsigned char sig64[64] = {
/* Generated by signing the above message with nonce 'This is the nonce we will use...'
* and secret key 0 (which is not valid), resulting in recid 0. */
0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8,
0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96,
0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63,
0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32,
0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E,
0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD,
0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86,
0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57
};
secp256k1_pubkey pubkey;
/* signature (r,s) = (4,4), which can be recovered with all 4 recids. */
const unsigned char sigb64[64] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
};
secp256k1_pubkey pubkeyb;
secp256k1_ecdsa_recoverable_signature rsig;
secp256k1_ecdsa_signature sig;
int recid;
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0));
CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1));
CHECK(secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2));
CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3));
CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
for (recid = 0; recid < 4; recid++) {
int i;
int recid2;
/* (4,4) encoded in DER. */
unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04};
unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01};
unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00};
unsigned char sigbderalt1[39] = {
0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04,
};
unsigned char sigbderalt2[39] = {
0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
};
unsigned char sigbderalt3[40] = {
0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04,
};
unsigned char sigbderalt4[40] = {
0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
};
/* (order + r,4) encoded in DER. */
unsigned char sigbderlong[40] = {
0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC,
0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E,
0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04
};
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);
for (recid2 = 0; recid2 < 4; recid2++) {
secp256k1_pubkey pubkey2b;
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1);
/* Verifying with (order + r,4) should always fail. */
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
}
/* DER parsing tests. */
/* Zero length r/s. */
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0);
/* Leading zeros. */
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0);
sigbderalt3[4] = 1;
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
sigbderalt4[7] = 1;
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
/* Damage signature. */
sigbder[7]++;
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
sigbder[7]--;
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0);
for(i = 0; i < 8; i++) {
int c;
unsigned char orig = sigbder[i];
/*Try every single-byte change.*/
for (c = 0; c < 256; c++) {
if (c == orig ) {
continue;
}
sigbder[i] = c;
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
}
sigbder[i] = orig;
}
}
/* Test r/s equal to zero */
{
/* (1,1) encoded in DER. */
unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01};
unsigned char sigc64[64] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
};
secp256k1_pubkey pubkeyc;
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1);
sigcder[4] = 0;
sigc64[31] = 0;
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0);
sigcder[4] = 1;
sigcder[7] = 0;
sigc64[31] = 1;
sigc64[63] = 0;
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0);
}
}
void run_recovery_tests(void) {
int i;
for (i = 0; i < count; i++) {
test_ecdsa_recovery_api();
}
for (i = 0; i < 64*count; i++) {
test_ecdsa_recovery_end_to_end();
}
test_ecdsa_recovery_edge_cases();
}
#endif