diff --git a/depend/secp256k1/include/secp256k1.h b/depend/secp256k1/include/secp256k1.h index 3c4a311..f1f78ab 100644 --- a/depend/secp256k1/include/secp256k1.h +++ b/depend/secp256k1/include/secp256k1.h @@ -179,6 +179,13 @@ typedef int (*secp256k1_nonce_function)( #define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06 #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. * * Returns: a newly created context object. diff --git a/depend/secp256k1/include/secp256k1_ecdh.h b/depend/secp256k1/include/secp256k1_ecdh.h index 88492dc..df5fde2 100644 --- a/depend/secp256k1/include/secp256k1_ecdh.h +++ b/depend/secp256k1/include/secp256k1_ecdh.h @@ -7,21 +7,45 @@ extern "C" { #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 * Returns: 1: exponentiation was successful * 0: scalar was invalid (zero or overflow) * Args: ctx: pointer to a context object (cannot be NULL) - * Out: result: a 32-byte array which will be populated by an ECDH - * secret computed from the point and scalar + * Out: output: pointer to an array to be filled by the function * In: pubkey: a pointer to a secp256k1_pubkey containing an * initialized public key * 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( const secp256k1_context* ctx, - unsigned char *result, + unsigned char *output, 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); #ifdef __cplusplus diff --git a/depend/secp256k1/src/bench_ecdh.c b/depend/secp256k1/src/bench_ecdh.c index 5837f4e..c1dd5a6 100644 --- a/depend/secp256k1/src/bench_ecdh.c +++ b/depend/secp256k1/src/bench_ecdh.c @@ -42,7 +42,7 @@ static void bench_ecdh(void* arg) { bench_ecdh_data *data = (bench_ecdh_data*)arg; 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); } } diff --git a/depend/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/depend/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c index bcef7b3..b50970b 100644 --- a/depend/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c +++ b/depend/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c @@ -83,7 +83,7 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e 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]; size_t outputLen = 72; @@ -353,7 +353,9 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e ctx, nonce_res, &pubkey, - secdata + secdata, + NULL, + NULL ); } diff --git a/depend/secp256k1/src/modules/ecdh/main_impl.h b/depend/secp256k1/src/modules/ecdh/main_impl.h index df3ec5c..44cb68e 100644 --- a/depend/secp256k1/src/modules/ecdh/main_impl.h +++ b/depend/secp256k1/src/modules/ecdh/main_impl.h @@ -10,16 +10,35 @@ #include "include/secp256k1_ecdh.h" #include "ecmult_const_impl.h" -int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) { +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 overflow = 0; secp256k1_gej res; secp256k1_ge pt; secp256k1_scalar s; VERIFY_CHECK(ctx != NULL); - ARG_CHECK(result != NULL); + ARG_CHECK(output != NULL); ARG_CHECK(point != NULL); ARG_CHECK(scalar != NULL); + if (hashfp == NULL) { + hashfp = secp256k1_ecdh_hash_function_default; + } secp256k1_pubkey_load(ctx, &pt, point); 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; } else { unsigned char x[32]; - unsigned char y[1]; - secp256k1_sha256 sha; + unsigned char y[32]; secp256k1_ecmult_const(&res, &pt, &s, 256); secp256k1_ge_set_gej(&pt, &res); - /* Compute a hash of the point in compressed form - * Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not - * expect its output to be secret and has a timing sidechannel. */ + + /* Compute a hash of the point */ secp256k1_fe_normalize(&pt.x); secp256k1_fe_normalize(&pt.y); secp256k1_fe_get_b32(x, &pt.x); - y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y); + secp256k1_fe_get_b32(y, &pt.y); - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, y, sizeof(y)); - secp256k1_sha256_write(&sha, x, sizeof(x)); - secp256k1_sha256_finalize(&sha, result); - ret = 1; + ret = hashfp(output, x, y, data); } secp256k1_scalar_clear(&s); diff --git a/depend/secp256k1/src/modules/ecdh/tests_impl.h b/depend/secp256k1/src/modules/ecdh/tests_impl.h index 0c53f8e..fe26e8f 100644 --- a/depend/secp256k1/src/modules/ecdh/tests_impl.h +++ b/depend/secp256k1/src/modules/ecdh/tests_impl.h @@ -7,6 +7,23 @@ #ifndef 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) { /* Setup context that just counts errors */ 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 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(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0); + CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0); 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(secp256k1_ecdh(tctx, res, &point, NULL) == 0); + CHECK(secp256k1_ecdh(tctx, res, &point, NULL, NULL, NULL) == 0); 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); /* Cleanup */ @@ -46,27 +63,34 @@ void test_ecdh_generator_basepoint(void) { for (i = 0; i < 100; ++i) { secp256k1_sha256 sha; unsigned char s_b32[32]; - unsigned char output_ecdh[32]; + unsigned char output_ecdh[65]; unsigned char output_ser[32]; - unsigned char point_ser[33]; + unsigned char point_ser[65]; size_t point_ser_len = sizeof(point_ser); secp256k1_scalar s; random_scalar_order(&s); secp256k1_scalar_get_b32(s_b32, &s); - /* compute using ECDH function */ CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1); - CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1); - /* compute "explicitly" */ CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1); + + /* 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(point_ser_len == sizeof(point_ser)); secp256k1_sha256_initialize(&sha); secp256k1_sha256_write(&sha, point_ser, point_ser_len); secp256k1_sha256_finalize(&sha, output_ser); /* compare */ - CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0); + 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); /* Try to multiply it by bad values */ - CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0); - CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0); + CHECK(secp256k1_ecdh(ctx, output, &point, s_zero, NULL, NULL) == 0); + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 0); /* ...and a good one */ 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) { diff --git a/depend/secp256k1/src/secp256k1.c b/depend/secp256k1/src/secp256k1.c index cd0972d..a1e3908 100644 --- a/depend/secp256k1/src/secp256k1.c +++ b/depend/secp256k1/src/secp256k1.c @@ -56,6 +56,14 @@ struct secp256k1_context_struct { 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* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context)); 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) { + CHECK(ctx != secp256k1_context_no_precomp); if (ctx != NULL) { secp256k1_ecmult_context_clear(&ctx->ecmult_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) { + CHECK(ctx != secp256k1_context_no_precomp); if (fun == NULL) { 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) { + CHECK(ctx != secp256k1_context_no_precomp); if (fun == NULL) { 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) { VERIFY_CHECK(ctx != NULL); + CHECK(ctx != secp256k1_context_no_precomp); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); return 1; diff --git a/depend/secp256k1/src/tests.c b/depend/secp256k1/src/tests.c index 15f4491..c72a742 100644 --- a/depend/secp256k1/src/tests.c +++ b/depend/secp256k1/src/tests.c @@ -3599,6 +3599,7 @@ void run_ec_pubkey_parse_test(void) { ecount = 0; VG_UNDEF(&pubkey, sizeof(pubkey)); 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)); CHECK(ecount == 0); VG_UNDEF(&ge, sizeof(ge)); diff --git a/src/ecdh.rs b/src/ecdh.rs index 6cb6729..aec2dbc 100644 --- a/src/ecdh.rs +++ b/src/ecdh.rs @@ -16,9 +16,8 @@ //! Support for shared secret computations //! -use std::ops; +use std::{ops, ptr}; -use super::Secp256k1; use key::{SecretKey, PublicKey}; use ffi; @@ -29,10 +28,17 @@ pub struct SharedSecret(ffi::SharedSecret); impl SharedSecret { /// Creates a new shared secret from a pubkey and secret key #[inline] - pub fn new(secp: &Secp256k1, point: &PublicKey, scalar: &SecretKey) -> SharedSecret { + pub fn new(point: &PublicKey, scalar: &SecretKey) -> SharedSecret { unsafe { 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); SharedSecret(ss) } @@ -102,9 +108,9 @@ mod tests { let (sk1, pk1) = s.generate_keypair(&mut thread_rng()); let (sk2, pk2) = s.generate_keypair(&mut thread_rng()); - let sec1 = SharedSecret::new(&s, &pk1, &sk2); - let sec2 = SharedSecret::new(&s, &pk2, &sk1); - let sec_odd = SharedSecret::new(&s, &pk1, &sk1); + let sec1 = SharedSecret::new(&pk1, &sk2); + let sec2 = SharedSecret::new(&pk2, &sk1); + let sec_odd = SharedSecret::new(&pk1, &sk1); assert_eq!(sec1, sec2); assert!(sec_odd != sec2); } @@ -125,7 +131,7 @@ mod benches { let s = Secp256k1::new(); bh.iter( || { - let res = SharedSecret::new(&s, &pk, &sk); + let res = SharedSecret::new(&pk, &sk); black_box(res); }); } diff --git a/src/ffi.rs b/src/ffi.rs index bcf6dd3..dfb2c39 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -46,6 +46,14 @@ pub type NonceFn = unsafe extern "C" fn(nonce32: *mut c_uchar, attempt: c_uint, 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 /// needed to do elliptic curve computations. If you create one of these @@ -114,10 +122,15 @@ impl SharedSecret { #[cfg(not(feature = "fuzztarget"))] 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_default: NonceFn; + pub static secp256k1_context_no_precomp: *const Context; + // Contexts pub fn secp256k1_context_create(flags: c_uint) -> *mut Context; @@ -248,11 +261,14 @@ extern "C" { n: c_int) -> c_int; - pub fn secp256k1_ecdh(cx: *const Context, - out: *mut SharedSecret, - point: *const PublicKey, - scalar: *const c_uchar) - -> c_int; + pub fn secp256k1_ecdh( + cx: *const Context, + output: *mut SharedSecret, + pubkey: *const PublicKey, + privkey: *const c_uchar, + hashfp: EcdhHashFn, + data: *mut c_void, + ) -> c_int; } #[cfg(feature = "fuzztarget")] @@ -262,7 +278,9 @@ mod fuzz_dummy { use std::ptr; extern "C" { + pub static secp256k1_ecdh_hash_function_default: EcdhHashFn; pub static secp256k1_nonce_function_rfc6979: NonceFn; + pub static secp256k1_context_no_precomp: *const Context; } // Contexts @@ -618,11 +636,14 @@ mod fuzz_dummy { } /// Sets out to point[0..16]||scalar[0..16] - pub unsafe fn secp256k1_ecdh(cx: *const Context, - out: *mut SharedSecret, - point: *const PublicKey, - scalar: *const c_uchar) - -> c_int { + pub unsafe fn secp256k1_ecdh( + cx: *const Context, + out: *mut SharedSecret, + point: *const PublicKey, + scalar: *const c_uchar, + 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).0 as u32 & SECP256K1_START_SIGN == SECP256K1_START_SIGN); if secp256k1_ec_seckey_verify(cx, scalar) != 1 { return 0; } diff --git a/src/key.rs b/src/key.rs index 36af2c3..c5d7b33 100644 --- a/src/key.rs +++ b/src/key.rs @@ -87,17 +87,15 @@ impl fmt::Display for PublicKey { impl str::FromStr for PublicKey { type Err = Error; fn from_str(s: &str) -> Result { - let secp = Secp256k1::without_caps(); let mut res = [0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]; match from_hex(s, &mut res) { Ok(constants::PUBLIC_KEY_SIZE) => { PublicKey::from_slice( - &secp, &res[0..constants::PUBLIC_KEY_SIZE] ) } Ok(constants::UNCOMPRESSED_PUBLIC_KEY_SIZE) => { - PublicKey::from_slice(&secp, &res) + PublicKey::from_slice(&res) } _ => Err(Error::InvalidPublicKey) } @@ -115,10 +113,14 @@ impl SecretKey { /// Creates a new random secret key. Requires compilation with the "rand" feature. #[inline] #[cfg(any(test, feature = "rand"))] - pub fn new(secp: &Secp256k1, rng: &mut R) -> SecretKey { + pub fn new(rng: &mut R) -> SecretKey { let mut data = random_32_bytes(rng); 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); } } @@ -127,13 +129,16 @@ impl SecretKey { /// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key #[inline] - pub fn from_slice(secp: &Secp256k1, data: &[u8]) - -> Result { + pub fn from_slice(data: &[u8])-> Result { match data.len() { constants::SECRET_KEY_SIZE => { let mut ret = [0; constants::SECRET_KEY_SIZE]; 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); } } @@ -146,10 +151,14 @@ impl SecretKey { #[inline] /// Adds one secret key to another, modulo the curve order - pub fn add_assign(&mut self, secp: &Secp256k1, other: &SecretKey) - -> Result<(), Error> { + pub fn add_assign(&mut self, other: &SecretKey) -> Result<(), Error> { 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) } else { Ok(()) @@ -159,10 +168,14 @@ impl SecretKey { #[inline] /// Multiplies one secret key by another, modulo the curve order - pub fn mul_assign(&mut self, secp: &Secp256k1, other: &SecretKey) - -> Result<(), Error> { + pub fn mul_assign(&mut self, other: &SecretKey) -> Result<(), Error> { 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) } else { Ok(()) @@ -220,13 +233,16 @@ impl PublicKey { /// Creates a public key directly from a slice #[inline] - pub fn from_slice(secp: &Secp256k1, data: &[u8]) - -> Result { - + pub fn from_slice(data: &[u8]) -> Result { let mut pk = unsafe { ffi::PublicKey::blank() }; unsafe { - if ffi::secp256k1_ec_pubkey_parse(secp.ctx, &mut pk, data.as_ptr(), - data.len() as ::libc::size_t) == 1 { + if ffi::secp256k1_ec_pubkey_parse( + ffi::secp256k1_context_no_precomp, + &mut pk, + data.as_ptr(), + data.len() as ::libc::size_t, + ) == 1 + { Ok(PublicKey(pk)) } else { Err(InvalidPublicKey) @@ -239,13 +255,12 @@ impl PublicKey { /// the y-coordinate is represented by only a single bit, as x determines /// it up to one bit. pub fn serialize(&self) -> [u8; constants::PUBLIC_KEY_SIZE] { - let secp = Secp256k1::without_caps(); let mut ret = [0; constants::PUBLIC_KEY_SIZE]; unsafe { let mut ret_len = constants::PUBLIC_KEY_SIZE as ::libc::size_t; let err = ffi::secp256k1_ec_pubkey_serialize( - secp.ctx, + ffi::secp256k1_context_no_precomp, ret.as_mut_ptr(), &mut ret_len, self.as_ptr(), @@ -259,13 +274,12 @@ impl PublicKey { /// Serialize the key as a byte-encoded pair of values, in uncompressed form 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]; unsafe { let mut ret_len = constants::UNCOMPRESSED_PUBLIC_KEY_SIZE as ::libc::size_t; let err = ffi::secp256k1_ec_pubkey_serialize( - secp.ctx, + ffi::secp256k1_context_no_precomp, ret.as_mut_ptr(), &mut ret_len, self.as_ptr(), @@ -308,11 +322,17 @@ impl PublicKey { /// 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 /// to its own negation - pub fn combine(&self, secp: &Secp256k1, other: &PublicKey) -> Result { + pub fn combine(&self, other: &PublicKey) -> Result { unsafe { let mut ret = mem::uninitialized(); 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)) } else { Err(InvalidPublicKey) @@ -341,9 +361,8 @@ impl<'de> ::serde::Deserialize<'de> for PublicKey { fn deserialize>(d: D) -> Result { use ::serde::de::Error; - let secp = Secp256k1::without_caps(); 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] fn skey_from_slice() { - let s = Secp256k1::new(); - let sk = SecretKey::from_slice(&s, &[1; 31]); + let sk = SecretKey::from_slice(&[1; 31]); assert_eq!(sk, Err(InvalidSecretKey)); - let sk = SecretKey::from_slice(&s, &[1; 32]); + let sk = SecretKey::from_slice(&[1; 32]); assert!(sk.is_ok()); } #[test] fn pubkey_from_slice() { - let s = Secp256k1::new(); - assert_eq!(PublicKey::from_slice(&s, &[]), Err(InvalidPublicKey)); - assert_eq!(PublicKey::from_slice(&s, &[1, 2, 3]), Err(InvalidPublicKey)); + assert_eq!(PublicKey::from_slice(&[]), Err(InvalidPublicKey)); + assert_eq!(PublicKey::from_slice(&[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()); - 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()); } @@ -395,30 +412,31 @@ mod test { let s = Secp256k1::new(); let (sk1, pk1) = s.generate_keypair(&mut thread_rng()); - assert_eq!(SecretKey::from_slice(&s, &sk1[..]), Ok(sk1)); - assert_eq!(PublicKey::from_slice(&s, &pk1.serialize()[..]), Ok(pk1)); - assert_eq!(PublicKey::from_slice(&s, &pk1.serialize_uncompressed()[..]), Ok(pk1)); + assert_eq!(SecretKey::from_slice(&sk1[..]), Ok(sk1)); + assert_eq!(PublicKey::from_slice(&pk1.serialize()[..]), Ok(pk1)); + assert_eq!(PublicKey::from_slice(&pk1.serialize_uncompressed()[..]), Ok(pk1)); } #[test] fn invalid_secret_key() { - let s = Secp256k1::new(); // Zero - assert_eq!(SecretKey::from_slice(&s, &[0; 32]), Err(InvalidSecretKey)); + assert_eq!(SecretKey::from_slice(&[0; 32]), Err(InvalidSecretKey)); // -1 - assert_eq!(SecretKey::from_slice(&s, &[0xff; 32]), Err(InvalidSecretKey)); + assert_eq!(SecretKey::from_slice(&[0xff; 32]), Err(InvalidSecretKey)); // Top of range - assert!(SecretKey::from_slice(&s, - &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, - 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40]).is_ok()); + assert!(SecretKey::from_slice(&[ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, + 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40, + ]).is_ok()); // One past top of range - assert!(SecretKey::from_slice(&s, - &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, - 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41]).is_err()); + assert!(SecretKey::from_slice(&[ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, + 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41, + ]).is_err()); } #[test] @@ -449,22 +467,33 @@ mod test { #[test] fn test_pubkey_from_bad_slice() { - let s = Secp256k1::new(); // Bad sizes - assert_eq!(PublicKey::from_slice(&s, &[0; constants::PUBLIC_KEY_SIZE - 1]), - Err(InvalidPublicKey)); - assert_eq!(PublicKey::from_slice(&s, &[0; constants::PUBLIC_KEY_SIZE + 1]), - Err(InvalidPublicKey)); - assert_eq!(PublicKey::from_slice(&s, &[0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE - 1]), - Err(InvalidPublicKey)); - assert_eq!(PublicKey::from_slice(&s, &[0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE + 1]), - Err(InvalidPublicKey)); + assert_eq!( + PublicKey::from_slice(&[0; constants::PUBLIC_KEY_SIZE - 1]), + Err(InvalidPublicKey) + ); + assert_eq!( + PublicKey::from_slice(&[0; constants::PUBLIC_KEY_SIZE + 1]), + 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 - assert_eq!(PublicKey::from_slice(&s, &[0xff; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]), - Err(InvalidPublicKey)); - assert_eq!(PublicKey::from_slice(&s, &[0x55; constants::PUBLIC_KEY_SIZE]), - Err(InvalidPublicKey)); + assert_eq!( + PublicKey::from_slice(&[0xff; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]), + Err(InvalidPublicKey) + ); + assert_eq!( + PublicKey::from_slice(&[0x55; constants::PUBLIC_KEY_SIZE]), + Err(InvalidPublicKey) + ); } #[test] @@ -494,7 +523,7 @@ mod test { ]; 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); assert_eq!( @@ -563,12 +592,12 @@ mod test { let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng()); 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_eq!(PublicKey::from_secret_key(&s, &sk1), pk1); 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_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()); 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_eq!(PublicKey::from_secret_key(&s, &sk1), pk1); 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_eq!(PublicKey::from_secret_key(&s, &sk2), pk2); } @@ -617,23 +646,19 @@ mod test { #[test] fn pubkey_combine() { - let s = Secp256k1::without_caps(); let compressed1 = PublicKey::from_slice( - &s, &hex!("0241cc121c419921942add6db6482fb36243faf83317c866d2a28d8c6d7089f7ba"), ).unwrap(); let compressed2 = PublicKey::from_slice( - &s, &hex!("02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"), ).unwrap(); let exp_sum = PublicKey::from_slice( - &s, &hex!("0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07"), ).unwrap(); - let sum1 = compressed1.combine(&s, &compressed2); + let sum1 = compressed1.combine(&compressed2); assert!(sum1.is_ok()); - let sum2 = compressed2.combine(&s, &compressed1); + let sum2 = compressed2.combine(&compressed1); assert!(sum2.is_ok()); assert_eq!(sum1, sum2); assert_eq!(sum1.unwrap(), exp_sum); @@ -641,14 +666,11 @@ mod test { #[test] fn pubkey_equal() { - let s = Secp256k1::new(); let pk1 = PublicKey::from_slice( - &s, &hex!("0241cc121c419921942add6db6482fb36243faf83317c866d2a28d8c6d7089f7ba"), ).unwrap(); let pk2 = pk1.clone(); let pk3 = PublicKey::from_slice( - &s, &hex!("02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"), ).unwrap(); @@ -684,7 +706,7 @@ mod test { 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); assert_tokens(&sk, &[Token::BorrowedBytes(&SK_BYTES[..])]); diff --git a/src/lib.rs b/src/lib.rs index 5de10e7..81cbc57 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,7 +66,7 @@ //! use self::secp256k1::{Secp256k1, Message, SecretKey, PublicKey}; //! //! 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 message = Message::from_slice(&[0xab; 32]).expect("32 bytes"); //! @@ -83,7 +83,7 @@ //! //! let secp = Secp256k1::verification_only(); //! -//! let public_key = PublicKey::from_slice(&secp, &[ +//! let public_key = PublicKey::from_slice(&[ //! 0x02, //! 0xc6, 0x6e, 0x7d, 0x89, 0x66, 0xb5, 0xc5, 0x55, //! 0xaf, 0x58, 0x05, 0x98, 0x9d, 0xa9, 0xfb, 0xf8, @@ -98,7 +98,7 @@ //! 0xd5, 0x44, 0x53, 0xcf, 0x6e, 0x82, 0xb4, 0x50, //! ]).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, //! 0x3f, 0x25, 0x34, 0x49, 0xcf, 0x8c, 0x39, 0x7a, //! 0xb6, 0xf1, 0x6f, 0xb3, 0xd6, 0x3d, 0x86, 0x94, @@ -165,70 +165,77 @@ pub struct RecoveryId(i32); pub struct Signature(ffi::Signature); impl fmt::Debug for Signature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, f) - } +fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) +} } impl fmt::Display for Signature { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut v = [0; 72]; - let mut len = v.len() as size_t; - let secp = Secp256k1::without_caps(); - unsafe { - let err = ffi::secp256k1_ecdsa_signature_serialize_der(secp.ctx, v.as_mut_ptr(), - &mut len, self.as_ptr()); - debug_assert!(err == 1); - } - for ch in &v[..] { - write!(f, "{:02x}", *ch)?; - } - Ok(()) +fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut v = [0; 72]; + let mut len = v.len() as size_t; + unsafe { + let err = ffi::secp256k1_ecdsa_signature_serialize_der( + ffi::secp256k1_context_no_precomp, + v.as_mut_ptr(), + &mut len, + self.as_ptr() + ); + debug_assert!(err == 1); } + for ch in &v[..] { + write!(f, "{:02x}", *ch)?; + } + Ok(()) +} } impl str::FromStr for Signature { - type Err = Error; - fn from_str(s: &str) -> Result { - let secp = Secp256k1::without_caps(); - let mut res = [0; 72]; - match from_hex(s, &mut res) { - Ok(x) => Signature::from_der(&secp, &res[0..x]), - _ => Err(Error::InvalidSignature), - } +type Err = Error; +fn from_str(s: &str) -> Result { + let mut res = [0; 72]; + match from_hex(s, &mut res) { + Ok(x) => Signature::from_der(&res[0..x]), + _ => Err(Error::InvalidSignature), } } +} /// An ECDSA signature with a recovery ID for pubkey recovery #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct RecoverableSignature(ffi::RecoverableSignature); impl RecoveryId { - #[inline] - /// Allows library users to create valid recovery IDs from i32. - pub fn from_i32(id: i32) -> Result { - match id { - 0 | 1 | 2 | 3 => Ok(RecoveryId(id)), - _ => Err(Error::InvalidRecoveryId) - } - } - - #[inline] - /// Allows library users to convert recovery IDs to i32. - pub fn to_i32(&self) -> i32 { - self.0 +#[inline] +/// Allows library users to create valid recovery IDs from i32. +pub fn from_i32(id: i32) -> Result { + match id { + 0 | 1 | 2 | 3 => Ok(RecoveryId(id)), + _ => Err(Error::InvalidRecoveryId) } } +#[inline] +/// Allows library users to convert recovery IDs to i32. +pub fn to_i32(&self) -> i32 { + self.0 +} +} + impl Signature { - #[inline] +#[inline] /// Converts a DER-encoded byte slice to a signature - pub fn from_der(secp: &Secp256k1, data: &[u8]) -> Result { + pub fn from_der(data: &[u8]) -> Result { let mut ret = unsafe { ffi::Signature::blank() }; unsafe { - if ffi::secp256k1_ecdsa_signature_parse_der(secp.ctx, &mut ret, - data.as_ptr(), data.len() as libc::size_t) == 1 { + if ffi::secp256k1_ecdsa_signature_parse_der( + ffi::secp256k1_context_no_precomp, + &mut ret, + data.as_ptr(), + data.len() as libc::size_t, + ) == 1 + { Ok(Signature(ret)) } else { Err(Error::InvalidSignature) @@ -237,15 +244,19 @@ impl Signature { } /// Converts a 64-byte compact-encoded byte slice to a signature - pub fn from_compact(secp: &Secp256k1, data: &[u8]) -> Result { + pub fn from_compact(data: &[u8]) -> Result { let mut ret = unsafe { ffi::Signature::blank() }; if data.len() != 64 { return Err(Error::InvalidSignature) } unsafe { - if ffi::secp256k1_ecdsa_signature_parse_compact(secp.ctx, &mut ret, - data.as_ptr()) == 1 { + if ffi::secp256k1_ecdsa_signature_parse_compact( + ffi::secp256k1_context_no_precomp, + &mut ret, + data.as_ptr(), + ) == 1 + { Ok(Signature(ret)) } else { Err(Error::InvalidSignature) @@ -257,11 +268,16 @@ impl Signature { /// only useful for validating signatures in the Bitcoin blockchain from before /// 2016. It should never be used in new applications. This library does not /// support serializing to this "format" - pub fn from_der_lax(secp: &Secp256k1, data: &[u8]) -> Result { + pub fn from_der_lax(data: &[u8]) -> Result { unsafe { let mut ret = ffi::Signature::blank(); - if ffi::ecdsa_signature_parse_der_lax(secp.ctx, &mut ret, - data.as_ptr(), data.len() as libc::size_t) == 1 { + if ffi::ecdsa_signature_parse_der_lax( + ffi::secp256k1_context_no_precomp, + &mut ret, + data.as_ptr(), + data.len() as libc::size_t, + ) == 1 + { Ok(Signature(ret)) } else { Err(Error::InvalidSignature) @@ -286,12 +302,15 @@ impl Signature { /// valid. (For example, parsing the historic Bitcoin blockchain requires /// this.) For these applications we provide this normalization function, /// which ensures that the s value lies in the lower half of its range. - pub fn normalize_s(&mut self, secp: &Secp256k1) { + pub fn normalize_s(&mut self) { unsafe { // Ignore return value, which indicates whether the sig // was already normalized. We don't care. - ffi::secp256k1_ecdsa_signature_normalize(secp.ctx, self.as_mut_ptr(), - self.as_ptr()); + ffi::secp256k1_ecdsa_signature_normalize( + ffi::secp256k1_context_no_precomp, + self.as_mut_ptr(), + self.as_ptr(), + ); } } @@ -309,12 +328,16 @@ impl Signature { #[inline] /// Serializes the signature in DER format - pub fn serialize_der(&self, secp: &Secp256k1) -> Vec { + pub fn serialize_der(&self) -> Vec { let mut ret = Vec::with_capacity(72); let mut len: size_t = ret.capacity() as size_t; unsafe { - let err = ffi::secp256k1_ecdsa_signature_serialize_der(secp.ctx, ret.as_mut_ptr(), - &mut len, self.as_ptr()); + let err = ffi::secp256k1_ecdsa_signature_serialize_der( + ffi::secp256k1_context_no_precomp, + ret.as_mut_ptr(), + &mut len, + self.as_ptr(), + ); debug_assert!(err == 1); ret.set_len(len as usize); } @@ -323,11 +346,14 @@ impl Signature { #[inline] /// Serializes the signature in compact format - pub fn serialize_compact(&self, secp: &Secp256k1) -> [u8; 64] { + pub fn serialize_compact(&self) -> [u8; 64] { let mut ret = [0; 64]; unsafe { - let err = ffi::secp256k1_ecdsa_signature_serialize_compact(secp.ctx, ret.as_mut_ptr(), - self.as_ptr()); + let err = ffi::secp256k1_ecdsa_signature_serialize_compact( + ffi::secp256k1_context_no_precomp, + ret.as_mut_ptr(), + self.as_ptr(), + ); debug_assert!(err == 1); } ret @@ -348,14 +374,19 @@ impl RecoverableSignature { /// Converts a compact-encoded byte slice to a signature. This /// representation is nonstandard and defined by the libsecp256k1 /// library. - pub fn from_compact(secp: &Secp256k1, data: &[u8], recid: RecoveryId) -> Result { + pub fn from_compact(data: &[u8], recid: RecoveryId) -> Result { let mut ret = unsafe { ffi::RecoverableSignature::blank() }; unsafe { if data.len() != 64 { Err(Error::InvalidSignature) - } else if ffi::secp256k1_ecdsa_recoverable_signature_parse_compact(secp.ctx, &mut ret, - data.as_ptr(), recid.0) == 1 { + } else if ffi::secp256k1_ecdsa_recoverable_signature_parse_compact( + ffi::secp256k1_context_no_precomp, + &mut ret, + data.as_ptr(), + recid.0, + ) == 1 + { Ok(RecoverableSignature(ret)) } else { Err(Error::InvalidSignature) @@ -371,12 +402,16 @@ impl RecoverableSignature { #[inline] /// Serializes the recoverable signature in compact format - pub fn serialize_compact(&self, secp: &Secp256k1) -> (RecoveryId, [u8; 64]) { + pub fn serialize_compact(&self) -> (RecoveryId, [u8; 64]) { let mut ret = [0u8; 64]; let mut recid = 0i32; unsafe { 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); } (RecoveryId(recid), ret) @@ -385,10 +420,14 @@ impl RecoverableSignature { /// Converts a recoverable signature to a non-recoverable one (this is needed /// for verification #[inline] - pub fn to_standard(&self, secp: &Secp256k1) -> Signature { + pub fn to_standard(&self) -> Signature { let mut ret = unsafe { ffi::Signature::blank() }; 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); } Signature(ret) @@ -442,8 +481,7 @@ impl ops::Index for Signature { #[cfg(feature = "serde")] impl ::serde::Serialize for Signature { fn serialize(&self, s: S) -> Result { - let secp = Secp256k1::without_caps(); - s.serialize_bytes(&self.serialize_der(&secp)) + s.serialize_bytes(&self.serialize_der()) } } @@ -452,9 +490,8 @@ impl<'de> ::serde::Deserialize<'de> for Signature { fn deserialize>(d: D) -> Result { use ::serde::de::Error; - let secp = Secp256k1::without_caps(); 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. pub trait Verification {} -/// Represents the empty set of capabilities. -pub struct None {} - /// Represents the set of capabilities needed for signing. pub struct SignOnly {} @@ -581,12 +615,6 @@ impl Drop for Secp256k1 { } } -impl fmt::Debug for Secp256k1 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "", self.ctx) - } -} - impl fmt::Debug for Secp256k1 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "", self.ctx) @@ -605,13 +633,6 @@ impl fmt::Debug for Secp256k1 { } } -impl Secp256k1 { - /// Creates a new Secp256k1 context with no capabilities (just de/serialization) - pub fn without_caps() -> Secp256k1 { - Secp256k1 { ctx: unsafe { ffi::secp256k1_context_create(ffi::SECP256K1_START_NONE) }, phantom: PhantomData } - } -} - impl Secp256k1 { /// Creates a new Secp256k1 context with all capabilities pub fn new() -> Secp256k1 { @@ -686,9 +707,17 @@ impl Secp256k1 { unsafe { // We can assume the return value because it's not possible to construct // an invalid signature from a valid `Message` and `SecretKey` - assert_eq!(ffi::secp256k1_ecdsa_sign_recoverable(self.ctx, &mut ret, msg.as_ptr(), - sk.as_ptr(), ffi::secp256k1_nonce_function_rfc6979, - ptr::null()), 1); + assert_eq!( + ffi::secp256k1_ecdsa_sign_recoverable( + self.ctx, + &mut ret, + msg.as_ptr(), + sk.as_ptr(), + ffi::secp256k1_nonce_function_rfc6979, + ptr::null() + ), + 1 + ); } RecoverableSignature::from(ret) @@ -702,7 +731,7 @@ impl Secp256k1 { #[cfg(any(test, feature = "rand"))] pub fn generate_keypair(&self, rng: &mut R) -> (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); (sk, pk) } @@ -792,7 +821,6 @@ mod tests { #[test] fn capabilities() { - let none = Secp256k1::without_caps(); let sign = Secp256k1::signing_only(); let vrfy = Secp256k1::verification_only(); let full = Secp256k1::new(); @@ -824,8 +852,8 @@ mod tests { // Check that we can produce keys from slices with no precomputation let (pk_slice, sk_slice) = (&pk.serialize(), &sk[..]); - let new_pk = PublicKey::from_slice(&none, pk_slice).unwrap(); - let new_sk = SecretKey::from_slice(&none, sk_slice).unwrap(); + let new_pk = PublicKey::from_slice(pk_slice).unwrap(); + let new_sk = SecretKey::from_slice(sk_slice).unwrap(); assert_eq!(sk, new_sk); 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, 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 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, 0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6, 0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65, @@ -871,29 +899,28 @@ mod tests { let (sk, _) = s.generate_keypair(&mut thread_rng()); let sig1 = s.sign(&msg, &sk); - let der = sig1.serialize_der(&s); - let sig2 = Signature::from_der(&s, &der[..]).unwrap(); + let der = sig1.serialize_der(); + let sig2 = Signature::from_der(&der[..]).unwrap(); assert_eq!(sig1, sig2); - let compact = sig1.serialize_compact(&s); - let sig2 = Signature::from_compact(&s, &compact[..]).unwrap(); + let compact = sig1.serialize_compact(); + let sig2 = Signature::from_compact(&compact[..]).unwrap(); assert_eq!(sig1, sig2); - assert!(Signature::from_compact(&s, &der[..]).is_err()); - assert!(Signature::from_compact(&s, &compact[0..4]).is_err()); - assert!(Signature::from_der(&s, &compact[..]).is_err()); - assert!(Signature::from_der(&s, &der[0..4]).is_err()); + assert!(Signature::from_compact(&der[..]).is_err()); + assert!(Signature::from_compact(&compact[0..4]).is_err()); + assert!(Signature::from_der(&compact[..]).is_err()); + assert!(Signature::from_der(&der[0..4]).is_err()); } } #[test] fn signature_display() { - let secp = Secp256k1::without_caps(); let hex_str = "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45"; let byte_str = hex!(hex_str); 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") ); @@ -927,9 +954,8 @@ mod tests { fn signature_lax_der() { macro_rules! check_lax_sig( ($hex:expr) => ({ - let secp = Secp256k1::without_caps(); 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_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()) { let sig = s.sign(&msg, &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 sigr = s.sign_recoverable(&msg, &sk); - let sig = sigr.to_standard(&s); + let sig = sigr.to_standard(); let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); @@ -1035,19 +1061,18 @@ mod tests { let msg = Message::from_slice(&[0x55; 32]).unwrap(); // 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)); // ...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()); } #[test] fn test_bad_slice() { - let s = Secp256k1::new(); - assert_eq!(Signature::from_der(&s, &[0; constants::MAX_SIGNATURE_SIZE + 1]), + assert_eq!(Signature::from_der(&[0; constants::MAX_SIGNATURE_SIZE + 1]), 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)); assert_eq!(Message::from_slice(&[0; constants::MESSAGE_SIZE - 1]), @@ -1059,8 +1084,7 @@ mod tests { #[test] fn test_debug_output() { - let s = Secp256k1::new(); - let sig = RecoverableSignature::from_compact(&s, &[ + let sig = RecoverableSignature::from_compact(&[ 0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f, 0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6, 0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65, @@ -1081,8 +1105,6 @@ mod tests { #[test] fn test_recov_sig_serialize_compact() { - let s = Secp256k1::new(); - let recid_in = RecoveryId(1); let bytes_in = &[ 0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f, @@ -1094,8 +1116,10 @@ mod tests { 0xff, 0x20, 0x80, 0xc4, 0xa3, 0x9a, 0xae, 0x06, 0x8d, 0x12, 0xee, 0xd0, 0x09, 0xb6, 0x8c, 0x89]; let sig = RecoverableSignature::from_compact( - &s, bytes_in, recid_in).unwrap(); - let (recid_out, bytes_out) = sig.serialize_compact(&s); + bytes_in, + recid_in, + ).unwrap(); + let (recid_out, bytes_out) = sig.serialize_compact(); assert_eq!(recid_in, recid_out); assert_eq!(&bytes_in[..], &bytes_out[..]); } @@ -1124,14 +1148,14 @@ mod tests { let msg = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d"); let secp = Secp256k1::new(); - let mut sig = Signature::from_der(&secp, &sig[..]).unwrap(); - let pk = PublicKey::from_slice(&secp, &pk[..]).unwrap(); + let mut sig = Signature::from_der(&sig[..]).unwrap(); + let pk = PublicKey::from_slice(&pk[..]).unwrap(); let msg = Message::from_slice(&msg[..]).unwrap(); // without normalization we expect this will fail assert_eq!(secp.verify(&msg, &sig, &pk), Err(IncorrectSignature)); // after normalization it should pass - sig.normalize_s(&secp); + sig.normalize_s(); assert_eq!(secp.verify(&msg, &sig, &pk), Ok(())); } @@ -1143,7 +1167,7 @@ mod tests { let s = Secp256k1::new(); 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); static SIG_BYTES: [u8; 71] = [ 48, 69, 2, 33, 0, 157, 11, 173, 87, 103, 25, 211, 42, 231, 107, 237,