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:
Andrew Poelstra 2018-11-10 12:51:14 +00:00 committed by GitHub
commit 4b88cfc2fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 415 additions and 256 deletions

View File

@ -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.

View File

@ -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

View File

@ -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);
} }
} }

View File

@ -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
); );
} }

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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));

View File

@ -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);
}); });
} }

View File

@ -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; }

View File

@ -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[..])]);

View File

@ -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,