Merge pull request #78 from rust-bitcoin/2018-11-remove-without-caps
Update upstream libsecp; remove `without_caps` and all use of dummy contexts
This commit is contained in:
commit
4b88cfc2fc
|
@ -179,6 +179,13 @@ typedef int (*secp256k1_nonce_function)(
|
||||||
#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06
|
#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06
|
||||||
#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07
|
#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07
|
||||||
|
|
||||||
|
/** A simple secp256k1 context object with no precomputed tables. These are useful for
|
||||||
|
* type serialization/parsing functions which require a context object to maintain
|
||||||
|
* API consistency, but currently do not require expensive precomputations or dynamic
|
||||||
|
* allocations.
|
||||||
|
*/
|
||||||
|
SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp;
|
||||||
|
|
||||||
/** Create a secp256k1 context object.
|
/** Create a secp256k1 context object.
|
||||||
*
|
*
|
||||||
* Returns: a newly created context object.
|
* Returns: a newly created context object.
|
||||||
|
|
|
@ -7,21 +7,45 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** A pointer to a function that applies hash function to a point
|
||||||
|
*
|
||||||
|
* Returns: 1 if a point was successfully hashed. 0 will cause ecdh to fail
|
||||||
|
* Out: output: pointer to an array to be filled by the function
|
||||||
|
* In: x: pointer to a 32-byte x coordinate
|
||||||
|
* y: pointer to a 32-byte y coordinate
|
||||||
|
* data: Arbitrary data pointer that is passed through
|
||||||
|
*/
|
||||||
|
typedef int (*secp256k1_ecdh_hash_function)(
|
||||||
|
unsigned char *output,
|
||||||
|
const unsigned char *x,
|
||||||
|
const unsigned char *y,
|
||||||
|
void *data
|
||||||
|
);
|
||||||
|
|
||||||
|
/** An implementation of SHA256 hash function that applies to compressed public key. */
|
||||||
|
SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
|
||||||
|
|
||||||
|
/** A default ecdh hash function (currently equal to secp256k1_ecdh_hash_function_sha256). */
|
||||||
|
SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
|
||||||
|
|
||||||
/** Compute an EC Diffie-Hellman secret in constant time
|
/** Compute an EC Diffie-Hellman secret in constant time
|
||||||
* Returns: 1: exponentiation was successful
|
* Returns: 1: exponentiation was successful
|
||||||
* 0: scalar was invalid (zero or overflow)
|
* 0: scalar was invalid (zero or overflow)
|
||||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||||
* Out: result: a 32-byte array which will be populated by an ECDH
|
* Out: output: pointer to an array to be filled by the function
|
||||||
* secret computed from the point and scalar
|
|
||||||
* In: pubkey: a pointer to a secp256k1_pubkey containing an
|
* In: pubkey: a pointer to a secp256k1_pubkey containing an
|
||||||
* initialized public key
|
* initialized public key
|
||||||
* privkey: a 32-byte scalar with which to multiply the point
|
* privkey: a 32-byte scalar with which to multiply the point
|
||||||
|
* hashfp: pointer to a hash function. If NULL, secp256k1_ecdh_hash_function_sha256 is used
|
||||||
|
* data: Arbitrary data pointer that is passed through
|
||||||
*/
|
*/
|
||||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
|
||||||
const secp256k1_context* ctx,
|
const secp256k1_context* ctx,
|
||||||
unsigned char *result,
|
unsigned char *output,
|
||||||
const secp256k1_pubkey *pubkey,
|
const secp256k1_pubkey *pubkey,
|
||||||
const unsigned char *privkey
|
const unsigned char *privkey,
|
||||||
|
secp256k1_ecdh_hash_function hashfp,
|
||||||
|
void *data
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -42,7 +42,7 @@ static void bench_ecdh(void* arg) {
|
||||||
bench_ecdh_data *data = (bench_ecdh_data*)arg;
|
bench_ecdh_data *data = (bench_ecdh_data*)arg;
|
||||||
|
|
||||||
for (i = 0; i < 20000; i++) {
|
for (i = 0; i < 20000; i++) {
|
||||||
CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1);
|
CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
|
||||||
|
|
||||||
secp256k1_ecdsa_signature sig[72];
|
secp256k1_ecdsa_signature sig[72];
|
||||||
|
|
||||||
int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL );
|
int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL);
|
||||||
|
|
||||||
unsigned char outputSer[72];
|
unsigned char outputSer[72];
|
||||||
size_t outputLen = 72;
|
size_t outputLen = 72;
|
||||||
|
@ -353,7 +353,9 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
|
||||||
ctx,
|
ctx,
|
||||||
nonce_res,
|
nonce_res,
|
||||||
&pubkey,
|
&pubkey,
|
||||||
secdata
|
secdata,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,16 +10,35 @@
|
||||||
#include "include/secp256k1_ecdh.h"
|
#include "include/secp256k1_ecdh.h"
|
||||||
#include "ecmult_const_impl.h"
|
#include "ecmult_const_impl.h"
|
||||||
|
|
||||||
int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) {
|
static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
|
||||||
|
unsigned char version = (y[31] & 0x01) | 0x02;
|
||||||
|
secp256k1_sha256 sha;
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
secp256k1_sha256_initialize(&sha);
|
||||||
|
secp256k1_sha256_write(&sha, &version, 1);
|
||||||
|
secp256k1_sha256_write(&sha, x, 32);
|
||||||
|
secp256k1_sha256_finalize(&sha, output);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256;
|
||||||
|
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256;
|
||||||
|
|
||||||
|
int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pubkey *point, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int overflow = 0;
|
int overflow = 0;
|
||||||
secp256k1_gej res;
|
secp256k1_gej res;
|
||||||
secp256k1_ge pt;
|
secp256k1_ge pt;
|
||||||
secp256k1_scalar s;
|
secp256k1_scalar s;
|
||||||
VERIFY_CHECK(ctx != NULL);
|
VERIFY_CHECK(ctx != NULL);
|
||||||
ARG_CHECK(result != NULL);
|
ARG_CHECK(output != NULL);
|
||||||
ARG_CHECK(point != NULL);
|
ARG_CHECK(point != NULL);
|
||||||
ARG_CHECK(scalar != NULL);
|
ARG_CHECK(scalar != NULL);
|
||||||
|
if (hashfp == NULL) {
|
||||||
|
hashfp = secp256k1_ecdh_hash_function_default;
|
||||||
|
}
|
||||||
|
|
||||||
secp256k1_pubkey_load(ctx, &pt, point);
|
secp256k1_pubkey_load(ctx, &pt, point);
|
||||||
secp256k1_scalar_set_b32(&s, scalar, &overflow);
|
secp256k1_scalar_set_b32(&s, scalar, &overflow);
|
||||||
|
@ -27,24 +46,18 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
unsigned char x[32];
|
unsigned char x[32];
|
||||||
unsigned char y[1];
|
unsigned char y[32];
|
||||||
secp256k1_sha256 sha;
|
|
||||||
|
|
||||||
secp256k1_ecmult_const(&res, &pt, &s, 256);
|
secp256k1_ecmult_const(&res, &pt, &s, 256);
|
||||||
secp256k1_ge_set_gej(&pt, &res);
|
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
|
/* Compute a hash of the point */
|
||||||
* expect its output to be secret and has a timing sidechannel. */
|
|
||||||
secp256k1_fe_normalize(&pt.x);
|
secp256k1_fe_normalize(&pt.x);
|
||||||
secp256k1_fe_normalize(&pt.y);
|
secp256k1_fe_normalize(&pt.y);
|
||||||
secp256k1_fe_get_b32(x, &pt.x);
|
secp256k1_fe_get_b32(x, &pt.x);
|
||||||
y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y);
|
secp256k1_fe_get_b32(y, &pt.y);
|
||||||
|
|
||||||
secp256k1_sha256_initialize(&sha);
|
ret = hashfp(output, x, y, data);
|
||||||
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);
|
secp256k1_scalar_clear(&s);
|
||||||
|
|
|
@ -7,6 +7,23 @@
|
||||||
#ifndef SECP256K1_MODULE_ECDH_TESTS_H
|
#ifndef SECP256K1_MODULE_ECDH_TESTS_H
|
||||||
#define SECP256K1_MODULE_ECDH_TESTS_H
|
#define SECP256K1_MODULE_ECDH_TESTS_H
|
||||||
|
|
||||||
|
int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
|
||||||
|
(void)output;
|
||||||
|
(void)x;
|
||||||
|
(void)y;
|
||||||
|
(void)data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
|
||||||
|
(void)data;
|
||||||
|
/* Save x and y as uncompressed public key */
|
||||||
|
output[0] = 0x04;
|
||||||
|
memcpy(output + 1, x, 32);
|
||||||
|
memcpy(output + 33, y, 32);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void test_ecdh_api(void) {
|
void test_ecdh_api(void) {
|
||||||
/* Setup context that just counts errors */
|
/* Setup context that just counts errors */
|
||||||
secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||||
|
@ -21,15 +38,15 @@ void test_ecdh_api(void) {
|
||||||
CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
|
CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
|
||||||
|
|
||||||
/* Check all NULLs are detected */
|
/* Check all NULLs are detected */
|
||||||
CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
|
CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
|
||||||
CHECK(ecount == 0);
|
CHECK(ecount == 0);
|
||||||
CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0);
|
CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0);
|
||||||
CHECK(ecount == 1);
|
CHECK(ecount == 1);
|
||||||
CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0);
|
CHECK(secp256k1_ecdh(tctx, res, NULL, s_one, NULL, NULL) == 0);
|
||||||
CHECK(ecount == 2);
|
CHECK(ecount == 2);
|
||||||
CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0);
|
CHECK(secp256k1_ecdh(tctx, res, &point, NULL, NULL, NULL) == 0);
|
||||||
CHECK(ecount == 3);
|
CHECK(ecount == 3);
|
||||||
CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
|
CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
|
||||||
CHECK(ecount == 3);
|
CHECK(ecount == 3);
|
||||||
|
|
||||||
/* Cleanup */
|
/* Cleanup */
|
||||||
|
@ -46,27 +63,34 @@ void test_ecdh_generator_basepoint(void) {
|
||||||
for (i = 0; i < 100; ++i) {
|
for (i = 0; i < 100; ++i) {
|
||||||
secp256k1_sha256 sha;
|
secp256k1_sha256 sha;
|
||||||
unsigned char s_b32[32];
|
unsigned char s_b32[32];
|
||||||
unsigned char output_ecdh[32];
|
unsigned char output_ecdh[65];
|
||||||
unsigned char output_ser[32];
|
unsigned char output_ser[32];
|
||||||
unsigned char point_ser[33];
|
unsigned char point_ser[65];
|
||||||
size_t point_ser_len = sizeof(point_ser);
|
size_t point_ser_len = sizeof(point_ser);
|
||||||
secp256k1_scalar s;
|
secp256k1_scalar s;
|
||||||
|
|
||||||
random_scalar_order(&s);
|
random_scalar_order(&s);
|
||||||
secp256k1_scalar_get_b32(s_b32, &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_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_create(ctx, &point[1], s_b32) == 1);
|
||||||
|
|
||||||
|
/* compute using ECDH function with custom hash function */
|
||||||
|
CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1);
|
||||||
|
/* compute "explicitly" */
|
||||||
|
CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1);
|
||||||
|
/* compare */
|
||||||
|
CHECK(memcmp(output_ecdh, point_ser, 65) == 0);
|
||||||
|
|
||||||
|
/* compute using ECDH function with default hash function */
|
||||||
|
CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1);
|
||||||
|
/* compute "explicitly" */
|
||||||
CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 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_initialize(&sha);
|
||||||
secp256k1_sha256_write(&sha, point_ser, point_ser_len);
|
secp256k1_sha256_write(&sha, point_ser, point_ser_len);
|
||||||
secp256k1_sha256_finalize(&sha, output_ser);
|
secp256k1_sha256_finalize(&sha, output_ser);
|
||||||
/* compare */
|
/* compare */
|
||||||
CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0);
|
CHECK(memcmp(output_ecdh, output_ser, 32) == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,11 +113,14 @@ void test_bad_scalar(void) {
|
||||||
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1);
|
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1);
|
||||||
|
|
||||||
/* Try to multiply it by bad values */
|
/* Try to multiply it by bad values */
|
||||||
CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0);
|
CHECK(secp256k1_ecdh(ctx, output, &point, s_zero, NULL, NULL) == 0);
|
||||||
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0);
|
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 0);
|
||||||
/* ...and a good one */
|
/* ...and a good one */
|
||||||
s_overflow[31] -= 1;
|
s_overflow[31] -= 1;
|
||||||
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1);
|
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 1);
|
||||||
|
|
||||||
|
/* Hash function failure results in ecdh failure */
|
||||||
|
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_ecdh_tests(void) {
|
void run_ecdh_tests(void) {
|
||||||
|
|
|
@ -56,6 +56,14 @@ struct secp256k1_context_struct {
|
||||||
secp256k1_callback error_callback;
|
secp256k1_callback error_callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const secp256k1_context secp256k1_context_no_precomp_ = {
|
||||||
|
{ 0 },
|
||||||
|
{ 0 },
|
||||||
|
{ default_illegal_callback_fn, 0 },
|
||||||
|
{ default_error_callback_fn, 0 }
|
||||||
|
};
|
||||||
|
const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_no_precomp_;
|
||||||
|
|
||||||
secp256k1_context* secp256k1_context_create(unsigned int flags) {
|
secp256k1_context* secp256k1_context_create(unsigned int flags) {
|
||||||
secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context));
|
secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context));
|
||||||
ret->illegal_callback = default_illegal_callback;
|
ret->illegal_callback = default_illegal_callback;
|
||||||
|
@ -91,6 +99,7 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void secp256k1_context_destroy(secp256k1_context* ctx) {
|
void secp256k1_context_destroy(secp256k1_context* ctx) {
|
||||||
|
CHECK(ctx != secp256k1_context_no_precomp);
|
||||||
if (ctx != NULL) {
|
if (ctx != NULL) {
|
||||||
secp256k1_ecmult_context_clear(&ctx->ecmult_ctx);
|
secp256k1_ecmult_context_clear(&ctx->ecmult_ctx);
|
||||||
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
|
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
|
||||||
|
@ -100,6 +109,7 @@ void secp256k1_context_destroy(secp256k1_context* ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
|
void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
|
||||||
|
CHECK(ctx != secp256k1_context_no_precomp);
|
||||||
if (fun == NULL) {
|
if (fun == NULL) {
|
||||||
fun = default_illegal_callback_fn;
|
fun = default_illegal_callback_fn;
|
||||||
}
|
}
|
||||||
|
@ -108,6 +118,7 @@ void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(
|
||||||
}
|
}
|
||||||
|
|
||||||
void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
|
void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
|
||||||
|
CHECK(ctx != secp256k1_context_no_precomp);
|
||||||
if (fun == NULL) {
|
if (fun == NULL) {
|
||||||
fun = default_error_callback_fn;
|
fun = default_error_callback_fn;
|
||||||
}
|
}
|
||||||
|
@ -559,6 +570,7 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey
|
||||||
|
|
||||||
int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) {
|
int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) {
|
||||||
VERIFY_CHECK(ctx != NULL);
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
CHECK(ctx != secp256k1_context_no_precomp);
|
||||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||||
secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
|
secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -3599,6 +3599,7 @@ void run_ec_pubkey_parse_test(void) {
|
||||||
ecount = 0;
|
ecount = 0;
|
||||||
VG_UNDEF(&pubkey, sizeof(pubkey));
|
VG_UNDEF(&pubkey, sizeof(pubkey));
|
||||||
CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1);
|
CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1);
|
||||||
|
CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_no_precomp, &pubkey, pubkeyc, 65) == 1);
|
||||||
VG_CHECK(&pubkey, sizeof(pubkey));
|
VG_CHECK(&pubkey, sizeof(pubkey));
|
||||||
CHECK(ecount == 0);
|
CHECK(ecount == 0);
|
||||||
VG_UNDEF(&ge, sizeof(ge));
|
VG_UNDEF(&ge, sizeof(ge));
|
||||||
|
|
22
src/ecdh.rs
22
src/ecdh.rs
|
@ -16,9 +16,8 @@
|
||||||
//! Support for shared secret computations
|
//! Support for shared secret computations
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use std::ops;
|
use std::{ops, ptr};
|
||||||
|
|
||||||
use super::Secp256k1;
|
|
||||||
use key::{SecretKey, PublicKey};
|
use key::{SecretKey, PublicKey};
|
||||||
use ffi;
|
use ffi;
|
||||||
|
|
||||||
|
@ -29,10 +28,17 @@ pub struct SharedSecret(ffi::SharedSecret);
|
||||||
impl SharedSecret {
|
impl SharedSecret {
|
||||||
/// Creates a new shared secret from a pubkey and secret key
|
/// Creates a new shared secret from a pubkey and secret key
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new<C>(secp: &Secp256k1<C>, point: &PublicKey, scalar: &SecretKey) -> SharedSecret {
|
pub fn new(point: &PublicKey, scalar: &SecretKey) -> SharedSecret {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut ss = ffi::SharedSecret::blank();
|
let mut ss = ffi::SharedSecret::blank();
|
||||||
let res = ffi::secp256k1_ecdh(secp.ctx, &mut ss, point.as_ptr(), scalar.as_ptr());
|
let res = ffi::secp256k1_ecdh(
|
||||||
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
&mut ss,
|
||||||
|
point.as_ptr(),
|
||||||
|
scalar.as_ptr(),
|
||||||
|
ffi::secp256k1_ecdh_hash_function_default,
|
||||||
|
ptr::null_mut(),
|
||||||
|
);
|
||||||
debug_assert_eq!(res, 1);
|
debug_assert_eq!(res, 1);
|
||||||
SharedSecret(ss)
|
SharedSecret(ss)
|
||||||
}
|
}
|
||||||
|
@ -102,9 +108,9 @@ mod tests {
|
||||||
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
|
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
|
||||||
let (sk2, pk2) = s.generate_keypair(&mut thread_rng());
|
let (sk2, pk2) = s.generate_keypair(&mut thread_rng());
|
||||||
|
|
||||||
let sec1 = SharedSecret::new(&s, &pk1, &sk2);
|
let sec1 = SharedSecret::new(&pk1, &sk2);
|
||||||
let sec2 = SharedSecret::new(&s, &pk2, &sk1);
|
let sec2 = SharedSecret::new(&pk2, &sk1);
|
||||||
let sec_odd = SharedSecret::new(&s, &pk1, &sk1);
|
let sec_odd = SharedSecret::new(&pk1, &sk1);
|
||||||
assert_eq!(sec1, sec2);
|
assert_eq!(sec1, sec2);
|
||||||
assert!(sec_odd != sec2);
|
assert!(sec_odd != sec2);
|
||||||
}
|
}
|
||||||
|
@ -125,7 +131,7 @@ mod benches {
|
||||||
|
|
||||||
let s = Secp256k1::new();
|
let s = Secp256k1::new();
|
||||||
bh.iter( || {
|
bh.iter( || {
|
||||||
let res = SharedSecret::new(&s, &pk, &sk);
|
let res = SharedSecret::new(&pk, &sk);
|
||||||
black_box(res);
|
black_box(res);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
37
src/ffi.rs
37
src/ffi.rs
|
@ -46,6 +46,14 @@ pub type NonceFn = unsafe extern "C" fn(nonce32: *mut c_uchar,
|
||||||
attempt: c_uint,
|
attempt: c_uint,
|
||||||
data: *const c_void);
|
data: *const c_void);
|
||||||
|
|
||||||
|
/// Hash function to use to post-process an ECDH point to get
|
||||||
|
/// a shared secret.
|
||||||
|
pub type EcdhHashFn = unsafe extern "C" fn(
|
||||||
|
output: *mut c_uchar,
|
||||||
|
x: *const c_uchar,
|
||||||
|
y: *const c_uchar,
|
||||||
|
data: *const c_void,
|
||||||
|
);
|
||||||
|
|
||||||
/// A Secp256k1 context, containing various precomputed values and such
|
/// A Secp256k1 context, containing various precomputed values and such
|
||||||
/// needed to do elliptic curve computations. If you create one of these
|
/// needed to do elliptic curve computations. If you create one of these
|
||||||
|
@ -114,10 +122,15 @@ impl SharedSecret {
|
||||||
|
|
||||||
#[cfg(not(feature = "fuzztarget"))]
|
#[cfg(not(feature = "fuzztarget"))]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
/// Default ECDH hash function
|
||||||
|
pub static secp256k1_ecdh_hash_function_default: EcdhHashFn;
|
||||||
|
|
||||||
pub static secp256k1_nonce_function_rfc6979: NonceFn;
|
pub static secp256k1_nonce_function_rfc6979: NonceFn;
|
||||||
|
|
||||||
pub static secp256k1_nonce_function_default: NonceFn;
|
pub static secp256k1_nonce_function_default: NonceFn;
|
||||||
|
|
||||||
|
pub static secp256k1_context_no_precomp: *const Context;
|
||||||
|
|
||||||
// Contexts
|
// Contexts
|
||||||
pub fn secp256k1_context_create(flags: c_uint) -> *mut Context;
|
pub fn secp256k1_context_create(flags: c_uint) -> *mut Context;
|
||||||
|
|
||||||
|
@ -248,11 +261,14 @@ extern "C" {
|
||||||
n: c_int)
|
n: c_int)
|
||||||
-> c_int;
|
-> c_int;
|
||||||
|
|
||||||
pub fn secp256k1_ecdh(cx: *const Context,
|
pub fn secp256k1_ecdh(
|
||||||
out: *mut SharedSecret,
|
cx: *const Context,
|
||||||
point: *const PublicKey,
|
output: *mut SharedSecret,
|
||||||
scalar: *const c_uchar)
|
pubkey: *const PublicKey,
|
||||||
-> c_int;
|
privkey: *const c_uchar,
|
||||||
|
hashfp: EcdhHashFn,
|
||||||
|
data: *mut c_void,
|
||||||
|
) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "fuzztarget")]
|
#[cfg(feature = "fuzztarget")]
|
||||||
|
@ -262,7 +278,9 @@ mod fuzz_dummy {
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
pub static secp256k1_ecdh_hash_function_default: EcdhHashFn;
|
||||||
pub static secp256k1_nonce_function_rfc6979: NonceFn;
|
pub static secp256k1_nonce_function_rfc6979: NonceFn;
|
||||||
|
pub static secp256k1_context_no_precomp: *const Context;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contexts
|
// Contexts
|
||||||
|
@ -618,11 +636,14 @@ mod fuzz_dummy {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets out to point[0..16]||scalar[0..16]
|
/// Sets out to point[0..16]||scalar[0..16]
|
||||||
pub unsafe fn secp256k1_ecdh(cx: *const Context,
|
pub unsafe fn secp256k1_ecdh(
|
||||||
|
cx: *const Context,
|
||||||
out: *mut SharedSecret,
|
out: *mut SharedSecret,
|
||||||
point: *const PublicKey,
|
point: *const PublicKey,
|
||||||
scalar: *const c_uchar)
|
scalar: *const c_uchar,
|
||||||
-> c_int {
|
hashfp: EcdhHashFn,
|
||||||
|
data: *mut c_void,
|
||||||
|
) -> c_int {
|
||||||
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
|
||||||
assert!((*cx).0 as u32 & SECP256K1_START_SIGN == SECP256K1_START_SIGN);
|
assert!((*cx).0 as u32 & SECP256K1_START_SIGN == SECP256K1_START_SIGN);
|
||||||
if secp256k1_ec_seckey_verify(cx, scalar) != 1 { return 0; }
|
if secp256k1_ec_seckey_verify(cx, scalar) != 1 { return 0; }
|
||||||
|
|
172
src/key.rs
172
src/key.rs
|
@ -87,17 +87,15 @@ impl fmt::Display for PublicKey {
|
||||||
impl str::FromStr for PublicKey {
|
impl str::FromStr for PublicKey {
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
fn from_str(s: &str) -> Result<PublicKey, Error> {
|
fn from_str(s: &str) -> Result<PublicKey, Error> {
|
||||||
let secp = Secp256k1::without_caps();
|
|
||||||
let mut res = [0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE];
|
let mut res = [0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE];
|
||||||
match from_hex(s, &mut res) {
|
match from_hex(s, &mut res) {
|
||||||
Ok(constants::PUBLIC_KEY_SIZE) => {
|
Ok(constants::PUBLIC_KEY_SIZE) => {
|
||||||
PublicKey::from_slice(
|
PublicKey::from_slice(
|
||||||
&secp,
|
|
||||||
&res[0..constants::PUBLIC_KEY_SIZE]
|
&res[0..constants::PUBLIC_KEY_SIZE]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Ok(constants::UNCOMPRESSED_PUBLIC_KEY_SIZE) => {
|
Ok(constants::UNCOMPRESSED_PUBLIC_KEY_SIZE) => {
|
||||||
PublicKey::from_slice(&secp, &res)
|
PublicKey::from_slice(&res)
|
||||||
}
|
}
|
||||||
_ => Err(Error::InvalidPublicKey)
|
_ => Err(Error::InvalidPublicKey)
|
||||||
}
|
}
|
||||||
|
@ -115,10 +113,14 @@ impl SecretKey {
|
||||||
/// Creates a new random secret key. Requires compilation with the "rand" feature.
|
/// Creates a new random secret key. Requires compilation with the "rand" feature.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(any(test, feature = "rand"))]
|
#[cfg(any(test, feature = "rand"))]
|
||||||
pub fn new<R: Rng, C>(secp: &Secp256k1<C>, rng: &mut R) -> SecretKey {
|
pub fn new<R: Rng>(rng: &mut R) -> SecretKey {
|
||||||
let mut data = random_32_bytes(rng);
|
let mut data = random_32_bytes(rng);
|
||||||
unsafe {
|
unsafe {
|
||||||
while ffi::secp256k1_ec_seckey_verify(secp.ctx, data.as_ptr()) == 0 {
|
while ffi::secp256k1_ec_seckey_verify(
|
||||||
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
data.as_ptr(),
|
||||||
|
) == 0
|
||||||
|
{
|
||||||
data = random_32_bytes(rng);
|
data = random_32_bytes(rng);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,13 +129,16 @@ impl SecretKey {
|
||||||
|
|
||||||
/// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key
|
/// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_slice<C>(secp: &Secp256k1<C>, data: &[u8])
|
pub fn from_slice(data: &[u8])-> Result<SecretKey, Error> {
|
||||||
-> Result<SecretKey, Error> {
|
|
||||||
match data.len() {
|
match data.len() {
|
||||||
constants::SECRET_KEY_SIZE => {
|
constants::SECRET_KEY_SIZE => {
|
||||||
let mut ret = [0; constants::SECRET_KEY_SIZE];
|
let mut ret = [0; constants::SECRET_KEY_SIZE];
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ec_seckey_verify(secp.ctx, data.as_ptr()) == 0 {
|
if ffi::secp256k1_ec_seckey_verify(
|
||||||
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
data.as_ptr(),
|
||||||
|
) == 0
|
||||||
|
{
|
||||||
return Err(InvalidSecretKey);
|
return Err(InvalidSecretKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,10 +151,14 @@ impl SecretKey {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Adds one secret key to another, modulo the curve order
|
/// Adds one secret key to another, modulo the curve order
|
||||||
pub fn add_assign<C>(&mut self, secp: &Secp256k1<C>, other: &SecretKey)
|
pub fn add_assign(&mut self, other: &SecretKey) -> Result<(), Error> {
|
||||||
-> Result<(), Error> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ec_privkey_tweak_add(secp.ctx, self.as_mut_ptr(), other.as_ptr()) != 1 {
|
if ffi::secp256k1_ec_privkey_tweak_add(
|
||||||
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
self.as_mut_ptr(),
|
||||||
|
other.as_ptr(),
|
||||||
|
) != 1
|
||||||
|
{
|
||||||
Err(InvalidSecretKey)
|
Err(InvalidSecretKey)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -159,10 +168,14 @@ impl SecretKey {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Multiplies one secret key by another, modulo the curve order
|
/// Multiplies one secret key by another, modulo the curve order
|
||||||
pub fn mul_assign<C>(&mut self, secp: &Secp256k1<C>, other: &SecretKey)
|
pub fn mul_assign(&mut self, other: &SecretKey) -> Result<(), Error> {
|
||||||
-> Result<(), Error> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ec_privkey_tweak_mul(secp.ctx, self.as_mut_ptr(), other.as_ptr()) != 1 {
|
if ffi::secp256k1_ec_privkey_tweak_mul(
|
||||||
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
self.as_mut_ptr(),
|
||||||
|
other.as_ptr(),
|
||||||
|
) != 1
|
||||||
|
{
|
||||||
Err(InvalidSecretKey)
|
Err(InvalidSecretKey)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -220,13 +233,16 @@ impl PublicKey {
|
||||||
|
|
||||||
/// Creates a public key directly from a slice
|
/// Creates a public key directly from a slice
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_slice<C>(secp: &Secp256k1<C>, data: &[u8])
|
pub fn from_slice(data: &[u8]) -> Result<PublicKey, Error> {
|
||||||
-> Result<PublicKey, Error> {
|
|
||||||
|
|
||||||
let mut pk = unsafe { ffi::PublicKey::blank() };
|
let mut pk = unsafe { ffi::PublicKey::blank() };
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ec_pubkey_parse(secp.ctx, &mut pk, data.as_ptr(),
|
if ffi::secp256k1_ec_pubkey_parse(
|
||||||
data.len() as ::libc::size_t) == 1 {
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
&mut pk,
|
||||||
|
data.as_ptr(),
|
||||||
|
data.len() as ::libc::size_t,
|
||||||
|
) == 1
|
||||||
|
{
|
||||||
Ok(PublicKey(pk))
|
Ok(PublicKey(pk))
|
||||||
} else {
|
} else {
|
||||||
Err(InvalidPublicKey)
|
Err(InvalidPublicKey)
|
||||||
|
@ -239,13 +255,12 @@ impl PublicKey {
|
||||||
/// the y-coordinate is represented by only a single bit, as x determines
|
/// the y-coordinate is represented by only a single bit, as x determines
|
||||||
/// it up to one bit.
|
/// it up to one bit.
|
||||||
pub fn serialize(&self) -> [u8; constants::PUBLIC_KEY_SIZE] {
|
pub fn serialize(&self) -> [u8; constants::PUBLIC_KEY_SIZE] {
|
||||||
let secp = Secp256k1::without_caps();
|
|
||||||
let mut ret = [0; constants::PUBLIC_KEY_SIZE];
|
let mut ret = [0; constants::PUBLIC_KEY_SIZE];
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut ret_len = constants::PUBLIC_KEY_SIZE as ::libc::size_t;
|
let mut ret_len = constants::PUBLIC_KEY_SIZE as ::libc::size_t;
|
||||||
let err = ffi::secp256k1_ec_pubkey_serialize(
|
let err = ffi::secp256k1_ec_pubkey_serialize(
|
||||||
secp.ctx,
|
ffi::secp256k1_context_no_precomp,
|
||||||
ret.as_mut_ptr(),
|
ret.as_mut_ptr(),
|
||||||
&mut ret_len,
|
&mut ret_len,
|
||||||
self.as_ptr(),
|
self.as_ptr(),
|
||||||
|
@ -259,13 +274,12 @@ impl PublicKey {
|
||||||
|
|
||||||
/// Serialize the key as a byte-encoded pair of values, in uncompressed form
|
/// Serialize the key as a byte-encoded pair of values, in uncompressed form
|
||||||
pub fn serialize_uncompressed(&self) -> [u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE] {
|
pub fn serialize_uncompressed(&self) -> [u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE] {
|
||||||
let secp = Secp256k1::without_caps();
|
|
||||||
let mut ret = [0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE];
|
let mut ret = [0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE];
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut ret_len = constants::UNCOMPRESSED_PUBLIC_KEY_SIZE as ::libc::size_t;
|
let mut ret_len = constants::UNCOMPRESSED_PUBLIC_KEY_SIZE as ::libc::size_t;
|
||||||
let err = ffi::secp256k1_ec_pubkey_serialize(
|
let err = ffi::secp256k1_ec_pubkey_serialize(
|
||||||
secp.ctx,
|
ffi::secp256k1_context_no_precomp,
|
||||||
ret.as_mut_ptr(),
|
ret.as_mut_ptr(),
|
||||||
&mut ret_len,
|
&mut ret_len,
|
||||||
self.as_ptr(),
|
self.as_ptr(),
|
||||||
|
@ -308,11 +322,17 @@ impl PublicKey {
|
||||||
/// Adds a second key to this one, returning the sum. Returns an error if
|
/// Adds a second key to this one, returning the sum. Returns an error if
|
||||||
/// the result would be the point at infinity, i.e. we are adding this point
|
/// the result would be the point at infinity, i.e. we are adding this point
|
||||||
/// to its own negation
|
/// to its own negation
|
||||||
pub fn combine<C>(&self, secp: &Secp256k1<C>, other: &PublicKey) -> Result<PublicKey, Error> {
|
pub fn combine(&self, other: &PublicKey) -> Result<PublicKey, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut ret = mem::uninitialized();
|
let mut ret = mem::uninitialized();
|
||||||
let ptrs = [self.as_ptr(), other.as_ptr()];
|
let ptrs = [self.as_ptr(), other.as_ptr()];
|
||||||
if ffi::secp256k1_ec_pubkey_combine(secp.ctx, &mut ret, ptrs.as_ptr(), 2) == 1 {
|
if ffi::secp256k1_ec_pubkey_combine(
|
||||||
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
&mut ret,
|
||||||
|
ptrs.as_ptr(),
|
||||||
|
2
|
||||||
|
) == 1
|
||||||
|
{
|
||||||
Ok(PublicKey(ret))
|
Ok(PublicKey(ret))
|
||||||
} else {
|
} else {
|
||||||
Err(InvalidPublicKey)
|
Err(InvalidPublicKey)
|
||||||
|
@ -341,9 +361,8 @@ impl<'de> ::serde::Deserialize<'de> for PublicKey {
|
||||||
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<PublicKey, D::Error> {
|
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<PublicKey, D::Error> {
|
||||||
use ::serde::de::Error;
|
use ::serde::de::Error;
|
||||||
|
|
||||||
let secp = Secp256k1::without_caps();
|
|
||||||
let sl: &[u8] = ::serde::Deserialize::deserialize(d)?;
|
let sl: &[u8] = ::serde::Deserialize::deserialize(d)?;
|
||||||
PublicKey::from_slice(&secp, sl).map_err(D::Error::custom)
|
PublicKey::from_slice(sl).map_err(D::Error::custom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,24 +388,22 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn skey_from_slice() {
|
fn skey_from_slice() {
|
||||||
let s = Secp256k1::new();
|
let sk = SecretKey::from_slice(&[1; 31]);
|
||||||
let sk = SecretKey::from_slice(&s, &[1; 31]);
|
|
||||||
assert_eq!(sk, Err(InvalidSecretKey));
|
assert_eq!(sk, Err(InvalidSecretKey));
|
||||||
|
|
||||||
let sk = SecretKey::from_slice(&s, &[1; 32]);
|
let sk = SecretKey::from_slice(&[1; 32]);
|
||||||
assert!(sk.is_ok());
|
assert!(sk.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pubkey_from_slice() {
|
fn pubkey_from_slice() {
|
||||||
let s = Secp256k1::new();
|
assert_eq!(PublicKey::from_slice(&[]), Err(InvalidPublicKey));
|
||||||
assert_eq!(PublicKey::from_slice(&s, &[]), Err(InvalidPublicKey));
|
assert_eq!(PublicKey::from_slice(&[1, 2, 3]), Err(InvalidPublicKey));
|
||||||
assert_eq!(PublicKey::from_slice(&s, &[1, 2, 3]), Err(InvalidPublicKey));
|
|
||||||
|
|
||||||
let uncompressed = PublicKey::from_slice(&s, &[4, 54, 57, 149, 239, 162, 148, 175, 246, 254, 239, 75, 154, 152, 10, 82, 234, 224, 85, 220, 40, 100, 57, 121, 30, 162, 94, 156, 135, 67, 74, 49, 179, 57, 236, 53, 162, 124, 149, 144, 168, 77, 74, 30, 72, 211, 229, 110, 111, 55, 96, 193, 86, 227, 183, 152, 195, 155, 51, 247, 123, 113, 60, 228, 188]);
|
let uncompressed = PublicKey::from_slice(&[4, 54, 57, 149, 239, 162, 148, 175, 246, 254, 239, 75, 154, 152, 10, 82, 234, 224, 85, 220, 40, 100, 57, 121, 30, 162, 94, 156, 135, 67, 74, 49, 179, 57, 236, 53, 162, 124, 149, 144, 168, 77, 74, 30, 72, 211, 229, 110, 111, 55, 96, 193, 86, 227, 183, 152, 195, 155, 51, 247, 123, 113, 60, 228, 188]);
|
||||||
assert!(uncompressed.is_ok());
|
assert!(uncompressed.is_ok());
|
||||||
|
|
||||||
let compressed = PublicKey::from_slice(&s, &[3, 23, 183, 225, 206, 31, 159, 148, 195, 42, 67, 115, 146, 41, 248, 140, 11, 3, 51, 41, 111, 180, 110, 143, 114, 134, 88, 73, 198, 174, 52, 184, 78]);
|
let compressed = PublicKey::from_slice(&[3, 23, 183, 225, 206, 31, 159, 148, 195, 42, 67, 115, 146, 41, 248, 140, 11, 3, 51, 41, 111, 180, 110, 143, 114, 134, 88, 73, 198, 174, 52, 184, 78]);
|
||||||
assert!(compressed.is_ok());
|
assert!(compressed.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,30 +412,31 @@ mod test {
|
||||||
let s = Secp256k1::new();
|
let s = Secp256k1::new();
|
||||||
|
|
||||||
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
|
let (sk1, pk1) = s.generate_keypair(&mut thread_rng());
|
||||||
assert_eq!(SecretKey::from_slice(&s, &sk1[..]), Ok(sk1));
|
assert_eq!(SecretKey::from_slice(&sk1[..]), Ok(sk1));
|
||||||
assert_eq!(PublicKey::from_slice(&s, &pk1.serialize()[..]), Ok(pk1));
|
assert_eq!(PublicKey::from_slice(&pk1.serialize()[..]), Ok(pk1));
|
||||||
assert_eq!(PublicKey::from_slice(&s, &pk1.serialize_uncompressed()[..]), Ok(pk1));
|
assert_eq!(PublicKey::from_slice(&pk1.serialize_uncompressed()[..]), Ok(pk1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_secret_key() {
|
fn invalid_secret_key() {
|
||||||
let s = Secp256k1::new();
|
|
||||||
// Zero
|
// Zero
|
||||||
assert_eq!(SecretKey::from_slice(&s, &[0; 32]), Err(InvalidSecretKey));
|
assert_eq!(SecretKey::from_slice(&[0; 32]), Err(InvalidSecretKey));
|
||||||
// -1
|
// -1
|
||||||
assert_eq!(SecretKey::from_slice(&s, &[0xff; 32]), Err(InvalidSecretKey));
|
assert_eq!(SecretKey::from_slice(&[0xff; 32]), Err(InvalidSecretKey));
|
||||||
// Top of range
|
// Top of range
|
||||||
assert!(SecretKey::from_slice(&s,
|
assert!(SecretKey::from_slice(&[
|
||||||
&[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, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
|
||||||
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
|
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
|
||||||
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40]).is_ok());
|
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40,
|
||||||
|
]).is_ok());
|
||||||
// One past top of range
|
// One past top of range
|
||||||
assert!(SecretKey::from_slice(&s,
|
assert!(SecretKey::from_slice(&[
|
||||||
&[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, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
|
||||||
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
|
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
|
||||||
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41]).is_err());
|
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41,
|
||||||
|
]).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -449,22 +467,33 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pubkey_from_bad_slice() {
|
fn test_pubkey_from_bad_slice() {
|
||||||
let s = Secp256k1::new();
|
|
||||||
// Bad sizes
|
// Bad sizes
|
||||||
assert_eq!(PublicKey::from_slice(&s, &[0; constants::PUBLIC_KEY_SIZE - 1]),
|
assert_eq!(
|
||||||
Err(InvalidPublicKey));
|
PublicKey::from_slice(&[0; constants::PUBLIC_KEY_SIZE - 1]),
|
||||||
assert_eq!(PublicKey::from_slice(&s, &[0; constants::PUBLIC_KEY_SIZE + 1]),
|
Err(InvalidPublicKey)
|
||||||
Err(InvalidPublicKey));
|
);
|
||||||
assert_eq!(PublicKey::from_slice(&s, &[0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE - 1]),
|
assert_eq!(
|
||||||
Err(InvalidPublicKey));
|
PublicKey::from_slice(&[0; constants::PUBLIC_KEY_SIZE + 1]),
|
||||||
assert_eq!(PublicKey::from_slice(&s, &[0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE + 1]),
|
Err(InvalidPublicKey)
|
||||||
Err(InvalidPublicKey));
|
);
|
||||||
|
assert_eq!(
|
||||||
|
PublicKey::from_slice(&[0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE - 1]),
|
||||||
|
Err(InvalidPublicKey)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
PublicKey::from_slice(&[0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE + 1]),
|
||||||
|
Err(InvalidPublicKey)
|
||||||
|
);
|
||||||
|
|
||||||
// Bad parse
|
// Bad parse
|
||||||
assert_eq!(PublicKey::from_slice(&s, &[0xff; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]),
|
assert_eq!(
|
||||||
Err(InvalidPublicKey));
|
PublicKey::from_slice(&[0xff; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]),
|
||||||
assert_eq!(PublicKey::from_slice(&s, &[0x55; constants::PUBLIC_KEY_SIZE]),
|
Err(InvalidPublicKey)
|
||||||
Err(InvalidPublicKey));
|
);
|
||||||
|
assert_eq!(
|
||||||
|
PublicKey::from_slice(&[0x55; constants::PUBLIC_KEY_SIZE]),
|
||||||
|
Err(InvalidPublicKey)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -494,7 +523,7 @@ mod test {
|
||||||
];
|
];
|
||||||
|
|
||||||
let s = Secp256k1::signing_only();
|
let s = Secp256k1::signing_only();
|
||||||
let sk = SecretKey::from_slice(&s, &SK_BYTES).expect("sk");
|
let sk = SecretKey::from_slice(&SK_BYTES).expect("sk");
|
||||||
let pk = PublicKey::from_secret_key(&s, &sk);
|
let pk = PublicKey::from_secret_key(&s, &sk);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -563,12 +592,12 @@ mod test {
|
||||||
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
|
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
|
||||||
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
|
||||||
assert!(sk1.add_assign(&s, &sk2).is_ok());
|
assert!(sk1.add_assign(&sk2).is_ok());
|
||||||
assert!(pk1.add_exp_assign(&s, &sk2).is_ok());
|
assert!(pk1.add_exp_assign(&s, &sk2).is_ok());
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
|
||||||
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
|
||||||
assert!(sk2.add_assign(&s, &sk1).is_ok());
|
assert!(sk2.add_assign(&sk1).is_ok());
|
||||||
assert!(pk2.add_exp_assign(&s, &sk1).is_ok());
|
assert!(pk2.add_exp_assign(&s, &sk1).is_ok());
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
|
||||||
}
|
}
|
||||||
|
@ -581,12 +610,12 @@ mod test {
|
||||||
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
|
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng());
|
||||||
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
|
||||||
assert!(sk1.mul_assign(&s, &sk2).is_ok());
|
assert!(sk1.mul_assign(&sk2).is_ok());
|
||||||
assert!(pk1.mul_assign(&s, &sk2).is_ok());
|
assert!(pk1.mul_assign(&s, &sk2).is_ok());
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
|
||||||
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
|
||||||
assert!(sk2.mul_assign(&s, &sk1).is_ok());
|
assert!(sk2.mul_assign(&sk1).is_ok());
|
||||||
assert!(pk2.mul_assign(&s, &sk1).is_ok());
|
assert!(pk2.mul_assign(&s, &sk1).is_ok());
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
|
||||||
}
|
}
|
||||||
|
@ -617,23 +646,19 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pubkey_combine() {
|
fn pubkey_combine() {
|
||||||
let s = Secp256k1::without_caps();
|
|
||||||
let compressed1 = PublicKey::from_slice(
|
let compressed1 = PublicKey::from_slice(
|
||||||
&s,
|
|
||||||
&hex!("0241cc121c419921942add6db6482fb36243faf83317c866d2a28d8c6d7089f7ba"),
|
&hex!("0241cc121c419921942add6db6482fb36243faf83317c866d2a28d8c6d7089f7ba"),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
let compressed2 = PublicKey::from_slice(
|
let compressed2 = PublicKey::from_slice(
|
||||||
&s,
|
|
||||||
&hex!("02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"),
|
&hex!("02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
let exp_sum = PublicKey::from_slice(
|
let exp_sum = PublicKey::from_slice(
|
||||||
&s,
|
|
||||||
&hex!("0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07"),
|
&hex!("0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07"),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let sum1 = compressed1.combine(&s, &compressed2);
|
let sum1 = compressed1.combine(&compressed2);
|
||||||
assert!(sum1.is_ok());
|
assert!(sum1.is_ok());
|
||||||
let sum2 = compressed2.combine(&s, &compressed1);
|
let sum2 = compressed2.combine(&compressed1);
|
||||||
assert!(sum2.is_ok());
|
assert!(sum2.is_ok());
|
||||||
assert_eq!(sum1, sum2);
|
assert_eq!(sum1, sum2);
|
||||||
assert_eq!(sum1.unwrap(), exp_sum);
|
assert_eq!(sum1.unwrap(), exp_sum);
|
||||||
|
@ -641,14 +666,11 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pubkey_equal() {
|
fn pubkey_equal() {
|
||||||
let s = Secp256k1::new();
|
|
||||||
let pk1 = PublicKey::from_slice(
|
let pk1 = PublicKey::from_slice(
|
||||||
&s,
|
|
||||||
&hex!("0241cc121c419921942add6db6482fb36243faf83317c866d2a28d8c6d7089f7ba"),
|
&hex!("0241cc121c419921942add6db6482fb36243faf83317c866d2a28d8c6d7089f7ba"),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
let pk2 = pk1.clone();
|
let pk2 = pk1.clone();
|
||||||
let pk3 = PublicKey::from_slice(
|
let pk3 = PublicKey::from_slice(
|
||||||
&s,
|
|
||||||
&hex!("02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"),
|
&hex!("02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
|
@ -684,7 +706,7 @@ mod test {
|
||||||
|
|
||||||
let s = Secp256k1::new();
|
let s = Secp256k1::new();
|
||||||
|
|
||||||
let sk = SecretKey::from_slice(&s, &SK_BYTES).unwrap();
|
let sk = SecretKey::from_slice(&SK_BYTES).unwrap();
|
||||||
let pk = PublicKey::from_secret_key(&s, &sk);
|
let pk = PublicKey::from_secret_key(&s, &sk);
|
||||||
|
|
||||||
assert_tokens(&sk, &[Token::BorrowedBytes(&SK_BYTES[..])]);
|
assert_tokens(&sk, &[Token::BorrowedBytes(&SK_BYTES[..])]);
|
||||||
|
|
238
src/lib.rs
238
src/lib.rs
|
@ -66,7 +66,7 @@
|
||||||
//! use self::secp256k1::{Secp256k1, Message, SecretKey, PublicKey};
|
//! use self::secp256k1::{Secp256k1, Message, SecretKey, PublicKey};
|
||||||
//!
|
//!
|
||||||
//! let secp = Secp256k1::new();
|
//! let secp = Secp256k1::new();
|
||||||
//! let secret_key = SecretKey::from_slice(&secp, &[0xcd; 32]).expect("32 bytes, within curve order");
|
//! let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order");
|
||||||
//! let public_key = PublicKey::from_secret_key(&secp, &secret_key);
|
//! let public_key = PublicKey::from_secret_key(&secp, &secret_key);
|
||||||
//! let message = Message::from_slice(&[0xab; 32]).expect("32 bytes");
|
//! let message = Message::from_slice(&[0xab; 32]).expect("32 bytes");
|
||||||
//!
|
//!
|
||||||
|
@ -83,7 +83,7 @@
|
||||||
//!
|
//!
|
||||||
//! let secp = Secp256k1::verification_only();
|
//! let secp = Secp256k1::verification_only();
|
||||||
//!
|
//!
|
||||||
//! let public_key = PublicKey::from_slice(&secp, &[
|
//! let public_key = PublicKey::from_slice(&[
|
||||||
//! 0x02,
|
//! 0x02,
|
||||||
//! 0xc6, 0x6e, 0x7d, 0x89, 0x66, 0xb5, 0xc5, 0x55,
|
//! 0xc6, 0x6e, 0x7d, 0x89, 0x66, 0xb5, 0xc5, 0x55,
|
||||||
//! 0xaf, 0x58, 0x05, 0x98, 0x9d, 0xa9, 0xfb, 0xf8,
|
//! 0xaf, 0x58, 0x05, 0x98, 0x9d, 0xa9, 0xfb, 0xf8,
|
||||||
|
@ -98,7 +98,7 @@
|
||||||
//! 0xd5, 0x44, 0x53, 0xcf, 0x6e, 0x82, 0xb4, 0x50,
|
//! 0xd5, 0x44, 0x53, 0xcf, 0x6e, 0x82, 0xb4, 0x50,
|
||||||
//! ]).expect("messages must be 32 bytes and are expected to be hashes");
|
//! ]).expect("messages must be 32 bytes and are expected to be hashes");
|
||||||
//!
|
//!
|
||||||
//! let sig = Signature::from_compact(&secp, &[
|
//! let sig = Signature::from_compact(&[
|
||||||
//! 0xdc, 0x4d, 0xc2, 0x64, 0xa9, 0xfe, 0xf1, 0x7a,
|
//! 0xdc, 0x4d, 0xc2, 0x64, 0xa9, 0xfe, 0xf1, 0x7a,
|
||||||
//! 0x3f, 0x25, 0x34, 0x49, 0xcf, 0x8c, 0x39, 0x7a,
|
//! 0x3f, 0x25, 0x34, 0x49, 0xcf, 0x8c, 0x39, 0x7a,
|
||||||
//! 0xb6, 0xf1, 0x6f, 0xb3, 0xd6, 0x3d, 0x86, 0x94,
|
//! 0xb6, 0xf1, 0x6f, 0xb3, 0xd6, 0x3d, 0x86, 0x94,
|
||||||
|
@ -165,38 +165,40 @@ pub struct RecoveryId(i32);
|
||||||
pub struct Signature(ffi::Signature);
|
pub struct Signature(ffi::Signature);
|
||||||
|
|
||||||
impl fmt::Debug for Signature {
|
impl fmt::Debug for Signature {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::Display::fmt(self, f)
|
fmt::Display::fmt(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Signature {
|
impl fmt::Display for Signature {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let mut v = [0; 72];
|
let mut v = [0; 72];
|
||||||
let mut len = v.len() as size_t;
|
let mut len = v.len() as size_t;
|
||||||
let secp = Secp256k1::without_caps();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let err = ffi::secp256k1_ecdsa_signature_serialize_der(secp.ctx, v.as_mut_ptr(),
|
let err = ffi::secp256k1_ecdsa_signature_serialize_der(
|
||||||
&mut len, self.as_ptr());
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
v.as_mut_ptr(),
|
||||||
|
&mut len,
|
||||||
|
self.as_ptr()
|
||||||
|
);
|
||||||
debug_assert!(err == 1);
|
debug_assert!(err == 1);
|
||||||
}
|
}
|
||||||
for ch in &v[..] {
|
for ch in &v[..] {
|
||||||
write!(f, "{:02x}", *ch)?;
|
write!(f, "{:02x}", *ch)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl str::FromStr for Signature {
|
impl str::FromStr for Signature {
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
fn from_str(s: &str) -> Result<Signature, Error> {
|
fn from_str(s: &str) -> Result<Signature, Error> {
|
||||||
let secp = Secp256k1::without_caps();
|
|
||||||
let mut res = [0; 72];
|
let mut res = [0; 72];
|
||||||
match from_hex(s, &mut res) {
|
match from_hex(s, &mut res) {
|
||||||
Ok(x) => Signature::from_der(&secp, &res[0..x]),
|
Ok(x) => Signature::from_der(&res[0..x]),
|
||||||
_ => Err(Error::InvalidSignature),
|
_ => Err(Error::InvalidSignature),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An ECDSA signature with a recovery ID for pubkey recovery
|
/// An ECDSA signature with a recovery ID for pubkey recovery
|
||||||
|
@ -204,31 +206,36 @@ impl str::FromStr for Signature {
|
||||||
pub struct RecoverableSignature(ffi::RecoverableSignature);
|
pub struct RecoverableSignature(ffi::RecoverableSignature);
|
||||||
|
|
||||||
impl RecoveryId {
|
impl RecoveryId {
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Allows library users to create valid recovery IDs from i32.
|
/// Allows library users to create valid recovery IDs from i32.
|
||||||
pub fn from_i32(id: i32) -> Result<RecoveryId, Error> {
|
pub fn from_i32(id: i32) -> Result<RecoveryId, Error> {
|
||||||
match id {
|
match id {
|
||||||
0 | 1 | 2 | 3 => Ok(RecoveryId(id)),
|
0 | 1 | 2 | 3 => Ok(RecoveryId(id)),
|
||||||
_ => Err(Error::InvalidRecoveryId)
|
_ => Err(Error::InvalidRecoveryId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Allows library users to convert recovery IDs to i32.
|
/// Allows library users to convert recovery IDs to i32.
|
||||||
pub fn to_i32(&self) -> i32 {
|
pub fn to_i32(&self) -> i32 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Signature {
|
impl Signature {
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Converts a DER-encoded byte slice to a signature
|
/// Converts a DER-encoded byte slice to a signature
|
||||||
pub fn from_der<C>(secp: &Secp256k1<C>, data: &[u8]) -> Result<Signature, Error> {
|
pub fn from_der(data: &[u8]) -> Result<Signature, Error> {
|
||||||
let mut ret = unsafe { ffi::Signature::blank() };
|
let mut ret = unsafe { ffi::Signature::blank() };
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ecdsa_signature_parse_der(secp.ctx, &mut ret,
|
if ffi::secp256k1_ecdsa_signature_parse_der(
|
||||||
data.as_ptr(), data.len() as libc::size_t) == 1 {
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
&mut ret,
|
||||||
|
data.as_ptr(),
|
||||||
|
data.len() as libc::size_t,
|
||||||
|
) == 1
|
||||||
|
{
|
||||||
Ok(Signature(ret))
|
Ok(Signature(ret))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::InvalidSignature)
|
Err(Error::InvalidSignature)
|
||||||
|
@ -237,15 +244,19 @@ impl Signature {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a 64-byte compact-encoded byte slice to a signature
|
/// Converts a 64-byte compact-encoded byte slice to a signature
|
||||||
pub fn from_compact<C>(secp: &Secp256k1<C>, data: &[u8]) -> Result<Signature, Error> {
|
pub fn from_compact(data: &[u8]) -> Result<Signature, Error> {
|
||||||
let mut ret = unsafe { ffi::Signature::blank() };
|
let mut ret = unsafe { ffi::Signature::blank() };
|
||||||
if data.len() != 64 {
|
if data.len() != 64 {
|
||||||
return Err(Error::InvalidSignature)
|
return Err(Error::InvalidSignature)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::secp256k1_ecdsa_signature_parse_compact(secp.ctx, &mut ret,
|
if ffi::secp256k1_ecdsa_signature_parse_compact(
|
||||||
data.as_ptr()) == 1 {
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
&mut ret,
|
||||||
|
data.as_ptr(),
|
||||||
|
) == 1
|
||||||
|
{
|
||||||
Ok(Signature(ret))
|
Ok(Signature(ret))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::InvalidSignature)
|
Err(Error::InvalidSignature)
|
||||||
|
@ -257,11 +268,16 @@ impl Signature {
|
||||||
/// only useful for validating signatures in the Bitcoin blockchain from before
|
/// only useful for validating signatures in the Bitcoin blockchain from before
|
||||||
/// 2016. It should never be used in new applications. This library does not
|
/// 2016. It should never be used in new applications. This library does not
|
||||||
/// support serializing to this "format"
|
/// support serializing to this "format"
|
||||||
pub fn from_der_lax<C>(secp: &Secp256k1<C>, data: &[u8]) -> Result<Signature, Error> {
|
pub fn from_der_lax(data: &[u8]) -> Result<Signature, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut ret = ffi::Signature::blank();
|
let mut ret = ffi::Signature::blank();
|
||||||
if ffi::ecdsa_signature_parse_der_lax(secp.ctx, &mut ret,
|
if ffi::ecdsa_signature_parse_der_lax(
|
||||||
data.as_ptr(), data.len() as libc::size_t) == 1 {
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
&mut ret,
|
||||||
|
data.as_ptr(),
|
||||||
|
data.len() as libc::size_t,
|
||||||
|
) == 1
|
||||||
|
{
|
||||||
Ok(Signature(ret))
|
Ok(Signature(ret))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::InvalidSignature)
|
Err(Error::InvalidSignature)
|
||||||
|
@ -286,12 +302,15 @@ impl Signature {
|
||||||
/// valid. (For example, parsing the historic Bitcoin blockchain requires
|
/// valid. (For example, parsing the historic Bitcoin blockchain requires
|
||||||
/// this.) For these applications we provide this normalization function,
|
/// this.) For these applications we provide this normalization function,
|
||||||
/// which ensures that the s value lies in the lower half of its range.
|
/// which ensures that the s value lies in the lower half of its range.
|
||||||
pub fn normalize_s<C>(&mut self, secp: &Secp256k1<C>) {
|
pub fn normalize_s(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Ignore return value, which indicates whether the sig
|
// Ignore return value, which indicates whether the sig
|
||||||
// was already normalized. We don't care.
|
// was already normalized. We don't care.
|
||||||
ffi::secp256k1_ecdsa_signature_normalize(secp.ctx, self.as_mut_ptr(),
|
ffi::secp256k1_ecdsa_signature_normalize(
|
||||||
self.as_ptr());
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
self.as_mut_ptr(),
|
||||||
|
self.as_ptr(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,12 +328,16 @@ impl Signature {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Serializes the signature in DER format
|
/// Serializes the signature in DER format
|
||||||
pub fn serialize_der<C>(&self, secp: &Secp256k1<C>) -> Vec<u8> {
|
pub fn serialize_der(&self) -> Vec<u8> {
|
||||||
let mut ret = Vec::with_capacity(72);
|
let mut ret = Vec::with_capacity(72);
|
||||||
let mut len: size_t = ret.capacity() as size_t;
|
let mut len: size_t = ret.capacity() as size_t;
|
||||||
unsafe {
|
unsafe {
|
||||||
let err = ffi::secp256k1_ecdsa_signature_serialize_der(secp.ctx, ret.as_mut_ptr(),
|
let err = ffi::secp256k1_ecdsa_signature_serialize_der(
|
||||||
&mut len, self.as_ptr());
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
ret.as_mut_ptr(),
|
||||||
|
&mut len,
|
||||||
|
self.as_ptr(),
|
||||||
|
);
|
||||||
debug_assert!(err == 1);
|
debug_assert!(err == 1);
|
||||||
ret.set_len(len as usize);
|
ret.set_len(len as usize);
|
||||||
}
|
}
|
||||||
|
@ -323,11 +346,14 @@ impl Signature {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Serializes the signature in compact format
|
/// Serializes the signature in compact format
|
||||||
pub fn serialize_compact<C>(&self, secp: &Secp256k1<C>) -> [u8; 64] {
|
pub fn serialize_compact(&self) -> [u8; 64] {
|
||||||
let mut ret = [0; 64];
|
let mut ret = [0; 64];
|
||||||
unsafe {
|
unsafe {
|
||||||
let err = ffi::secp256k1_ecdsa_signature_serialize_compact(secp.ctx, ret.as_mut_ptr(),
|
let err = ffi::secp256k1_ecdsa_signature_serialize_compact(
|
||||||
self.as_ptr());
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
ret.as_mut_ptr(),
|
||||||
|
self.as_ptr(),
|
||||||
|
);
|
||||||
debug_assert!(err == 1);
|
debug_assert!(err == 1);
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
|
@ -348,14 +374,19 @@ impl RecoverableSignature {
|
||||||
/// Converts a compact-encoded byte slice to a signature. This
|
/// Converts a compact-encoded byte slice to a signature. This
|
||||||
/// representation is nonstandard and defined by the libsecp256k1
|
/// representation is nonstandard and defined by the libsecp256k1
|
||||||
/// library.
|
/// library.
|
||||||
pub fn from_compact<C>(secp: &Secp256k1<C>, data: &[u8], recid: RecoveryId) -> Result<RecoverableSignature, Error> {
|
pub fn from_compact(data: &[u8], recid: RecoveryId) -> Result<RecoverableSignature, Error> {
|
||||||
let mut ret = unsafe { ffi::RecoverableSignature::blank() };
|
let mut ret = unsafe { ffi::RecoverableSignature::blank() };
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if data.len() != 64 {
|
if data.len() != 64 {
|
||||||
Err(Error::InvalidSignature)
|
Err(Error::InvalidSignature)
|
||||||
} else if ffi::secp256k1_ecdsa_recoverable_signature_parse_compact(secp.ctx, &mut ret,
|
} else if ffi::secp256k1_ecdsa_recoverable_signature_parse_compact(
|
||||||
data.as_ptr(), recid.0) == 1 {
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
&mut ret,
|
||||||
|
data.as_ptr(),
|
||||||
|
recid.0,
|
||||||
|
) == 1
|
||||||
|
{
|
||||||
Ok(RecoverableSignature(ret))
|
Ok(RecoverableSignature(ret))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::InvalidSignature)
|
Err(Error::InvalidSignature)
|
||||||
|
@ -371,12 +402,16 @@ impl RecoverableSignature {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Serializes the recoverable signature in compact format
|
/// Serializes the recoverable signature in compact format
|
||||||
pub fn serialize_compact<C>(&self, secp: &Secp256k1<C>) -> (RecoveryId, [u8; 64]) {
|
pub fn serialize_compact(&self) -> (RecoveryId, [u8; 64]) {
|
||||||
let mut ret = [0u8; 64];
|
let mut ret = [0u8; 64];
|
||||||
let mut recid = 0i32;
|
let mut recid = 0i32;
|
||||||
unsafe {
|
unsafe {
|
||||||
let err = ffi::secp256k1_ecdsa_recoverable_signature_serialize_compact(
|
let err = ffi::secp256k1_ecdsa_recoverable_signature_serialize_compact(
|
||||||
secp.ctx, ret.as_mut_ptr(), &mut recid, self.as_ptr());
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
ret.as_mut_ptr(),
|
||||||
|
&mut recid,
|
||||||
|
self.as_ptr(),
|
||||||
|
);
|
||||||
assert!(err == 1);
|
assert!(err == 1);
|
||||||
}
|
}
|
||||||
(RecoveryId(recid), ret)
|
(RecoveryId(recid), ret)
|
||||||
|
@ -385,10 +420,14 @@ impl RecoverableSignature {
|
||||||
/// Converts a recoverable signature to a non-recoverable one (this is needed
|
/// Converts a recoverable signature to a non-recoverable one (this is needed
|
||||||
/// for verification
|
/// for verification
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_standard<C>(&self, secp: &Secp256k1<C>) -> Signature {
|
pub fn to_standard(&self) -> Signature {
|
||||||
let mut ret = unsafe { ffi::Signature::blank() };
|
let mut ret = unsafe { ffi::Signature::blank() };
|
||||||
unsafe {
|
unsafe {
|
||||||
let err = ffi::secp256k1_ecdsa_recoverable_signature_convert(secp.ctx, &mut ret, self.as_ptr());
|
let err = ffi::secp256k1_ecdsa_recoverable_signature_convert(
|
||||||
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
&mut ret,
|
||||||
|
self.as_ptr(),
|
||||||
|
);
|
||||||
assert!(err == 1);
|
assert!(err == 1);
|
||||||
}
|
}
|
||||||
Signature(ret)
|
Signature(ret)
|
||||||
|
@ -442,8 +481,7 @@ impl ops::Index<ops::RangeFull> for Signature {
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl ::serde::Serialize for Signature {
|
impl ::serde::Serialize for Signature {
|
||||||
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||||
let secp = Secp256k1::without_caps();
|
s.serialize_bytes(&self.serialize_der())
|
||||||
s.serialize_bytes(&self.serialize_der(&secp))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,9 +490,8 @@ impl<'de> ::serde::Deserialize<'de> for Signature {
|
||||||
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Signature, D::Error> {
|
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Signature, D::Error> {
|
||||||
use ::serde::de::Error;
|
use ::serde::de::Error;
|
||||||
|
|
||||||
let secp = Secp256k1::without_caps();
|
|
||||||
let sl: &[u8] = ::serde::Deserialize::deserialize(d)?;
|
let sl: &[u8] = ::serde::Deserialize::deserialize(d)?;
|
||||||
Signature::from_der(&secp, sl).map_err(D::Error::custom)
|
Signature::from_der(sl).map_err(D::Error::custom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,9 +568,6 @@ pub trait Signing {}
|
||||||
/// Marker trait for indicating that an instance of `Secp256k1` can be used for verification.
|
/// Marker trait for indicating that an instance of `Secp256k1` can be used for verification.
|
||||||
pub trait Verification {}
|
pub trait Verification {}
|
||||||
|
|
||||||
/// Represents the empty set of capabilities.
|
|
||||||
pub struct None {}
|
|
||||||
|
|
||||||
/// Represents the set of capabilities needed for signing.
|
/// Represents the set of capabilities needed for signing.
|
||||||
pub struct SignOnly {}
|
pub struct SignOnly {}
|
||||||
|
|
||||||
|
@ -581,12 +615,6 @@ impl<C> Drop for Secp256k1<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Secp256k1<None> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "<secp256k1 context {:?}, no capabilities>", self.ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Secp256k1<SignOnly> {
|
impl fmt::Debug for Secp256k1<SignOnly> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "<secp256k1 context {:?}, signing only>", self.ctx)
|
write!(f, "<secp256k1 context {:?}, signing only>", self.ctx)
|
||||||
|
@ -605,13 +633,6 @@ impl fmt::Debug for Secp256k1<All> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Secp256k1<None> {
|
|
||||||
/// Creates a new Secp256k1 context with no capabilities (just de/serialization)
|
|
||||||
pub fn without_caps() -> Secp256k1<None> {
|
|
||||||
Secp256k1 { ctx: unsafe { ffi::secp256k1_context_create(ffi::SECP256K1_START_NONE) }, phantom: PhantomData }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Secp256k1<All> {
|
impl Secp256k1<All> {
|
||||||
/// Creates a new Secp256k1 context with all capabilities
|
/// Creates a new Secp256k1 context with all capabilities
|
||||||
pub fn new() -> Secp256k1<All> {
|
pub fn new() -> Secp256k1<All> {
|
||||||
|
@ -686,9 +707,17 @@ impl<C: Signing> Secp256k1<C> {
|
||||||
unsafe {
|
unsafe {
|
||||||
// We can assume the return value because it's not possible to construct
|
// We can assume the return value because it's not possible to construct
|
||||||
// an invalid signature from a valid `Message` and `SecretKey`
|
// an invalid signature from a valid `Message` and `SecretKey`
|
||||||
assert_eq!(ffi::secp256k1_ecdsa_sign_recoverable(self.ctx, &mut ret, msg.as_ptr(),
|
assert_eq!(
|
||||||
sk.as_ptr(), ffi::secp256k1_nonce_function_rfc6979,
|
ffi::secp256k1_ecdsa_sign_recoverable(
|
||||||
ptr::null()), 1);
|
self.ctx,
|
||||||
|
&mut ret,
|
||||||
|
msg.as_ptr(),
|
||||||
|
sk.as_ptr(),
|
||||||
|
ffi::secp256k1_nonce_function_rfc6979,
|
||||||
|
ptr::null()
|
||||||
|
),
|
||||||
|
1
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
RecoverableSignature::from(ret)
|
RecoverableSignature::from(ret)
|
||||||
|
@ -702,7 +731,7 @@ impl<C: Signing> Secp256k1<C> {
|
||||||
#[cfg(any(test, feature = "rand"))]
|
#[cfg(any(test, feature = "rand"))]
|
||||||
pub fn generate_keypair<R: Rng>(&self, rng: &mut R)
|
pub fn generate_keypair<R: Rng>(&self, rng: &mut R)
|
||||||
-> (key::SecretKey, key::PublicKey) {
|
-> (key::SecretKey, key::PublicKey) {
|
||||||
let sk = key::SecretKey::new(self, rng);
|
let sk = key::SecretKey::new(rng);
|
||||||
let pk = key::PublicKey::from_secret_key(self, &sk);
|
let pk = key::PublicKey::from_secret_key(self, &sk);
|
||||||
(sk, pk)
|
(sk, pk)
|
||||||
}
|
}
|
||||||
|
@ -792,7 +821,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn capabilities() {
|
fn capabilities() {
|
||||||
let none = Secp256k1::without_caps();
|
|
||||||
let sign = Secp256k1::signing_only();
|
let sign = Secp256k1::signing_only();
|
||||||
let vrfy = Secp256k1::verification_only();
|
let vrfy = Secp256k1::verification_only();
|
||||||
let full = Secp256k1::new();
|
let full = Secp256k1::new();
|
||||||
|
@ -824,8 +852,8 @@ mod tests {
|
||||||
|
|
||||||
// Check that we can produce keys from slices with no precomputation
|
// Check that we can produce keys from slices with no precomputation
|
||||||
let (pk_slice, sk_slice) = (&pk.serialize(), &sk[..]);
|
let (pk_slice, sk_slice) = (&pk.serialize(), &sk[..]);
|
||||||
let new_pk = PublicKey::from_slice(&none, pk_slice).unwrap();
|
let new_pk = PublicKey::from_slice(pk_slice).unwrap();
|
||||||
let new_sk = SecretKey::from_slice(&none, sk_slice).unwrap();
|
let new_sk = SecretKey::from_slice(sk_slice).unwrap();
|
||||||
assert_eq!(sk, new_sk);
|
assert_eq!(sk, new_sk);
|
||||||
assert_eq!(pk, new_pk);
|
assert_eq!(pk, new_pk);
|
||||||
}
|
}
|
||||||
|
@ -843,11 +871,11 @@ mod tests {
|
||||||
let one = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
let one = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
|
||||||
|
|
||||||
let sk = SecretKey::from_slice(&s, &one).unwrap();
|
let sk = SecretKey::from_slice(&one).unwrap();
|
||||||
let msg = Message::from_slice(&one).unwrap();
|
let msg = Message::from_slice(&one).unwrap();
|
||||||
|
|
||||||
let sig = s.sign_recoverable(&msg, &sk);
|
let sig = s.sign_recoverable(&msg, &sk);
|
||||||
assert_eq!(Ok(sig), RecoverableSignature::from_compact(&s, &[
|
assert_eq!(Ok(sig), RecoverableSignature::from_compact(&[
|
||||||
0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f,
|
0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f,
|
||||||
0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6,
|
0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6,
|
||||||
0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65,
|
0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65,
|
||||||
|
@ -871,29 +899,28 @@ mod tests {
|
||||||
|
|
||||||
let (sk, _) = s.generate_keypair(&mut thread_rng());
|
let (sk, _) = s.generate_keypair(&mut thread_rng());
|
||||||
let sig1 = s.sign(&msg, &sk);
|
let sig1 = s.sign(&msg, &sk);
|
||||||
let der = sig1.serialize_der(&s);
|
let der = sig1.serialize_der();
|
||||||
let sig2 = Signature::from_der(&s, &der[..]).unwrap();
|
let sig2 = Signature::from_der(&der[..]).unwrap();
|
||||||
assert_eq!(sig1, sig2);
|
assert_eq!(sig1, sig2);
|
||||||
|
|
||||||
let compact = sig1.serialize_compact(&s);
|
let compact = sig1.serialize_compact();
|
||||||
let sig2 = Signature::from_compact(&s, &compact[..]).unwrap();
|
let sig2 = Signature::from_compact(&compact[..]).unwrap();
|
||||||
assert_eq!(sig1, sig2);
|
assert_eq!(sig1, sig2);
|
||||||
|
|
||||||
assert!(Signature::from_compact(&s, &der[..]).is_err());
|
assert!(Signature::from_compact(&der[..]).is_err());
|
||||||
assert!(Signature::from_compact(&s, &compact[0..4]).is_err());
|
assert!(Signature::from_compact(&compact[0..4]).is_err());
|
||||||
assert!(Signature::from_der(&s, &compact[..]).is_err());
|
assert!(Signature::from_der(&compact[..]).is_err());
|
||||||
assert!(Signature::from_der(&s, &der[0..4]).is_err());
|
assert!(Signature::from_der(&der[0..4]).is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn signature_display() {
|
fn signature_display() {
|
||||||
let secp = Secp256k1::without_caps();
|
|
||||||
let hex_str = "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45";
|
let hex_str = "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45";
|
||||||
let byte_str = hex!(hex_str);
|
let byte_str = hex!(hex_str);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Signature::from_der(&secp, &byte_str).expect("byte str decode"),
|
Signature::from_der(&byte_str).expect("byte str decode"),
|
||||||
Signature::from_str(&hex_str).expect("byte str decode")
|
Signature::from_str(&hex_str).expect("byte str decode")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -927,9 +954,8 @@ mod tests {
|
||||||
fn signature_lax_der() {
|
fn signature_lax_der() {
|
||||||
macro_rules! check_lax_sig(
|
macro_rules! check_lax_sig(
|
||||||
($hex:expr) => ({
|
($hex:expr) => ({
|
||||||
let secp = Secp256k1::without_caps();
|
|
||||||
let sig = hex!($hex);
|
let sig = hex!($hex);
|
||||||
assert!(Signature::from_der_lax(&secp, &sig[..]).is_ok());
|
assert!(Signature::from_der_lax(&sig[..]).is_ok());
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -979,7 +1005,7 @@ mod tests {
|
||||||
wild_keys[1][0] -= 1;
|
wild_keys[1][0] -= 1;
|
||||||
wild_msgs[1][0] -= 1;
|
wild_msgs[1][0] -= 1;
|
||||||
|
|
||||||
for key in wild_keys.iter().map(|k| SecretKey::from_slice(&s, &k[..]).unwrap()) {
|
for key in wild_keys.iter().map(|k| SecretKey::from_slice(&k[..]).unwrap()) {
|
||||||
for msg in wild_msgs.iter().map(|m| Message::from_slice(&m[..]).unwrap()) {
|
for msg in wild_msgs.iter().map(|m| Message::from_slice(&m[..]).unwrap()) {
|
||||||
let sig = s.sign(&msg, &key);
|
let sig = s.sign(&msg, &key);
|
||||||
let pk = PublicKey::from_secret_key(&s, &key);
|
let pk = PublicKey::from_secret_key(&s, &key);
|
||||||
|
@ -1000,7 +1026,7 @@ mod tests {
|
||||||
let (sk, pk) = s.generate_keypair(&mut thread_rng());
|
let (sk, pk) = s.generate_keypair(&mut thread_rng());
|
||||||
|
|
||||||
let sigr = s.sign_recoverable(&msg, &sk);
|
let sigr = s.sign_recoverable(&msg, &sk);
|
||||||
let sig = sigr.to_standard(&s);
|
let sig = sigr.to_standard();
|
||||||
|
|
||||||
let mut msg = [0u8; 32];
|
let mut msg = [0u8; 32];
|
||||||
thread_rng().fill_bytes(&mut msg);
|
thread_rng().fill_bytes(&mut msg);
|
||||||
|
@ -1035,19 +1061,18 @@ mod tests {
|
||||||
let msg = Message::from_slice(&[0x55; 32]).unwrap();
|
let msg = Message::from_slice(&[0x55; 32]).unwrap();
|
||||||
|
|
||||||
// Zero is not a valid sig
|
// Zero is not a valid sig
|
||||||
let sig = RecoverableSignature::from_compact(&s, &[0; 64], RecoveryId(0)).unwrap();
|
let sig = RecoverableSignature::from_compact(&[0; 64], RecoveryId(0)).unwrap();
|
||||||
assert_eq!(s.recover(&msg, &sig), Err(InvalidSignature));
|
assert_eq!(s.recover(&msg, &sig), Err(InvalidSignature));
|
||||||
// ...but 111..111 is
|
// ...but 111..111 is
|
||||||
let sig = RecoverableSignature::from_compact(&s, &[1; 64], RecoveryId(0)).unwrap();
|
let sig = RecoverableSignature::from_compact(&[1; 64], RecoveryId(0)).unwrap();
|
||||||
assert!(s.recover(&msg, &sig).is_ok());
|
assert!(s.recover(&msg, &sig).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bad_slice() {
|
fn test_bad_slice() {
|
||||||
let s = Secp256k1::new();
|
assert_eq!(Signature::from_der(&[0; constants::MAX_SIGNATURE_SIZE + 1]),
|
||||||
assert_eq!(Signature::from_der(&s, &[0; constants::MAX_SIGNATURE_SIZE + 1]),
|
|
||||||
Err(InvalidSignature));
|
Err(InvalidSignature));
|
||||||
assert_eq!(Signature::from_der(&s, &[0; constants::MAX_SIGNATURE_SIZE]),
|
assert_eq!(Signature::from_der(&[0; constants::MAX_SIGNATURE_SIZE]),
|
||||||
Err(InvalidSignature));
|
Err(InvalidSignature));
|
||||||
|
|
||||||
assert_eq!(Message::from_slice(&[0; constants::MESSAGE_SIZE - 1]),
|
assert_eq!(Message::from_slice(&[0; constants::MESSAGE_SIZE - 1]),
|
||||||
|
@ -1059,8 +1084,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_debug_output() {
|
fn test_debug_output() {
|
||||||
let s = Secp256k1::new();
|
let sig = RecoverableSignature::from_compact(&[
|
||||||
let sig = RecoverableSignature::from_compact(&s, &[
|
|
||||||
0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f,
|
0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f,
|
||||||
0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6,
|
0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6,
|
||||||
0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65,
|
0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65,
|
||||||
|
@ -1081,8 +1105,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_recov_sig_serialize_compact() {
|
fn test_recov_sig_serialize_compact() {
|
||||||
let s = Secp256k1::new();
|
|
||||||
|
|
||||||
let recid_in = RecoveryId(1);
|
let recid_in = RecoveryId(1);
|
||||||
let bytes_in = &[
|
let bytes_in = &[
|
||||||
0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f,
|
0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f,
|
||||||
|
@ -1094,8 +1116,10 @@ mod tests {
|
||||||
0xff, 0x20, 0x80, 0xc4, 0xa3, 0x9a, 0xae, 0x06,
|
0xff, 0x20, 0x80, 0xc4, 0xa3, 0x9a, 0xae, 0x06,
|
||||||
0x8d, 0x12, 0xee, 0xd0, 0x09, 0xb6, 0x8c, 0x89];
|
0x8d, 0x12, 0xee, 0xd0, 0x09, 0xb6, 0x8c, 0x89];
|
||||||
let sig = RecoverableSignature::from_compact(
|
let sig = RecoverableSignature::from_compact(
|
||||||
&s, bytes_in, recid_in).unwrap();
|
bytes_in,
|
||||||
let (recid_out, bytes_out) = sig.serialize_compact(&s);
|
recid_in,
|
||||||
|
).unwrap();
|
||||||
|
let (recid_out, bytes_out) = sig.serialize_compact();
|
||||||
assert_eq!(recid_in, recid_out);
|
assert_eq!(recid_in, recid_out);
|
||||||
assert_eq!(&bytes_in[..], &bytes_out[..]);
|
assert_eq!(&bytes_in[..], &bytes_out[..]);
|
||||||
}
|
}
|
||||||
|
@ -1124,14 +1148,14 @@ mod tests {
|
||||||
let msg = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d");
|
let msg = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d");
|
||||||
|
|
||||||
let secp = Secp256k1::new();
|
let secp = Secp256k1::new();
|
||||||
let mut sig = Signature::from_der(&secp, &sig[..]).unwrap();
|
let mut sig = Signature::from_der(&sig[..]).unwrap();
|
||||||
let pk = PublicKey::from_slice(&secp, &pk[..]).unwrap();
|
let pk = PublicKey::from_slice(&pk[..]).unwrap();
|
||||||
let msg = Message::from_slice(&msg[..]).unwrap();
|
let msg = Message::from_slice(&msg[..]).unwrap();
|
||||||
|
|
||||||
// without normalization we expect this will fail
|
// without normalization we expect this will fail
|
||||||
assert_eq!(secp.verify(&msg, &sig, &pk), Err(IncorrectSignature));
|
assert_eq!(secp.verify(&msg, &sig, &pk), Err(IncorrectSignature));
|
||||||
// after normalization it should pass
|
// after normalization it should pass
|
||||||
sig.normalize_s(&secp);
|
sig.normalize_s();
|
||||||
assert_eq!(secp.verify(&msg, &sig, &pk), Ok(()));
|
assert_eq!(secp.verify(&msg, &sig, &pk), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1143,7 +1167,7 @@ mod tests {
|
||||||
let s = Secp256k1::new();
|
let s = Secp256k1::new();
|
||||||
|
|
||||||
let msg = Message::from_slice(&[1; 32]).unwrap();
|
let msg = Message::from_slice(&[1; 32]).unwrap();
|
||||||
let sk = SecretKey::from_slice(&s, &[2; 32]).unwrap();
|
let sk = SecretKey::from_slice(&[2; 32]).unwrap();
|
||||||
let sig = s.sign(&msg, &sk);
|
let sig = s.sign(&msg, &sk);
|
||||||
static SIG_BYTES: [u8; 71] = [
|
static SIG_BYTES: [u8; 71] = [
|
||||||
48, 69, 2, 33, 0, 157, 11, 173, 87, 103, 25, 211, 42, 231, 107, 237,
|
48, 69, 2, 33, 0, 157, 11, 173, 87, 103, 25, 211, 42, 231, 107, 237,
|
||||||
|
|
Loading…
Reference in New Issue